-
Notifications
You must be signed in to change notification settings - Fork 33
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
[Website] - Added Internationalization Support (English & French) (#2479) #2527
base: staging
Are you sure you want to change the base?
[Website] - Added Internationalization Support (English & French) (#2479) #2527
Conversation
syncing branch with staging
…oses/AirQo-frontend into ft/lang-support-issue#2479
📝 WalkthroughWalkthroughThis pull request restores a previously removed API key declaration in an Android properties file, adds a new error message for password validation in a UI component, and updates a Dockerfile to introduce a new entry point command. Most other files have been reformatted through whitespace, indentation, or reordering of properties for improved clarity without changing functionality. Changes
Sequence Diagram(s)sequenceDiagram
participant Container as Docker Container
participant Django as Django Process
participant Gunicorn as Gunicorn Server
Container->>Django: Run "python manage.py migrate"
Container->>Django: Run "python manage.py collectstatic --noinput"
Django-->>Container: Migrations & static collection complete
Container->>Gunicorn: Execute "gunicorn --bind=0.0.0.0:8080 backend.wsgi"
Gunicorn-->>Container: Application now running
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (16)
src/website/frontend/ErrorBoundary.jsx (1)
43-44
: Adopt Optional Chaining for Error Details RenderingThe current conditional rendering using logical AND can be streamlined. Replacing it with optional chaining improves readability and reduces risk of runtime errors when the properties are undefined.
- <p>{this.state.error && this.state.error.toString()}</p> - <pre>{this.state.errorInfo && this.state.errorInfo.componentStack}</pre> + <p>{this.state.error?.toString()}</p> + <pre>{this.state.errorInfo?.componentStack}</pre>🧰 Tools
🪛 Biome (1.9.4)
[error] 43-43: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 44-44: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
src/platform/src/core/hooks/useGetActiveGroupId.jsx (2)
1-92
: File naming inconsistency with exported function.The filename
useGetActiveGroupId.jsx
doesn't match the exported function nameuseGetActiveGroup
. This naming inconsistency could lead to confusion for developers trying to locate or import this hook.Consider renaming either:
- The file to
useGetActiveGroup.jsx
to match the exported function name, or- The function to
useGetActiveGroupId
to match the file nameThis will improve code maintainability and make imports more intuitive.
28-91
: Multiple return statements with similar structures could be refactored.The function contains multiple return statements with similar structures but slight variations, which works but might be harder to maintain long-term.
Consider refactoring to use a single return statement with conditionally determined values:
export function useGetActiveGroup() { const [activeGroup, setActiveGroup] = useState(null); const [loading, setLoading] = useState(true); const userInfo = useSelector((state) => state?.login?.userInfo); const chartData = useSelector((state) => state.chart); useEffect(() => { setLoading(true); const matchingGroup = findGroupByOrgName( userInfo?.groups, chartData?.organizationName, ); setActiveGroup(matchingGroup); setLoading(false); }, [chartData?.organizationName]); // Determine the group to use based on various conditions let id = null; let title = null; let selectedGroup = null; if (userInfo && userInfo.groups && chartData?.organizationName) { // Prioritize stored group if it exists in user's groups const storedGroupInUserGroups = findGroupByOrgName( userInfo.groups, chartData.organizationName, ); if (storedGroupInUserGroups) { selectedGroup = storedGroupInUserGroups; } else { // Find group matching chart organization name const matchingGroup = findGroupByOrgName( userInfo.groups, chartData.organizationName, ); if (matchingGroup) { selectedGroup = matchingGroup; } else if (userInfo.groups.length > 0) { // Fallback to first group if available selectedGroup = userInfo.groups[0]; } } } else { // Use activeGroup from state if no userInfo or groups selectedGroup = activeGroup; } // Construct the return object return { loading, id: selectedGroup?._id || null, title: selectedGroup?.grp_title || null, userID: userInfo?._id || null, groupList: userInfo?.groups || [], }; }This approach centralizes the logic and makes the function easier to understand and maintain.
src/mobile-v3/android/local.defaults.properties (1)
1-1
: Verify if this empty line addition is intentional.The addition of an empty line at the beginning of the file doesn't impact functionality but might affect file parsing in some environments. Consider whether this change is intentional or could be omitted.
Also applies to: 5-5
src/website2/public/locales/en.json (1)
1-24
: Well-structured English localization file.The English localization file is well-organized with a clear hierarchical structure for the "home" section. The content provides comprehensive text for various UI elements including titles, descriptions, and call-to-action buttons.
However, I'd recommend implementing some best practices for localization files:
{ "home": { "title": "Home | AirQo", "description": "Explore the air quality monitoring data and tools by AirQo.", "keywords": "air quality, pollution, monitoring, AirQo, environment", + "sections": { + "highResolution": { + "title": "High-resolution air quality monitoring network", + "monitor": "Air Quality Monitor", + "description": "We deploy a high-resolution air quality monitoring network in target urban areas across Africa to increase awareness and understanding of air quality management, provide actionable information, and derive actions against air pollution.", + "cta": "Learn more" + }, + "analytics": { + "title": "An interactive air quality analytics platform", + "monitor": "Air Quality Analytics", + "description": "Access and visualise real-time and historical air quality information across Africa through our easy-to-use air quality analytics dashboard.", + "cta": "Learn more" + } }, - "highResolutionTitle": "High-resolution air quality monitoring network", - "airQualityMonitor": "Air Quality Monitor", - "monitorDescription": "We deploy a high-resolution air quality monitoring network in target urban areas across Africa to increase awareness and understanding of air quality management, provide actionable information, and derive actions against air pollution.", - "learnMore": "Learn more", - "analyticsTitle": "An interactive air quality analytics platform", - "airQualityAnalytics": "Air Quality Analytics", - "analyticsDescription": "Access and visualise real-time and historical air quality information across Africa through our easy-to-use air quality analytics dashboard.", // ... (similar nesting pattern for other sections) } }This nested structure will make the file more maintainable as it grows and clearly groups related strings together.
src/website2/src/app/[locale]/clean-air-forum/glossary/page.tsx (2)
105-109
: Unnecessary Fragment can be simplified.The Fragment wrapping the glossarySections mapping is unnecessary when it has only one child element.
- {glossarySections && glossarySections.length > 0 && ( - <> - {glossarySections.map((section: any) => ( - <SectionDisplay key={section.id} section={section} /> - ))} - </> - )} + {glossarySections && glossarySections.length > 0 && + glossarySections.map((section: any) => ( + <SectionDisplay key={section.id} section={section} /> + )) + }🧰 Tools
🪛 Biome (1.9.4)
[error] 105-109: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
39-43
: Type safety improvement needed.The code uses
any
type for section objects, which reduces type safety. Since you're filtering based on specific properties, consider defining a proper interface.+ interface Section { + id: string | number; + pages: string[]; + content: any; // Consider a more specific type + } - const glossarySections = selectedEvent.sections?.filter((section: any) => { + const glossarySections = selectedEvent.sections?.filter((section: Section) => { if (!section.pages.includes('glossary')) return false; const html = renderContent(section.content); return html.trim().length > 0; });src/website2/src/app/[locale]/clean-air-forum/program-committee/page.tsx (1)
88-93
: Consider removing unnecessary Fragment.The Fragment wrapper is redundant here as it contains only a single child element and doesn't require keying.
- {committeeSections.length > 0 && ( - <> - {committeeSections.map((section: any) => ( - <SectionDisplay key={section.id} section={section} /> - ))} - </> - )} + {committeeSections.length > 0 && ( + committeeSections.map((section: any) => ( + <SectionDisplay key={section.id} section={section} /> + )) + )}🧰 Tools
🪛 Biome (1.9.4)
[error] 88-92: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
src/website2/src/app/[locale]/clean-air-forum/speakers/page.tsx (1)
137-142
: Consider removing unnecessary Fragment.This Fragment is redundant as it only contains a single map operation and doesn't require keying.
- {speakersExtraSections && speakersExtraSections.length > 0 && ( - <> - {speakersExtraSections.map((section: any) => ( - <SectionDisplay key={section.id} section={section} /> - ))} - </> - )} + {speakersExtraSections && speakersExtraSections.length > 0 && ( + speakersExtraSections.map((section: any) => ( + <SectionDisplay key={section.id} section={section} /> + )) + )}🧰 Tools
🪛 Biome (1.9.4)
[error] 137-141: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
src/website2/src/app/[locale]/clean-air-forum/sessions/page.tsx (1)
118-123
: Remove unnecessary Fragment wrappers.There are two unnecessary Fragment wrappers that could be simplified for cleaner code.
- {sessionSections && sessionSections.length > 0 && ( - <> - {sessionSections.map((section: any) => ( - <SectionDisplay key={section.id} section={section} /> - ))} - </> - )} + {sessionSections && sessionSections.length > 0 && ( + sessionSections.map((section: any) => ( + <SectionDisplay key={section.id} section={section} /> + )) + )} - <> - {selectedEvent.programs?.map((program: any) => ( - <AccordionItem - key={program.id} - title={program.title} - subText={program.sub_text} - sessions={program.sessions} - isOpen={openAccordion === program.id} - onToggle={() => handleToggle(program.id)} - /> - ))} - </> + {selectedEvent.programs?.map((program: any) => ( + <AccordionItem + key={program.id} + title={program.title} + subText={program.sub_text} + sessions={program.sessions} + isOpen={openAccordion === program.id} + onToggle={() => handleToggle(program.id)} + /> + ))}Also applies to: 125-136
🧰 Tools
🪛 Biome (1.9.4)
[error] 118-122: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
src/website2/src/app/[locale]/clean-air-forum/sponsorships/page.tsx (1)
51-57
: Unnecessary Fragment Wrapper:
The fragment wrapping the sponsorship sections mapping appears redundant since it isn’t adding extra structure. Simplifying it might improve readability.🧰 Tools
🪛 Biome (1.9.4)
[error] 52-56: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
src/website2/src/app/[locale]/clean-air-forum/logistics/page.tsx (1)
86-90
: Streamline Additional Logistics Sections:
The extra fragment wrapping the mapped logistics sections may be unnecessary. Removing it could simplify the JSX without affecting layout or functionality.🧰 Tools
🪛 Biome (1.9.4)
[error] 86-90: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
src/website2/src/app/[locale]/clean-air-forum/partners/page.tsx (2)
17-44
: Refactor Repeated Partner Filtering:
The filtering and mapping logic for convening, host, program, and funding partners is very similar. Abstracting this to a helper function could reduce repetition and streamline future maintenance.
68-72
: Simplify JSX for Partners Sections:
The fragment wrapping the partners sections mapping may not be necessary. Removing it can simplify the markup without impacting rendering.🧰 Tools
🪛 Biome (1.9.4)
[error] 68-72: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
src/website2/README.md (1)
27-35
: Markdown Formatting Reminders:
Some headings trigger markdown lint warnings (e.g., trailing punctuation and heading style). Addressing these will improve the overall consistency and aesthetics of the documentation.src/website/Dockerfile (1)
64-70
: New CMD Command – Ensure Database Readiness:
The addition of the CMD that runs migrations, collects static files, and then starts Gunicorn is a solid approach. However, confirm that the database is accessible when the container starts—consider a wait-for-db script or mechanism to handle startup dependencies if needed.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (14)
src/platform/yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
src/website/package-lock.json
is excluded by!**/package-lock.json
src/website2/package-lock.json
is excluded by!**/package-lock.json
src/website2/public/assets/images/partners/UN.svg
is excluded by!**/*.svg
src/website2/public/assets/images/partners/enabel.svg
is excluded by!**/*.svg
src/website2/public/assets/images/partners/google.svg
is excluded by!**/*.svg
src/website2/public/assets/images/partners/usmissionuganda.svg
is excluded by!**/*.svg
src/website2/public/assets/images/partners/worldbankgroup.svg
is excluded by!**/*.svg
src/website2/public/assets/svgs/ImpactNumbers/Community.svg
is excluded by!**/*.svg
src/website2/public/assets/svgs/ImpactNumbers/Monitor.svg
is excluded by!**/*.svg
src/website2/public/assets/svgs/ImpactNumbers/Network.svg
is excluded by!**/*.svg
src/website2/public/assets/svgs/ImpactNumbers/Partners.svg
is excluded by!**/*.svg
src/website2/public/assets/svgs/ImpactNumbers/Publications.svg
is excluded by!**/*.svg
src/website2/public/assets/svgs/ImpactNumbers/Records.svg
is excluded by!**/*.svg
📒 Files selected for processing (107)
src/mobile-v3/android/local.defaults.properties
(1 hunks)src/mobile-v3/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
(2 hunks)src/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
(1 hunks)src/netmanager-app/components/Settings/ApiTokens.tsx
(9 hunks)src/netmanager-app/components/Settings/PasswordEdit.tsx
(4 hunks)src/netmanager-app/components/layout.tsx
(1 hunks)src/netmanager-app/components/sidebar.tsx
(1 hunks)src/netmanager-app/components/topbar.tsx
(3 hunks)src/netmanager/.env.sample
(1 hunks)src/platform/next-env.d.ts
(1 hunks)src/platform/public/icons/Analytics/checkCircleIcon.js
(1 hunks)src/platform/src/common/components/AQNumberCard/components/index.jsx
(1 hunks)src/platform/src/common/components/Charts/components/SkeletonLoader.jsx
(1 hunks)src/platform/src/common/components/Charts/components/StandardsMenu.jsx
(1 hunks)src/platform/src/common/components/Charts/constants/index.jsx
(1 hunks)src/platform/src/common/components/Charts/utils/index.jsx
(1 hunks)src/platform/src/common/components/Modal/dataDownload/components/TableLoadingSkeleton.jsx
(1 hunks)src/platform/src/common/components/Modal/dataDownload/modules/SelectMore.jsx
(1 hunks)src/platform/src/common/components/Toast/CustomToast.jsx
(1 hunks)src/platform/src/core/hooks/useDataDownload.jsx
(1 hunks)src/platform/src/core/hooks/useFetchAnalyticsData.jsx
(1 hunks)src/platform/src/core/hooks/useGetActiveGroupId.jsx
(1 hunks)src/platform/src/core/hooks/useInactivityLogout.jsx
(1 hunks)src/platform/src/core/hooks/useSitesSummary.jsx
(1 hunks)src/platform/src/core/hooks/useUserChecklists.jsx
(1 hunks)src/platform/src/core/hooks/useUserPreferences.jsx
(1 hunks)src/platform/src/core/utils/dateUtils.js
(1 hunks)src/platform/src/core/utils/formatDateRangeToISO.js
(1 hunks)src/platform/src/core/utils/useResizeObserver.js
(1 hunks)src/platform/src/lib/store/services/sitesSummarySlice/index.js
(1 hunks)src/platform/src/pages/api/proxy/analytics.js
(1 hunks)src/platform/src/pages/api/proxy/data-download.js
(1 hunks)src/platform/src/pages/api/proxy/sites.js
(1 hunks)src/website/.env.sample
(1 hunks)src/website/Dockerfile
(1 hunks)src/website/frontend/App.js
(1 hunks)src/website/frontend/ErrorBoundary.jsx
(1 hunks)src/website/frontend/index.js
(1 hunks)src/website/frontend/locales/en/translation.json
(1 hunks)src/website/frontend/reduxStore/AirQlouds/index.js
(1 hunks)src/website/frontend/src/components/Footer.js
(1 hunks)src/website/frontend/src/components/LoctionTracker/LocationTracker.js
(1 hunks)src/website/frontend/src/pages/Legal/AirQo_Data.js
(1 hunks)src/website/frontend/src/pages/Legal/AirQo_Payments.js
(1 hunks)src/website/frontend/src/pages/Legal/PrivacyPolicy.js
(1 hunks)src/website/frontend/src/pages/Legal/TermsOfService.js
(1 hunks)src/website/frontend/src/pages/Legal/index.js
(1 hunks)src/website/frontend/styles/Footer.scss
(1 hunks)src/website/frontend/styles/Legal.scss
(1 hunks)src/website/frontend/styles/index.scss
(1 hunks)src/website/package.json
(1 hunks)src/website/webpack.dev.config.js
(1 hunks)src/website/webpack.fullapp.config.js
(1 hunks)src/website2/.prettierignore
(1 hunks)src/website2/.prettierrc
(1 hunks)src/website2/Dockerfile
(1 hunks)src/website2/README.md
(2 hunks)src/website2/jest.setup.ts
(1 hunks)src/website2/next.config.mjs
(2 hunks)src/website2/package.json
(1 hunks)src/website2/public/assets/icons/Icon1.tsx
(1 hunks)src/website2/public/assets/icons/Icon2.tsx
(1 hunks)src/website2/public/assets/icons/Icon3.tsx
(1 hunks)src/website2/public/assets/icons/Icon4.tsx
(1 hunks)src/website2/public/assets/icons/Icon5.tsx
(1 hunks)src/website2/public/assets/icons/Icon6.tsx
(1 hunks)src/website2/public/assets/icons/Icon7.tsx
(1 hunks)src/website2/public/assets/icons/Icon8.tsx
(1 hunks)src/website2/public/locales/en.json
(1 hunks)src/website2/public/locales/fr.json
(1 hunks)src/website2/src/app/[locale]/(about)/about-us/page.tsx
(1 hunks)src/website2/src/app/[locale]/(about)/careers/[id]/page.tsx
(1 hunks)src/website2/src/app/[locale]/(about)/careers/layout.tsx
(1 hunks)src/website2/src/app/[locale]/(about)/careers/page.tsx
(1 hunks)src/website2/src/app/[locale]/(about)/events/[id]/page.tsx
(1 hunks)src/website2/src/app/[locale]/(about)/events/layout.tsx
(1 hunks)src/website2/src/app/[locale]/(about)/events/page.tsx
(1 hunks)src/website2/src/app/[locale]/(about)/layout.tsx
(1 hunks)src/website2/src/app/[locale]/(about)/press/page.tsx
(1 hunks)src/website2/src/app/[locale]/(about)/resources/page.tsx
(1 hunks)src/website2/src/app/[locale]/MaintenancePage.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/about/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/glossary/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/layout.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/logistics/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/partners/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/program-committee/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/resources/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/sessions/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/speakers/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/sponsorships/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-network/CleanAirPage.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-network/events/[id]/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-network/events/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-network/layout.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-network/membership/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-network/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-network/resources/page.tsx
(1 hunks)src/website2/src/app/[locale]/contact/ContactPage.tsx
(1 hunks)src/website2/src/app/[locale]/contact/form/FormPage.tsx
(1 hunks)src/website2/src/app/[locale]/contact/form/page.tsx
(1 hunks)src/website2/src/app/[locale]/contact/layout.tsx
(1 hunks)src/website2/src/app/[locale]/contact/page.tsx
(1 hunks)src/website2/src/app/[locale]/contact/success/SuccessPage.tsx
(1 hunks)src/website2/src/app/[locale]/contact/success/page.tsx
(1 hunks)src/website2/src/app/[locale]/error.tsx
(1 hunks)src/website2/src/app/[locale]/explore-data/ExplorePage.tsx
(1 hunks)
⛔ Files not processed due to max files limit (13)
- src/website2/src/app/[locale]/explore-data/layout.tsx
- src/website2/src/app/[locale]/explore-data/mobile-app/page.tsx
- src/website2/src/app/[locale]/explore-data/page.tsx
- src/website2/src/app/[locale]/home/page.tsx
- src/website2/src/app/[locale]/layout.tsx
- src/website2/src/app/[locale]/legal/airqo-data/page.tsx
- src/website2/src/app/[locale]/legal/layout.tsx
- src/website2/src/app/[locale]/legal/payment-refund-policy/page.tsx
- src/website2/src/app/[locale]/legal/privacy-policy/page.tsx
- src/website2/src/app/[locale]/legal/terms-of-service/page.tsx
- src/website2/src/app/[locale]/not-found.tsx
- src/website2/src/app/[locale]/partners/[id]/page.tsx
- src/website2/src/app/[locale]/partners/layout.tsx
✅ Files skipped from review due to trivial changes (91)
- src/website2/src/app/[locale]/clean-air-network/events/[id]/page.tsx
- src/netmanager-app/components/layout.tsx
- src/netmanager-app/components/topbar.tsx
- src/website2/src/app/[locale]/(about)/about-us/page.tsx
- src/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
- src/website2/src/app/[locale]/(about)/press/page.tsx
- src/platform/next-env.d.ts
- src/website2/src/app/[locale]/clean-air-network/page.tsx
- src/website2/src/app/[locale]/clean-air-network/membership/page.tsx
- src/website/webpack.dev.config.js
- src/website/frontend/index.js
- src/website/webpack.fullapp.config.js
- src/website2/src/app/[locale]/contact/form/page.tsx
- src/website2/src/app/[locale]/(about)/layout.tsx
- src/platform/src/pages/api/proxy/data-download.js
- src/website2/src/app/[locale]/(about)/careers/page.tsx
- src/platform/src/core/hooks/useDataDownload.jsx
- src/website2/src/app/[locale]/contact/layout.tsx
- src/website2/.prettierignore
- src/platform/src/core/utils/useResizeObserver.js
- src/platform/src/core/utils/dateUtils.js
- src/netmanager-app/components/Settings/ApiTokens.tsx
- src/platform/src/common/components/Charts/components/SkeletonLoader.jsx
- src/website2/src/app/[locale]/clean-air-network/events/page.tsx
- src/website2/.prettierrc
- src/website2/src/app/[locale]/contact/success/page.tsx
- src/platform/src/common/components/Modal/dataDownload/components/TableLoadingSkeleton.jsx
- src/website2/src/app/[locale]/clean-air-network/resources/page.tsx
- src/website/.env.sample
- src/website/frontend/reduxStore/AirQlouds/index.js
- src/website2/src/app/[locale]/(about)/careers/layout.tsx
- src/platform/src/lib/store/services/sitesSummarySlice/index.js
- src/website/frontend/App.js
- src/platform/src/core/hooks/useSitesSummary.jsx
- src/platform/src/core/hooks/useFetchAnalyticsData.jsx
- src/website2/public/assets/icons/Icon5.tsx
- src/website/package.json
- src/website/frontend/src/pages/Legal/index.js
- src/mobile-v3/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
- src/website2/public/assets/icons/Icon3.tsx
- src/website2/public/assets/icons/Icon1.tsx
- src/website2/src/app/[locale]/(about)/events/page.tsx
- src/website2/src/app/[locale]/(about)/resources/page.tsx
- src/website2/Dockerfile
- src/website/frontend/src/components/LoctionTracker/LocationTracker.js
- src/platform/src/common/components/Charts/utils/index.jsx
- src/website2/src/app/[locale]/clean-air-network/layout.tsx
- src/website2/public/assets/icons/Icon6.tsx
- src/website2/src/app/[locale]/error.tsx
- src/platform/src/core/hooks/useInactivityLogout.jsx
- src/platform/src/core/hooks/useUserChecklists.jsx
- src/platform/src/common/components/AQNumberCard/components/index.jsx
- src/netmanager-app/components/sidebar.tsx
- src/website2/src/app/[locale]/(about)/events/layout.tsx
- src/website2/src/app/[locale]/clean-air-forum/layout.tsx
- src/website/frontend/styles/Footer.scss
- src/website2/src/app/[locale]/contact/page.tsx
- src/website2/src/app/[locale]/(about)/careers/[id]/page.tsx
- src/website2/src/app/[locale]/clean-air-forum/resources/page.tsx
- src/website/frontend/styles/Legal.scss
- src/platform/src/common/components/Charts/constants/index.jsx
- src/website2/src/app/[locale]/clean-air-forum/about/page.tsx
- src/website2/public/locales/fr.json
- src/website2/src/app/[locale]/clean-air-network/CleanAirPage.tsx
- src/website2/src/app/[locale]/explore-data/ExplorePage.tsx
- src/platform/src/pages/api/proxy/analytics.js
- src/website/frontend/src/pages/Legal/PrivacyPolicy.js
- src/platform/src/core/hooks/useUserPreferences.jsx
- src/netmanager/.env.sample
- src/website2/public/assets/icons/Icon4.tsx
- src/website2/public/assets/icons/Icon2.tsx
- src/website2/src/app/[locale]/contact/success/SuccessPage.tsx
- src/website/frontend/src/pages/Legal/TermsOfService.js
- src/website/frontend/styles/index.scss
- src/website/frontend/src/pages/Legal/AirQo_Payments.js
- src/website2/jest.setup.ts
- src/platform/src/common/components/Modal/dataDownload/modules/SelectMore.jsx
- src/website2/public/assets/icons/Icon8.tsx
- src/website2/src/app/[locale]/contact/ContactPage.tsx
- src/platform/src/common/components/Charts/components/StandardsMenu.jsx
- src/website2/public/assets/icons/Icon7.tsx
- src/website/frontend/src/pages/Legal/AirQo_Data.js
- src/website2/src/app/[locale]/(about)/events/[id]/page.tsx
- src/platform/src/pages/api/proxy/sites.js
- src/platform/src/core/utils/formatDateRangeToISO.js
- src/website2/src/app/[locale]/MaintenancePage.tsx
- src/website/frontend/locales/en/translation.json
- src/website/frontend/src/components/Footer.js
- src/platform/public/icons/Analytics/checkCircleIcon.js
- src/website2/src/app/[locale]/contact/form/FormPage.tsx
- src/platform/src/common/components/Toast/CustomToast.jsx
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
src/website2/README.md
4-4: Trailing punctuation in heading
Punctuation: '.'
(MD026, no-trailing-punctuation)
26-26: Trailing punctuation in heading
Punctuation: '.'
(MD026, no-trailing-punctuation)
39-39: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
39-39: Trailing punctuation in heading
Punctuation: '.'
(MD026, no-trailing-punctuation)
🪛 Biome (1.9.4)
src/website/frontend/ErrorBoundary.jsx
[error] 43-43: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 44-44: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
src/website2/src/app/[locale]/clean-air-forum/glossary/page.tsx
[error] 95-95: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 105-109: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
src/website2/src/app/[locale]/clean-air-forum/logistics/page.tsx
[error] 53-53: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 75-75: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 86-90: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
src/website2/src/app/[locale]/clean-air-forum/partners/page.tsx
[error] 60-60: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 68-72: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
src/website2/src/app/[locale]/clean-air-forum/program-committee/page.tsx
[error] 78-78: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 88-92: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
src/website2/src/app/[locale]/clean-air-forum/sessions/page.tsx
[error] 48-48: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 66-66: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 110-110: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 118-122: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
[error] 125-136: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
[error] 147-147: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
src/website2/src/app/[locale]/clean-air-forum/speakers/page.tsx
[error] 81-81: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 137-141: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
src/website2/src/app/[locale]/clean-air-forum/sponsorships/page.tsx
[error] 43-43: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 52-56: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
🔇 Additional comments (22)
src/platform/src/core/hooks/useGetActiveGroupId.jsx (1)
1-92
: Missing the i18n integration mentioned in PR objective.This file doesn't contain any internationalization (i18n) related code despite the PR objective mentioning i18n support implementation.
If this file should support internationalization, consider integrating with the
next-intl
library as mentioned in the PR objective. For example, any user-facing strings should be translated using the appropriate i18n functions.However, since this hook appears to only deal with internal data structures and doesn't output any user-facing strings, it might not need i18n integration.
src/website2/package.json (1)
36-36
: Addition of next-intl dependency for internationalization support.The inclusion of the
next-intl
package (v3.26.4) aligns perfectly with the PR objectives to add internationalization support for both English and French languages. This is the foundation for the multi-language capabilities being implemented.src/mobile-v3/android/local.defaults.properties (1)
5-5
: API key restoration appears unrelated to internationalization.The restoration of
PLACES_API_KEY_DEV=DEFAULT_API_KEY
doesn't seem to be related to the internationalization efforts mentioned in the PR objectives. This change might belong in a separate PR focused on API configurations.Please confirm if this change is intentional and necessary for this internationalization PR, or if it was accidentally included.
src/website2/src/app/[locale]/clean-air-forum/glossary/page.tsx (2)
1-115
: The file structure supports internationalization but lacks i18n implementation.The file path includes the
[locale]
parameter indicating it's part of the internationalization routing structure, but the component itself doesn't utilize any internationalization features like text translation.Consider adding translation support for user-facing strings in this component. For example:
import { useTranslations } from 'next-intl'; const GlossaryPage: React.FC = () => { const t = useTranslations('glossary'); // Then use t() for translations: // <h1>{t('cleanAirForumEvents')}</h1> // instead of hardcoded "Clean Air Forum Events"🧰 Tools
🪛 Biome (1.9.4)
[error] 95-95: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 105-109: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
95-97
: Security concern with dangerouslySetInnerHTML usage.While you're using DOMPurify to sanitize the HTML content, directly rendering HTML is always a potential security risk. Consider additional measures to ensure the glossary content is safe.
<div className="md:w-2/3" dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(glossaryHTML), }} ></div>Consider implementing additional safeguards:
- Restrict allowed HTML tags and attributes in DOMPurify configuration
- Add server-side validation of content before it reaches the client
🧰 Tools
🪛 Biome (1.9.4)
[error] 95-95: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
src/website2/next.config.mjs (1)
1-3
: Well-implemented next-intl configuration.The integration of
next-intl
with the Next.js configuration is clean and follows best practices. The plugin is properly imported, initialized, and applied to the existing configuration without disrupting other settings.This configuration is essential for the internationalization features to work correctly throughout the application, enabling the routing and message loading for different locales.
Also applies to: 57-57
src/netmanager-app/components/Settings/PasswordEdit.tsx (2)
58-59
: Good addition of detailed error message for password validation.The error message "Password must meet all requirements" provides clear feedback to users when their password doesn't match the required regex pattern. This improves the user experience by explaining why their input was rejected.
3-3
: Minor whitespace changes.These whitespace additions maintain consistent code style throughout the file.
Also applies to: 14-14, 144-144
src/website2/src/app/[locale]/clean-air-forum/program-committee/page.tsx (2)
1-121
: Formatting changes maintain functionality while improving readability.The file has been thoroughly reformatted with consistent spacing and indentation while preserving all functionality. The component logic, hooks usage, and rendering approach remain unchanged.
🧰 Tools
🪛 Biome (1.9.4)
[error] 78-78: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 88-92: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
78-80
: XSS protection is properly implemented.The use of
dangerouslySetInnerHTML
is appropriately paired withDOMPurify.sanitize()
, which mitigates the risk of cross-site scripting attacks when rendering potentially untrusted HTML content.🧰 Tools
🪛 Biome (1.9.4)
[error] 78-78: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
src/website2/src/app/[locale]/clean-air-forum/speakers/page.tsx (2)
1-148
: Consistent formatting applied throughout the file.The code has been reformatted with consistent spacing and indentation while maintaining all functionality. This improves readability without changing the component's behavior.
🧰 Tools
🪛 Biome (1.9.4)
[error] 81-81: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 137-141: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
81-83
: Proper HTML sanitization in place.The
dangerouslySetInnerHTML
usage is correctly paired withDOMPurify.sanitize()
, which helps protect against XSS vulnerabilities when rendering HTML content.🧰 Tools
🪛 Biome (1.9.4)
[error] 81-81: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
src/website2/src/app/[locale]/clean-air-forum/sessions/page.tsx (2)
1-159
: Comprehensive formatting with preserved functionality.The entire file has been reformatted with consistent spacing and indentation while maintaining all functional aspects. The component logic, state management, and rendering approach remain unchanged.
🧰 Tools
🪛 Biome (1.9.4)
[error] 48-48: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 66-66: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 110-110: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 118-122: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
[error] 125-136: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
[error] 147-147: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
47-49
: Consistent HTML sanitization across the component.All instances of
dangerouslySetInnerHTML
are appropriately using eitherrenderContent
orDOMPurify.sanitize()
, which helps protect against XSS vulnerabilities when rendering HTML content from potentially untrusted sources.Also applies to: 66-68, 110-112, 147-149
🧰 Tools
🪛 Biome (1.9.4)
[error] 48-48: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
src/website2/src/app/[locale]/clean-air-forum/sponsorships/page.tsx (2)
1-11
: General Structure & Localization Readiness:
The reformatting and placement under the[locale]
folder align well with internationalization support. As you continue to add dynamic language content, verify that all user-visible strings (including titles and headings) are marked for translation.
42-46
: Cautious Use of dangerouslySetInnerHTML:
The HTML output is sanitized using DOMPurify, which is good practice. Please double-check that the DOMPurify configuration covers all potential XSS vectors for content that originates from external sources.🧰 Tools
🪛 Biome (1.9.4)
[error] 43-43: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
src/website2/src/app/[locale]/clean-air-forum/logistics/page.tsx (3)
1-11
: Consistent Code Formatting & Clarity:
The file’s overall formatting is clear, and the comments help explain the logic for loading event logistics. Keeping the code modular will support future i18n enhancements.
52-60
: Vaccination Content Security Check:
The vaccination section’s use of dangerouslySetInnerHTML is safeguarded by DOMPurify. Just ensure that any future modifications to the source HTML maintain this sanitization step.🧰 Tools
🪛 Biome (1.9.4)
[error] 53-53: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
73-77
: Visa Section HTML Safety:
Similarly, the visa invitation HTML is sanitized appropriately. Please confirm that no unsanitized content reaches the DOM in later updates.🧰 Tools
🪛 Biome (1.9.4)
[error] 75-75: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
src/website2/src/app/[locale]/clean-air-forum/partners/page.tsx (2)
1-16
: Consistent Rendering with i18n Considerations:
The structure looks solid. As with other pages, as you localize more content, ensure that textual elements are set up for translation while preserving the layout.
60-64
: HTML Injection Safety in Partners Section:
The main partners HTML is sanitized with DOMPurify before being rendered via dangerouslySetInnerHTML. Continue to verify that any dynamic content remains secure against XSS risks.🧰 Tools
🪛 Biome (1.9.4)
[error] 60-60: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
src/website/Dockerfile (1)
1-34
: Dockerfile Staging & Environment Configuration:
The multi-stage build is well structured. The careful separation of the frontend and backend stages helps keep the image lean and efficient.
src/website2/README.md
Outdated
<<<<<<< HEAD | ||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). | ||
|
||
## Getting Started. | ||
|
||
First, run the development server: | ||
|
||
```bash | ||
npm run dev | ||
# or | ||
yarn dev | ||
# or | ||
pnpm dev | ||
# or | ||
bun dev | ||
``` | ||
|
||
test | ||
|
||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. | ||
|
||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. | ||
|
||
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. | ||
|
||
## Learn More. |
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.
Resolve Merge Conflict Markers:
There are unresolved merge conflict markers (<<<<<<<, =======, >>>>>>>) present in the README. Please resolve these conflicts to ensure the documentation is clear and professional.
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
4-4: Trailing punctuation in heading
Punctuation: '.'
(MD026, no-trailing-punctuation)
26-26: Trailing punctuation in heading
Punctuation: '.'
(MD026, no-trailing-punctuation)
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 (4)
src/website2/README.md (4)
1-2
: Remove trailing punctuation from the "Getting Started" heading.The period at the end of "## Getting Started." violates markdown style guidelines (MD026). Consider updating it to "## Getting Started" for consistency and clarity.
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
1-1: Trailing punctuation in heading
Punctuation: '.'(MD026, no-trailing-punctuation)
15-16
: Remove stray text "test".The standalone word "test" appears to be leftover from debugging or an incomplete edit. Please remove it to ensure the documentation remains professional.
23-23
: Remove trailing punctuation from the "Learn More" heading.The heading "## Learn More." includes an unnecessary period. Removing it will better conform to markdown conventions.
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
23-23: Trailing punctuation in heading
Punctuation: '.'(MD026, no-trailing-punctuation)
1-222
: Ensure consistent header styling and overall content organization.After resolving merge conflicts, verify that the document follows a consistent heading style (preferably ATX) and that duplicate sections are removed. A streamlined, well-structured README will improve readability and maintainability.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~100-~100: The official spelling of this programming framework is “Node.js”.
Context: ...ll or update Node.js, download it from nodejs.org or use a vers...(NODE_JS)
[uncategorized] ~163-~163: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...ting We welcome contributions from the open source community. To help you get started, ple...(EN_COMPOUND_ADJECTIVE_INTERNAL)
🪛 markdownlint-cli2 (0.17.2)
1-1: Trailing punctuation in heading
Punctuation: '.'(MD026, no-trailing-punctuation)
23-23: Trailing punctuation in heading
Punctuation: '.'(MD026, no-trailing-punctuation)
36-36: Heading style
Expected: atx; Actual: setext(MD003, heading-style)
36-36: Trailing punctuation in heading
Punctuation: '.'(MD026, no-trailing-punctuation)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/website2/README.md
(1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
src/website2/README.md
1-1: Trailing punctuation in heading
Punctuation: '.'
(MD026, no-trailing-punctuation)
23-23: Trailing punctuation in heading
Punctuation: '.'
(MD026, no-trailing-punctuation)
36-36: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
36-36: Trailing punctuation in heading
Punctuation: '.'
(MD026, no-trailing-punctuation)
🔇 Additional comments (1)
src/website2/README.md (1)
37-41
:⚠️ Potential issueResolve unresolved merge conflict markers.
There are visible merge conflict markers (e.g., "=======") starting around this region. This indicates that two versions of the content have not been reconciled, leading to duplicate or conflicting sections. Please resolve these conflicts—choose the appropriate content and remove all conflict markers—to ensure a clear and professional README.
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
🔭 Outside diff range comments (2)
src/website2/README.md (2)
35-40
:⚠️ Potential issueResolve Merge Conflict Markers
There are unresolved merge conflict markers (e.g.,
=======
) present beginning at line 35. This results in duplicated and ambiguous content in the README. Please resolve the conflicts by choosing the appropriate content—either the new instructions or the legacy sections—and remove all conflict markers.
35-44
:⚠️ Potential issueClarify and Consolidate Documentation Structure
Due to the merge conflict, the README currently presents two overlapping sections (the new "Getting Started" segment and the original content starting with "# Website"). Once the conflict markers are resolved, please ensure that the final document has a clear, unified structure. Decide whether to merge the introductions into one cohesive guide or organize them under distinct, well-labeled sections.
🧹 Nitpick comments (1)
src/website2/README.md (1)
30-34
: Markdown Heading Style ConsistencyPlease verify that all headings throughout the file adhere to the ATX style (using
#
characters) and omit any trailing punctuation, as suggested by markdownlint (MD003 and MD026). Although the headings in this segment appear fine, double-checking can help maintain a consistent style across the documentation.🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
34-34: Heading style
Expected: atx; Actual: setext(MD003, heading-style)
34-34: Trailing punctuation in heading
Punctuation: '.'(MD026, no-trailing-punctuation)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/website2/README.md
(1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
src/website2/README.md
34-34: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
34-34: Trailing punctuation in heading
Punctuation: '.'
(MD026, no-trailing-punctuation)
🔇 Additional comments (1)
src/website2/README.md (1)
1-20
: New "Getting Started" Section is Clear and InformativeThe newly added "Getting Started" instructions effectively guide developers through installing dependencies and launching the development server. The step-by-step format and inclusion of commands for various package managers are a strong addition. In future iterations, consider integrating notes on internationalization once those features are ready to be documented.
…oses/AirQo-frontend into ft/lang-support-issue#2479
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 comments (2)
src/website2/public/locales/fr.json (1)
137-137
:⚠️ Potential issueExtra Trailing Content Detected.
A stray numeral appears on line 137 that does not conform to valid JSON syntax. Please remove this extraneous line to avoid potential parsing errors.src/website2/public/locales/en.json (1)
137-137
:⚠️ Potential issueExtra Trailing Content Detected.
Similar to the French file, a stray numeral is present on line 137. Removing this extra line will ensure the JSON remains valid and parseable.
🧹 Nitpick comments (5)
src/website2/public/locales/fr.json (1)
37-46
: Language Phrasing Consistency Suggestion.
In the engagementDialog options (e.g., for "partner" and "communityChampion"), the descriptions use “Intéressé à…” which might be less idiomatic in French. Consider revising to “Intéressé par…” for a more natural expression of interest.src/website2/public/locales/en.json (1)
15-15
: Phrasing Clarity Improvement.
The "apiDescription" reads “...leverage our open-air quality data on your App.” Consider rephrasing it to “in your app” (or “within your application”) for clarity and to follow conventional usage.src/website2/README.md (3)
36-44
: Header Consistency and Enhancement Suggestion
- The heading “# Website” is inconsistent with the other section headers that use “##”. For uniformity, consider changing it to “## Website”.
- Additionally, since this PR introduces internationalization support, it might be helpful to briefly mention the new language capabilities (English & French) in this introductory section.
Suggested changes:
-# Website +## Websiteand consider adding a new sub-section such as:
+## Internationalization (i18n) +This project now supports multiple languages (English and French) using the next-intl library. Navigate to /en or /fr in your browser to view localized content.
63-99
: Detailed Setup Instructions: Well Organized
The step-by-step guide for cloning the repository, navigating to the correct folder, and installing dependencies is clear and useful. There is a slight repetition when compared to the Quick Start section—consider consolidating or clarifying the purpose of each to avoid potential confusion.🧰 Tools
🪛 LanguageTool
[uncategorized] ~98-~98: The official spelling of this programming framework is “Node.js”.
Context: ...ll or update Node.js, download it from nodejs.org or use a vers...(NODE_JS)
217-220
: Consider Documenting Internationalization Features
While the README covers setup and deployment comprehensively, it currently lacks a dedicated section on the new internationalization support introduced in this PR. Including a brief note on how to test and use the language features (e.g., switching between English and French) would enhance clarity for contributors and users.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/website2/README.md
(1 hunks)src/website2/public/locales/en.json
(1 hunks)src/website2/public/locales/fr.json
(1 hunks)
🔇 Additional comments (12)
src/website2/public/locales/fr.json (1)
1-136
: Overall Structure and Content Verification.
The new French localization file is well-organized and covers key sections (home, playerSection, engagementDialog, navbar) with comprehensive translations. The hierarchical structure aligns nicely with the frontend’s expected usage.src/website2/public/locales/en.json (1)
1-136
: Overall Structure and Content Verification.
The new English localization file is clearly structured and provides detailed translations for each website section. The keys and values are organized consistently to support the internationalization efforts.src/website2/README.md (10)
1-14
: Quick Start Instructions: Clear and Concise Guidance
The instructions for launching the development server using various package managers (npm, yarn, pnpm, bun) are well presented and easy to follow.
19-29
: "Learn More" Section Approved
The section providing links to Next.js Documentation and the interactive tutorial is informative and aligns well with project documentation.
30-34
: Deploy on Vercel Section Looks Good
Clear instructions for using Vercel to deploy the application are present.
46-60
: Table of Contents Updated
The detailed table of contents enhances navigation through the README and is structured well.
109-118
: Development Server Launch Instructions Are Clear
The guidance for launching the development server is concise and straightforward.
126-143
: Environment Variables & Workflow Updates: Comprehensive and Helpful
The instructions for updating environment variables and workflow configurations are thorough—this is very useful for maintaining consistency across different environments.
146-156
: Backend & Database Integration Instructions: Clear
The guidelines provided for connecting to the backend and setting up database integration are detailed and well explained.
159-198
: Contribution Guidelines: Excellent Onboarding Documentation
The “Contributing” section offers clear, step-by-step instructions for contributors. This level of detail is great for helping new contributors get started with the project.🧰 Tools
🪛 LanguageTool
[uncategorized] ~161-~161: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...ting We welcome contributions from the open source community. To help you get started, ple...(EN_COMPOUND_ADJECTIVE_INTERNAL)
201-209
: Additional Learning Resources are Well Curated
The “Learn More” section concisely aggregates several valuable resources for Next.js development.
211-214
: Deployment Instructions: Solid Guidance Provided
The deployment section provides clear direction with relevant links, making it easy for users to understand the deployment process.
src/website2/README.md
Outdated
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. | ||
|
||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Update File Modification Reference
The line “You can start editing the page by modifying app/page.tsx
” should be updated to reflect the new file structure where pages have been moved to the [locale]
directory (e.g., app/[locale]/page.tsx
). This will help avoid confusion when navigating the project after the internationalization refactor.
Suggested change:
-You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+You can start editing the page by modifying files under `app/[locale]/` (e.g., `app/[locale]/page.tsx`). The page auto-updates as you edit the files.
📝 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.
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. | |
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. | |
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. | |
You can start editing the page by modifying files under `app/[locale]/` (e.g., `app/[locale]/page.tsx`). The page auto-updates as you edit the files. |
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 (1)
src/website2/README.md (1)
200-209
: Potential Redundancy in “Learn More” Sections
There are two “Learn More” sections in the README (one at the top and another later on). Consolidating these into a single, unified section could reduce confusion and streamline the documentation.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/website2/README.md
(2 hunks)
🔇 Additional comments (16)
src/website2/README.md (16)
1-13
: Clear Quick Start Instructions for Development Server
The “Getting Started” section now provides clear, concise commands for running the development server using various package managers. This greatly improves the onboarding experience for new developers.
15-17
: Accurate Update of Page Editing Instructions
The instructions now referenceapp/[locale]/page.tsx
, which aligns with the new internationalized file structure. This clarity minimizes confusion when editing the page.
19-20
: Optimized Font Handling Using next/font
Linking to Next.js’s optimized font loading vianext/font
is a great touch for performance.
21-29
: Helpful “Learn More” Section with Updated Resources
The newly added “Learn More” section offers worthwhile links directly to Next.js resources and tutorials. The list is succinct and well organized.
30-35
: Clear Deployment Instructions via Vercel
The “Deploy on Vercel” section provides an accessible guide for deploying the app, which is particularly useful for new deployments.
46-60
: Updated Table of Contents Reflecting New Structure
The Table of Contents has been refreshed to include links to “Getting Started,” “Learn More,” and other key sections. Ensure that the anchor links (e.g.,#getting-started-1
and#learn-more-1
) correctly map to the intended headers.
63-77
: Detailed “Getting Started” Instructions for Repository Setup
The step-by-step instructions for cloning the repository and initial setup are clearly laid out. This section is very reader-friendly and covers multiple operating systems.
78-88
: Straightforward Navigation to the Website Folder
The directions on navigating to the correct folder (AirQo-frontend/src/website2
) are clear and precise.
89-108
: Comprehensive Dependency Installation Guidelines
The instructions for checking Node.js and installing dependencies, complete with OS-specific tips, ensure that newcomers will encounter fewer hurdles during setup.🧰 Tools
🪛 LanguageTool
[uncategorized] ~98-~98: The official spelling of this programming framework is “Node.js”.
Context: ...ll or update Node.js, download it from nodejs.org or use a vers...(NODE_JS)
109-118
: Concise Command for Launching the Development Server
The command to launch the development server is repeated here for emphasis; it serves as a useful reminder after the detailed setup instructions.
119-123
: Useful Additional Tips for Mac/Linux Users
The extra tips help address common issues (like permission problems) on Mac and Linux, further improving the developer experience.
125-143
: Clear Guidance on Environment Variables & Workflow Updates
The section on updating environment variables and CI/CD workflows is detailed and offers actionable instructions. Verifying that secret names match in the workflows is a good practice here.
146-157
: Thorough Instructions for Backend & Database Integration
This part clearly outlines the need for a database URL and instructs contributors to contact the project admin, which helps maintain security and proper configuration.🧰 Tools
🪛 LanguageTool
[uncategorized] ~151-~151: Possible missing comma found.
Context: ...ccess:** You will need the database URL which is not publicly available. **...(AI_HYDRA_LEO_MISSING_COMMA)
159-198
: Well-Structured Contributing Guidelines
The “Contributing” section is comprehensive, providing clear, ordered steps from forking the repository to opening a pull request. This structure promotes a smooth contribution process.🧰 Tools
🪛 LanguageTool
[uncategorized] ~161-~161: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...ting We welcome contributions from the open source community. To help you get started, ple...(EN_COMPOUND_ADJECTIVE_INTERNAL)
211-214
: Straightforward Deployment Section
The “Deployment” section clearly directs users to the Vercel platform with a link to detailed documentation. This clarity is beneficial for new deployers.
215-220
: Friendly Concluding Remarks
The final “Thank you” section adds a welcoming tone and acknowledges contributor efforts—a nice finishing touch to the documentation.
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 (2)
src/website2/public/locales/fr.json (1)
1-229
: Localization Language and Consistency Check
The French translations are comprehensive and mostly accurate. For example, the phrasing in several sections is clear and contextually fitting. One minor suggestion: consider reviewing phrases like
"Intéressé à soutenir la vision d'AirQo"
for possibly more idiomatic alternatives (e.g."Intéressé par le soutien à la vision d'AirQo"
). It might be helpful to have a native speaker validate these subtle choices.src/website2/public/locales/en.json (1)
13-16
: API Description Text Consistency
In the "home" section, the "apiDescription" reads:
"Are you a developer? We invite you to leverage our open-air quality data on your App"
The phrase "on your App" sounds slightly unconventional. Consider rephrasing it to "in your app" for a more natural flow. For example:-"apiDescription": "Are you a developer? We invite you to leverage our open-air quality data on your App" +"apiDescription": "Are you a developer? We invite you to leverage our open-air quality data in your app"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/website2/public/locales/en.json
(1 hunks)src/website2/public/locales/fr.json
(1 hunks)
🔇 Additional comments (3)
src/website2/public/locales/fr.json (1)
1-229
: Overall Structure & JSON Validity
The French localization file is well-organized with a clear hierarchical structure and proper JSON syntax. All key sections such as "home", "playerSection", "engagementDialog", "navbar", etc., are present and consistently formatted.src/website2/public/locales/en.json (2)
1-229
: Overall Structure & JSON Validity
The English localization file mirrors its French counterpart in structure and coverage, ensuring that all major sections (home, playerSection, engagementDialog, navbar, notificationBanner, homeStatsSection, highlight, actionButtons, and newsletter) are addressed. The JSON format is correct and the organization is clear.
1-229
: Cross-language Consistency Check
Ensure that all keys and their implied contexts remain consistent across both the English and French localization files. A small discrepancy, such as the difference in interpretation for "champions" in the statistics section, may lead to confusion on the frontend. Verifying this consistency with the product specifications would be beneficial.
src/website2/public/locales/en.json
Outdated
"statistics": { | ||
"african_cities": "Cities", | ||
"champions": "Policy Makers", | ||
"deployed_monitors": "Monitors", | ||
"data_records": "Data Points", | ||
"research_papers": "Researchers", | ||
"partners": "Partners" | ||
}, |
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.
💡 Verification agent
❓ Verification inconclusive
Consistency in the 'champions' Key
Within the "statistics" section, the key "champions" is set to "Policy Makers". However, the French file uses a term suggesting community champions (i.e. "Les champions de la communauté"), and other sections (like the "engagementDialog" and "accordion" under "communities") imply a focus on community leadership rather than policymaking. Please confirm whether "champions" should be consistently translated as "Community Champions" (or equivalent) in English to match the intended context.
Action Required: Revisit the Translation of the "champions" Key
It appears that in the English locale file (src/website2/public/locales/en.json
), the "champions"
key is currently set to "Policy Makers"
, which conflicts with the French translation and other sections (like the "engagementDialog"
and "accordion"
under "communities"
) that imply a focus on community leadership. Please confirm whether this key should consistently be translated in English as "Community Champions"
(or a similar term) to align with the intended context. If the decision is to update it, kindly change the value from "Policy Makers"
to "Community Champions"
and ensure consistency across all relevant sections.
- File to Update:
src/website2/public/locales/en.json
(Lines 158-165) - Suggested Change:
Replace:With:"champions": "Policy Makers",
"champions": "Community Champions",
- Action: Confirm the intended meaning and apply the update accordingly. If sticking with
"Policy Makers"
is deliberate, then verify that the French translations and other related sections are updated to match this terminology.
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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
src/platform/yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (25)
src/website2/next.config.mjs
(2 hunks)src/website2/public/assets/icons/Icon1.tsx
(1 hunks)src/website2/public/assets/icons/Icon2.tsx
(1 hunks)src/website2/public/assets/icons/Icon3.tsx
(1 hunks)src/website2/public/assets/icons/Icon4.tsx
(1 hunks)src/website2/public/assets/icons/Icon5.tsx
(1 hunks)src/website2/public/assets/icons/Icon6.tsx
(1 hunks)src/website2/public/assets/icons/Icon7.tsx
(1 hunks)src/website2/public/assets/icons/Icon8.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/about/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/glossary/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/layout.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/logistics/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/partners/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/program-committee/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/resources/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/sessions/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/speakers/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-forum/sponsorships/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-network/CleanAirPage.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-network/events/[id]/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-network/events/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-network/membership/page.tsx
(1 hunks)src/website2/src/app/[locale]/clean-air-network/resources/page.tsx
(1 hunks)src/website2/src/app/[locale]/layout.tsx
(5 hunks)
🚧 Files skipped from review as they are similar to previous changes (23)
- src/website2/src/app/[locale]/clean-air-network/events/[id]/page.tsx
- src/website2/src/app/[locale]/clean-air-forum/about/page.tsx
- src/website2/src/app/[locale]/clean-air-network/resources/page.tsx
- src/website2/src/app/[locale]/clean-air-network/events/page.tsx
- src/website2/public/assets/icons/Icon3.tsx
- src/website2/src/app/[locale]/clean-air-forum/program-committee/page.tsx
- src/website2/public/assets/icons/Icon1.tsx
- src/website2/src/app/[locale]/clean-air-forum/resources/page.tsx
- src/website2/public/assets/icons/Icon5.tsx
- src/website2/src/app/[locale]/clean-air-network/membership/page.tsx
- src/website2/public/assets/icons/Icon2.tsx
- src/website2/public/assets/icons/Icon8.tsx
- src/website2/src/app/[locale]/clean-air-forum/layout.tsx
- src/website2/src/app/[locale]/clean-air-forum/logistics/page.tsx
- src/website2/src/app/[locale]/clean-air-forum/speakers/page.tsx
- src/website2/src/app/[locale]/clean-air-forum/sessions/page.tsx
- src/website2/next.config.mjs
- src/website2/public/assets/icons/Icon7.tsx
- src/website2/public/assets/icons/Icon4.tsx
- src/website2/src/app/[locale]/clean-air-forum/partners/page.tsx
- src/website2/public/assets/icons/Icon6.tsx
- src/website2/src/app/[locale]/clean-air-forum/glossary/page.tsx
- src/website2/src/app/[locale]/clean-air-forum/sponsorships/page.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
src/website2/src/app/[locale]/clean-air-network/CleanAirPage.tsx
[error] 1-2: Expected a statement but instead found '<<<<<<<< HEAD:src/website2/src/app/[locale]/clean-air-network/CleanAirPage.tsx
'use client''.
Expected a statement here.
(parse)
[error] 198-200: Expected a statement but instead found '========
'use client''.
Expected a statement here.
(parse)
[error] 394-395: Illegal duplicate default export declarations
multiple default exports are erroneous
the module's default export is first defined here
(parse)
[error] 197-198: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 200-200: Shouldn't redeclare 'Image'. Consider to delete it or rename it.
'Image' is defined here:
(lint/suspicious/noRedeclare)
[error] 201-201: Shouldn't redeclare 'React'. Consider to delete it or rename it.
'React' is defined here:
(lint/suspicious/noRedeclare)
[error] 203-203: Shouldn't redeclare 'ContentSection'. Consider to delete it or rename it.
'ContentSection' is defined here:
(lint/suspicious/noRedeclare)
[error] 204-204: Shouldn't redeclare 'FeaturedEvent'. Consider to delete it or rename it.
'FeaturedEvent' is defined here:
(lint/suspicious/noRedeclare)
[error] 206-206: Shouldn't redeclare 'CleanAirPage'. Consider to delete it or rename it.
'CleanAirPage' is defined here:
(lint/suspicious/noRedeclare)
src/website2/src/app/[locale]/layout.tsx
[error] 88-88: Expected a statement but instead found ','.
Expected a statement here.
(parse)
[error] 89-89: Expected a statement but instead found ': Props)'.
Expected a statement here.
(parse)
[error] 88-88: Unexpected label.
Only loops should be labeled.
The use of labels for other statements is suspicious and unfamiliar.
(lint/suspicious/noConfusingLabels)
[error] 88-88: Unused label.
The label is not used by any break statement and continue statement.
Safe fix: Remove the unused label.
(lint/correctness/noUnusedLabels)
🔇 Additional comments (5)
src/website2/src/app/[locale]/layout.tsx (5)
1-1
: Confirm correct global stylesheet import location.The updated import for
../globals.css
should be verified to ensure that the styles are loaded correctly. If the file was previously imported from a different relative path, confirm that this new location matches your final folder structure.
5-6
: Good approach for introducing NextIntl.The newly added imports for
NextIntlClientProvider
andgetMessages
look correct. This is a proper way to integrate i18n functionality in Next.js.
20-26
: Re-check local font paths.You’ve updated the paths for Inter fonts. Ensure that the referenced TTF files exist at these new relative locations and are correctly spelled.
33-36
: Clear type definition for layout props.Defining a
Props
type improves clarity for the layout function. Confirm that all references toparams.locale
throughout this file and related code adhere to the newly introduced type.
175-178
: Internationalization wrapper looks good.Wrapping
<EngagementDialog>
and{children}
with<NextIntlClientProvider>
is the correct way to ensure translations are accessible throughout the layout.
src/website2/src/app/[locale]/clean-air-network/CleanAirPage.tsx
Outdated
Show resolved
Hide resolved
/> | ||
</div> | ||
</section> | ||
|
||
<div className="max-w-5xl mx-auto w-full mt-16"> | ||
<ContentSection | ||
subtitle="Mission" | ||
title="The CLEAN-Air Mission" | ||
description={ | ||
<p> | ||
To strengthen regional networks for sustained partnerships and | ||
enable partners to co-develop solutions that enhance the capacity | ||
for air quality monitoring, modelling and management across cities | ||
in Africa. | ||
</p> | ||
} | ||
contentClassName="text-left space-y-4" | ||
buttonClassName="hidden" | ||
imgSrc="https://res.cloudinary.com/dbibjvyhm/image/upload/v1728132391/website/cleanAirForum/images/section3_vgzcbs.webp" | ||
imgAlt="Mission Image" | ||
reverse={true} | ||
/> | ||
</div> | ||
|
||
<div className="max-w-5xl mx-auto w-full mt-16"> | ||
<ContentSection | ||
subtitle="Membership" | ||
title="A Synergy for Air Quality in Africa" | ||
description={ | ||
<div className="space-y-3"> | ||
<p> | ||
The network comprises a diverse stakeholder landscape including | ||
research organisations, city and national governments, the | ||
private sector, development partners, and individuals who are | ||
championing the air quality agenda in African cities. | ||
</p> | ||
<p> | ||
Are you an organization or individual interested in air quality | ||
in Africa? We welcome you to join the CLEAN-Air Network. | ||
</p> | ||
</div> | ||
} | ||
contentClassName="text-left space-y-4" | ||
buttonClassName="hidden" | ||
imgSrc="https://res.cloudinary.com/dbibjvyhm/image/upload/v1728132391/website/cleanAirForum/images/section4_kudfs4.webp" | ||
imgAlt="Synergy Image" | ||
reverse={false} | ||
/> | ||
</div> | ||
|
||
<section className="bg-blue-50 w-full mt-16"> | ||
<div className="max-w-5xl mx-auto w-full py-16 px-4 lg:px-0"> | ||
<div className="text-left mb-12"> | ||
<span className="text-blue-600 text-[14px] bg-white rounded-full py-1 px-4 font-semibold mb-2 inline-block"> | ||
Goals | ||
</span> | ||
<h2 className="text-4xl lg:text-[48px] leading-[1.1] font-medium"> | ||
CLEAN Air Goals | ||
</h2> | ||
</div> | ||
|
||
<div className="space-y-16"> | ||
{goals.map((goal) => ( | ||
<div | ||
key={goal.id} | ||
className="flex flex-col lg:flex-row items-center lg:gap-4" | ||
> | ||
{/* Icon Section */} | ||
<div className="w-[231px] h-[174px] mb-6 lg:mb-0"> | ||
<Image | ||
src={goal.icon} | ||
alt={goal.title} | ||
width={192} | ||
height={176} | ||
className="object-cover rounded-lg" | ||
/> | ||
</div> | ||
|
||
{/* Content Section */} | ||
<div className="flex-1"> | ||
<h3 className="text-3xl lg:text-[32px] leading-[1.1] font-medium mb-2"> | ||
{goal.title} | ||
</h3> | ||
<p className="text-[20px] text-gray-600"> | ||
{goal.description} | ||
</p> | ||
</div> | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
</section> | ||
|
||
<FeaturedEvent /> | ||
</div> | ||
); | ||
}; | ||
|
||
export default CleanAirPage; | ||
>>>>>>>> origin/staging:src/website2/src/views/cleanAirNetwork/about/CleanAirPage.tsx |
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.
Eliminate duplicate defaults and finalize the merged content.
The file includes additional conflict markers (========
, >>>>>>>> ...
) and a second copy of the entire component. This leads to re-imported symbols (React
, Image
, ContentSection
, FeaturedEvent
) and multiple default export declarations, which break the build. Unify both sections into one clean component definition and remove all conflict markers.
Below is an example of a merged structure (keeping references to @/views/cleanAirNetwork
if that is the correct final path and ensuring only one export default
):
-========
-'use client';
-(repeated imports and component code)
->>>>>>>>
+// Ensure this file has only one cohesive version of the CleanAirPage component
+// and one `export default CleanAirPage;`.
Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 Biome (1.9.4)
[error] 198-200: Expected a statement but instead found '========
'use client''.
Expected a statement here.
(parse)
[error] 394-395: Illegal duplicate default export declarations
multiple default exports are erroneous
the module's default export is first defined here
(parse)
[error] 197-198: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 200-200: Shouldn't redeclare 'Image'. Consider to delete it or rename it.
'Image' is defined here:
(lint/suspicious/noRedeclare)
[error] 201-201: Shouldn't redeclare 'React'. Consider to delete it or rename it.
'React' is defined here:
(lint/suspicious/noRedeclare)
[error] 203-203: Shouldn't redeclare 'ContentSection'. Consider to delete it or rename it.
'ContentSection' is defined here:
(lint/suspicious/noRedeclare)
[error] 204-204: Shouldn't redeclare 'FeaturedEvent'. Consider to delete it or rename it.
'FeaturedEvent' is defined here:
(lint/suspicious/noRedeclare)
[error] 206-206: Shouldn't redeclare 'CleanAirPage'. Consider to delete it or rename it.
'CleanAirPage' is defined here:
(lint/suspicious/noRedeclare)
params: { locale }, | ||
}: Props) { | ||
const maintenance = await checkMaintenance(); | ||
const messages = await getMessages(); |
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 suspicious label or syntax.
The function signature is split, causing parse errors (unused label and mismatched brace). Merge the destructuring and the type annotation into a single declaration to resolve syntax issues. For example:
-export default async function RootLayout({
- children,
-}: {
- children: ReactNode;
-}) {
+export default async function RootLayout({ children, params }: Props) {
const maintenance = await checkMaintenance();
const messages = await getMessages();
...
🧰 Tools
🪛 Biome (1.9.4)
[error] 88-88: Expected a statement but instead found ','.
Expected a statement here.
(parse)
[error] 89-89: Expected a statement but instead found ': Props)'.
Expected a statement here.
(parse)
[error] 88-88: Unexpected label.
Only loops should be labeled.
The use of labels for other statements is suspicious and unfamiliar.
(lint/suspicious/noConfusingLabels)
[error] 88-88: Unused label.
The label is not used by any break statement and continue statement.
Safe fix: Remove the unused label.
(lint/correctness/noUnusedLabels)
@@ -151,6 +163,7 @@ export default async function RootLayout({ | |||
`} | |||
</Script> | |||
</head> | |||
<html lang={locale} className={interFont.variable}> |
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 multiple tags.
There are now two <html>
elements: one at line 96 and another at line 166. Retain only the later one that uses lang={locale}
to ensure proper internationalization and remove the earlier <html lang="en">
.
-<html lang="en" className={interFont.variable}>
+<html lang={locale} className={interFont.variable}>
Committable suggestion skipped: line range outside the PR's diff.
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: 8
🧹 Nitpick comments (2)
src/website2/src/app/[locale]/clean-air-network/CleanAirPage.tsx (2)
92-99
: Image component uses deprecated layout prop.The Image component is using a deprecated
layout="responsive"
prop. In Next.js 13+, this has been replaced with style or className properties.Update the Image component to use the new pattern:
<Image src="https://res.cloudinary.com/dbibjvyhm/image/upload/v1728132390/website/cleanAirForum/images/section2_jnqqyu.webp" alt="Urban Scene" - layout="responsive" width={1200} height={400} - className="object-cover" + className="object-cover w-full h-auto" + style={{ aspectRatio: '3/1' }} />
168-174
: Consider using next-image optimizations for Cloudinary images.The Image component is correctly used but could benefit from additional optimizations when working with Cloudinary.
Consider adding loader configuration for Cloudinary in your next.config.js and updating image references:
<Image src={goal.icon} alt={goal.title} width={192} height={176} className="object-cover rounded-lg" + quality={90} + placeholder="blur" + blurDataURL="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 192 176'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' fill='%23f3f4f6'/%3E%3C/svg%3E" />
|
||
<FeaturedEvent /> | ||
</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.
💡 Verification agent
🧩 Analysis chain
FeaturedEvent component lacks internationalization context.
The FeaturedEvent component is being used without passing any internationalization context or props.
Check if the FeaturedEvent component has its own internationalization implementation or if it needs props to be passed from this parent component:
🏁 Script executed:
#!/bin/bash
# Look for the FeaturedEvent component implementation
fd "FeaturedEvent" src/website2/src/views/
# Check for i18n implementation in the component
fd "FeaturedEvent" src/website2/src/views/ --exec grep -l "useTranslations\|next-intl" {} \;
Length of output: 195
Action Required: Address Missing Internationalization in FeaturedEvent
It appears that the FeaturedEvent
component in src/website2/src/views/cleanAirNetwork/FeaturedEvent.tsx
does not implement internationalization hooks (e.g., useTranslations
or next-intl
), nor does it receive any i18n props from its parent. Please either integrate the necessary internationalization logic directly in the component or pass the appropriate i18n context/props from CleanAirPage
.
- Verify if the component should self-manage translations.
- If not, update
CleanAirPage
to provide the required i18n context toFeaturedEvent
.
src/website2/src/app/[locale]/clean-air-network/CleanAirPage.tsx
Outdated
Show resolved
Hide resolved
src/website2/src/app/[locale]/clean-air-network/CleanAirPage.tsx
Outdated
Show resolved
Hide resolved
src/website2/src/app/[locale]/clean-air-network/CleanAirPage.tsx
Outdated
Show resolved
Hide resolved
|
||
<section className="bg-blue-50 w-full mt-16"> | ||
<div className="max-w-5xl mx-auto w-full py-16 px-4 lg:px-0"> | ||
<div className="text-left mb-12"> | ||
<span className="text-blue-600 text-[14px] bg-white rounded-full py-1 px-4 font-semibold mb-2 inline-block"> | ||
Goals | ||
</span> | ||
<h2 className="text-4xl lg:text-[48px] leading-[1.1] font-medium"> | ||
CLEAN Air Goals | ||
</h2> | ||
</div> | ||
|
||
<div className="space-y-16"> | ||
{goals.map((goal) => ( | ||
<div | ||
key={goal.id} | ||
className="flex flex-col lg:flex-row items-center lg:gap-4" | ||
> | ||
{/* Icon Section */} | ||
<div className="w-[231px] h-[174px] mb-6 lg:mb-0"> | ||
<Image | ||
src={goal.icon} | ||
alt={goal.title} | ||
width={192} | ||
height={176} | ||
className="object-cover rounded-lg" | ||
/> | ||
</div> | ||
|
||
{/* Content Section */} | ||
<div className="flex-1"> | ||
<h3 className="text-3xl lg:text-[32px] leading-[1.1] font-medium mb-2"> | ||
{goal.title} | ||
</h3> | ||
<p className="text-[20px] text-gray-600"> | ||
{goal.description} | ||
</p> | ||
</div> | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
</section> |
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
Goals section heading and display need internationalization.
The goals section heading and the rendering of goals should use translations.
Implement translations for the goals section:
<section className="bg-blue-50 w-full mt-16">
<div className="max-w-5xl mx-auto w-full py-16 px-4 lg:px-0">
<div className="text-left mb-12">
<span className="text-blue-600 text-[14px] bg-white rounded-full py-1 px-4 font-semibold mb-2 inline-block">
- Goals
+ {t('goals.label')}
</span>
<h2 className="text-4xl lg:text-[48px] leading-[1.1] font-medium">
- CLEAN Air Goals
+ {t('goals.heading')}
</h2>
</div>
<div className="space-y-16">
{goals.map((goal) => (
<div
key={goal.id}
className="flex flex-col lg:flex-row items-center lg:gap-4"
>
{/* Icon Section */}
<div className="w-[231px] h-[174px] mb-6 lg:mb-0">
<Image
src={goal.icon}
alt={goal.title}
width={192}
height={176}
className="object-cover rounded-lg"
/>
</div>
{/* Content Section */}
<div className="flex-1">
<h3 className="text-3xl lg:text-[32px] leading-[1.1] font-medium mb-2">
{goal.title}
</h3>
<p className="text-[20px] text-gray-600">
{goal.description}
</p>
</div>
</div>
))}
</div>
</div>
</section>
📝 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.
<section className="bg-blue-50 w-full mt-16"> | |
<div className="max-w-5xl mx-auto w-full py-16 px-4 lg:px-0"> | |
<div className="text-left mb-12"> | |
<span className="text-blue-600 text-[14px] bg-white rounded-full py-1 px-4 font-semibold mb-2 inline-block"> | |
Goals | |
</span> | |
<h2 className="text-4xl lg:text-[48px] leading-[1.1] font-medium"> | |
CLEAN Air Goals | |
</h2> | |
</div> | |
<div className="space-y-16"> | |
{goals.map((goal) => ( | |
<div | |
key={goal.id} | |
className="flex flex-col lg:flex-row items-center lg:gap-4" | |
> | |
{/* Icon Section */} | |
<div className="w-[231px] h-[174px] mb-6 lg:mb-0"> | |
<Image | |
src={goal.icon} | |
alt={goal.title} | |
width={192} | |
height={176} | |
className="object-cover rounded-lg" | |
/> | |
</div> | |
{/* Content Section */} | |
<div className="flex-1"> | |
<h3 className="text-3xl lg:text-[32px] leading-[1.1] font-medium mb-2"> | |
{goal.title} | |
</h3> | |
<p className="text-[20px] text-gray-600"> | |
{goal.description} | |
</p> | |
</div> | |
</div> | |
))} | |
</div> | |
</div> | |
</section> | |
<section className="bg-blue-50 w-full mt-16"> | |
<div className="max-w-5xl mx-auto w-full py-16 px-4 lg:px-0"> | |
<div className="text-left mb-12"> | |
<span className="text-blue-600 text-[14px] bg-white rounded-full py-1 px-4 font-semibold mb-2 inline-block"> | |
{t('goals.label')} | |
</span> | |
<h2 className="text-4xl lg:text-[48px] leading-[1.1] font-medium"> | |
{t('goals.heading')} | |
</h2> | |
</div> | |
<div className="space-y-16"> | |
{goals.map((goal) => ( | |
<div | |
key={goal.id} | |
className="flex flex-col lg:flex-row items-center lg:gap-4" | |
> | |
{/* Icon Section */} | |
<div className="w-[231px] h-[174px] mb-6 lg:mb-0"> | |
<Image | |
src={goal.icon} | |
alt={goal.title} | |
width={192} | |
height={176} | |
className="object-cover rounded-lg" | |
/> | |
</div> | |
{/* Content Section */} | |
<div className="flex-1"> | |
<h3 className="text-3xl lg:text-[32px] leading-[1.1] font-medium mb-2"> | |
{goal.title} | |
</h3> | |
<p className="text-[20px] text-gray-600"> | |
{goal.description} | |
</p> | |
</div> | |
</div> | |
))} | |
</div> | |
</div> | |
</section> |
src/website2/src/app/[locale]/clean-air-network/CleanAirPage.tsx
Outdated
Show resolved
Hide resolved
return ( | ||
<div className="flex flex-col overflow-hidden"> | ||
<div className="max-w-5xl mx-auto w-full"> | ||
<ContentSection | ||
title="The CLEAN-Air Network" | ||
description={ | ||
<p> | ||
<span className="text-blue-700 font-medium"> | ||
An African-led, multi-regional network | ||
</span> | ||
<br /> | ||
bringing together a community of practice for air quality | ||
solutions and air quality management across Africa. | ||
</p> | ||
} | ||
buttonText="Join the Network" | ||
buttonLink="https://docs.google.com/forms/d/e/1FAIpQLScIPz7VrhfO2ifMI0dPWIQRiGQ9y30LoKUCT-DDyorS7sAKUA/viewform" | ||
titleClassName="text-4xl lg:text-[56px] leading-[1.1]" | ||
contentClassName="text-left space-y-4" | ||
buttonClassName="rounded-none" | ||
imgSrc="https://res.cloudinary.com/dbibjvyhm/image/upload/v1728132390/website/cleanAirForum/images/section1_usfuoj.webp" | ||
imgAlt="Mission Image" | ||
reverse={true} | ||
/> | ||
</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
Text content in the ContentSection needs internationalization.
The first ContentSection component contains hardcoded English text that should be localized for proper i18n support.
Replace the hardcoded title and description with translated versions:
return (
<div className="flex flex-col overflow-hidden">
<div className="max-w-5xl mx-auto w-full">
<ContentSection
- title="The CLEAN-Air Network"
+ title={t('section1.title')}
description={
<p>
<span className="text-blue-700 font-medium">
- An African-led, multi-regional network
+ {t('section1.highlight')}
</span>
<br />
- bringing together a community of practice for air quality
- solutions and air quality management across Africa.
+ {t('section1.description')}
</p>
}
- buttonText="Join the Network"
+ buttonText={t('cta.join')}
buttonLink="https://docs.google.com/forms/d/e/1FAIpQLScIPz7VrhfO2ifMI0dPWIQRiGQ9y30LoKUCT-DDyorS7sAKUA/viewform"
titleClassName="text-4xl lg:text-[56px] leading-[1.1]"
contentClassName="text-left space-y-4"
buttonClassName="rounded-none"
imgSrc="https://res.cloudinary.com/dbibjvyhm/image/upload/v1728132390/website/cleanAirForum/images/section1_usfuoj.webp"
imgAlt="Mission Image"
reverse={true}
/>
</div>
📝 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 ( | |
<div className="flex flex-col overflow-hidden"> | |
<div className="max-w-5xl mx-auto w-full"> | |
<ContentSection | |
title="The CLEAN-Air Network" | |
description={ | |
<p> | |
<span className="text-blue-700 font-medium"> | |
An African-led, multi-regional network | |
</span> | |
<br /> | |
bringing together a community of practice for air quality | |
solutions and air quality management across Africa. | |
</p> | |
} | |
buttonText="Join the Network" | |
buttonLink="https://docs.google.com/forms/d/e/1FAIpQLScIPz7VrhfO2ifMI0dPWIQRiGQ9y30LoKUCT-DDyorS7sAKUA/viewform" | |
titleClassName="text-4xl lg:text-[56px] leading-[1.1]" | |
contentClassName="text-left space-y-4" | |
buttonClassName="rounded-none" | |
imgSrc="https://res.cloudinary.com/dbibjvyhm/image/upload/v1728132390/website/cleanAirForum/images/section1_usfuoj.webp" | |
imgAlt="Mission Image" | |
reverse={true} | |
/> | |
</div> | |
return ( | |
<div className="flex flex-col overflow-hidden"> | |
<div className="max-w-5xl mx-auto w-full"> | |
<ContentSection | |
title={t('section1.title')} | |
description={ | |
<p> | |
<span className="text-blue-700 font-medium"> | |
{t('section1.highlight')} | |
</span> | |
<br /> | |
{t('section1.description')} | |
</p> | |
} | |
buttonText={t('cta.join')} | |
buttonLink="https://docs.google.com/forms/d/e/1FAIpQLScIPz7VrhfO2ifMI0dPWIQRiGQ9y30LoKUCT-DDyorS7sAKUA/viewform" | |
titleClassName="text-4xl lg:text-[56px] leading-[1.1]" | |
contentClassName="text-left space-y-4" | |
buttonClassName="rounded-none" | |
imgSrc="https://res.cloudinary.com/dbibjvyhm/image/upload/v1728132390/website/cleanAirForum/images/section1_usfuoj.webp" | |
imgAlt="Mission Image" | |
reverse={true} | |
/> | |
</div> | |
</div> | |
); |
src/website2/src/app/[locale]/clean-air-network/CleanAirPage.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/website2/public/locales/en.json (3)
1-23
: Review of "home" Section Structure
The "home" section is well structured with descriptive keys (e.g., "title", "description", "keywords") that clearly capture the intended meta information and page content. The content is organized and self-explanatory.
228-273
: Review of "cleanAirNetwork" Section
This section delivers a detailed narrative for the CLEAN-Air Network, split into intro, acronym, mission, membership, and goals. The descriptive texts are thorough.
One minor suggestion: please double-check the formatting of the "fullName" in the "acronym" block to ensure the quote marks and punctuation meet the design guidelines.
355-397
: Review of "monitorPage" Section
The "monitorPage" spans several important components—from breadcrumb navigation and hero section to detailed descriptions for designed-for-Africa features, mobile monitoring, and installation guidelines. The translations are thorough and contextually accurate.
Minor suggestion: Consider reviewing the length and complexity of some paragraphs for enhanced readability and ease of localization updates in the future.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/website2/public/locales/en.json
(1 hunks)src/website2/public/locales/fr.json
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/website2/public/locales/fr.json
🔇 Additional comments (13)
src/website2/public/locales/en.json (13)
24-32
: Review of "playerSection" Translation
The "playerSection" provides engaging and concise translations, including an impactful quote and clear call-to-action buttons. The content aligns well with the intended messaging.
33-81
: Review of "engagementDialog" Section
This section is comprehensive: the options for different user roles (partner, policymaker, community champion, researcher, developer) and the associated form keys (including HTML-like placeholders in the "termsAndConditions" field) are clearly defined. The error and success messages are straightforward.
82-135
: Review of "navbar" Structure
The "navbar" section is neatly divided into menu items and sub-categories for products, solutions, and about pages. This clear hierarchy aligns well with the website’s navigation design.
136-143
: Review of "notificationBanner" Section
The notification banner correctly includes a nested "language" key for supporting the language switch (English/French). The design is simple and meets the internationalization requirement.
144-196
: Review of "homeStatsSection" and "accordion" Keys
The statistics keys (e.g., "african_cities", "champions", "deployed_monitors") are well defined. Notably, the"champions"
key within the "statistics" block now uses"Community Champions"
, which is an improvement over previous inconsistencies. However, please note that under the "accordion" → "communities" section (lines 182-186), the title is set to"AirQommunity Champions"
.
Please verify whether this slight discrepancy is intentional for branding purposes or if it would be preferable to standardize the terminology.
197-203
: Review of "highlight" Section
The "highlight" section is concise with clear alt text and descriptive information that maintains the context of the featured content.
204-213
: Review of "actionButtons" Section
The action buttons provide clear and compelling calls-to-action with both a title and associated action text, supporting the user engagement goals.
214-227
: Review of "newsletter" Section
The newsletter segment covers all necessary fields—from form labels to submission responses—which will aid in providing a smooth user subscription experience.
274-283
: Review of "actionButtons2" Section
The secondary set of action buttons is succinct and consistent with the other calls-to-action found in the file.
284-293
: Review of "featuredEvent" Section
The featuredEvent block correctly provides fallback text for errors and placeholders for dates and labels, ensuring a robust user experience in case data is missing.
294-336
: Review of "footer" Section
The footer is comprehensive, covering taglines, social links, and navigation sections. The inclusion of legal links and additional site sections ensures complete coverage for footer content.
337-350
: Review of "countrySelector" Section
The "countrySelector" is user-friendly, with clear instructions and dialog components that will help guide user interactions when selecting a country.
351-354
: Review of "monitorDisplay" Section
This section makes effective use of placeholders (e.g.,{country}
) to facilitate dynamic content display, and it is brief yet clear.
Summary of Changes (What does this PR do?)
This PR introduces internationalization (i18n) support for the frontend, allowing the application to support English and French. It leverages
next-intl
for language translation and routing.✅ What’s been done so far:
next.config.mjs
to integratenext-intl
.public/locales/en.json
(English translations)public/locales/fr.json
(French translations)src/config.ts
→ Defines supported locales and pathnames.src/i18n.ts
→ Handles locale-based message loading.src/middleware.ts
→ Middleware for locale redirection.src/navigation.ts
→ Provides a customLink
component for localized navigation.app
directory into[locale]
to support dynamic language routing.src/app/[locale]/layout.tsx
file with<NextIntlClientProvider>
to manage translations.src/views/home/HomePage.tsx
):useTranslations('home')
to fetch localized text.🚧 What’s still in progress?
Status of maturity (all need to be checked before merging):
How should this be manually tested?
What are the relevant tickets?
Screenshots (optional)
**In English
**In French
Summary by CodeRabbit
New Features
CleanAirPage
component added to display information about the CLEAN-Air Network.Chores
.env.sample
files for both the website and mobile applications.