Feature/multilingual about#95
Conversation
✅ Deploy Preview for develop-devlovers ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
📝 WalkthroughWalkthroughThis PR adds internationalization across the frontend by introducing next-intl Changes
Sequence Diagram(s)(omitted) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
frontend/components/blog/BlogFilters.tsx (2)
91-102: Variabletshadows the translation function.The filter callback uses
tas the iteration variable, which shadows theuseTranslationshook result. While this works becausetfromuseTranslationsisn't used inside these callbacks, it reduces code clarity and could cause confusion during maintenance.🔎 Suggested fix: rename the iteration variable
const removeTag = (tag: string) => { - setSelectedTags(prev => prev.filter(t => t !== tag)); + setSelectedTags(prev => prev.filter(item => item !== tag)); }; const toggleTag = (raw: string) => { const norm = normalizeTag(raw); if (!norm) return; setSelectedTags(prev => - prev.includes(norm) ? prev.filter(t => t !== norm) : [...prev, norm] + prev.includes(norm) ? prev.filter(item => item !== norm) : [...prev, norm] ); };
259-263: Consider showing a different message when there are no posts at all vs. no posts for selected tags.Currently, if
filteredPostsis empty,t('noPostsForTags')is shown regardless of whether tags are selected. If no tags are selected and there are simply no posts, the message "No posts found for selected tags" would be misleading.🔎 Suggested fix
{!filteredPosts.length && ( <p className="text-center text-gray-500 mt-10"> - {t('noPostsForTags')} + {selectedTags.length > 0 ? t('noPostsForTags') : t('noPosts')} </p> )}frontend/components/about/CommunitySection.tsx (1)
82-84: Using array index as React key in duplicated list.Since testimonials are duplicated for the infinite scroll animation (
[...testimonials, ...testimonials]), usingindexas the key will result in duplicate keys (e.g., two elements with key0,1, etc.). While this works because the list is static and never re-ordered, using a more unique key would be cleaner.🔎 Suggested fix
- {[...testimonials, ...testimonials].map((testimonial, index) => ( - <TestimonialCard key={index} {...testimonial} /> + {[...testimonials, ...testimonials].map((testimonial, index) => ( + <TestimonialCard key={`${testimonial.name}-${index}`} {...testimonial} /> ))}frontend/components/about/FeaturesSection.tsx (1)
17-19: Consider liftinguseTranslationsout ofFeatureCard.
useTranslations("about.features")is called insideFeatureCard, which means it runs once per card (6 times total). Since the only usage ist("learnMore")on line 49, consider either:
- Adding a
learnMoreLabelprop toFeatureCardand passing the translated string from the parent- Using a single translation instance from the parent
FeaturesSection🔎 Proposed fix: Pass translated string as prop
interface FeatureCardProps { icon: React.ReactNode title: string description: string href: string className?: string children?: React.ReactNode + learnMoreLabel: string } -function FeatureCard({ icon, title, description, href, className = "", children }: FeatureCardProps) { - const t = useTranslations("about.features") - +function FeatureCard({ icon, title, description, href, className = "", children, learnMoreLabel }: FeatureCardProps) { return ( // ... <Link href={href} className="..." > - {t("learnMore")} + {learnMoreLabel} </Link>Then in each
<FeatureCard>usage, addlearnMoreLabel={t("learnMore")}.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
frontend/components/about/CommunitySection.tsxfrontend/components/about/FeaturesSection.tsxfrontend/components/about/HeroSection.tsxfrontend/components/about/PricingSection.tsxfrontend/components/about/StatsSection.tsxfrontend/components/blog/BlogCard.tsxfrontend/components/blog/BlogFilters.tsxfrontend/components/shared/Footer.tsxfrontend/messages/en.jsonfrontend/messages/pl.jsonfrontend/messages/uk.json
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/components/about/StatsSection.tsx (1)
frontend/db/seed-quiz-types.ts (1)
t(42-48)
🔇 Additional comments (17)
frontend/messages/en.json (1)
135-142: Testimonials use numeric string keys — this is intentional and works well withnext-intl.Using
"0","1", etc. as keys allows dynamic access viat(\testimonials.${index}`)` in components. This is a valid pattern for array-like translation data.frontend/messages/uk.json (1)
56-144: LGTM!The Ukrainian translation structure correctly mirrors the English version with all required keys present. The translations appear natural and appropriate.
frontend/components/blog/BlogCard.tsx (1)
5-18: LGTM!Correct usage of
useTranslationshook at the component level with the'blog'namespace. The'use client'directive is properly in place as required for client-side hooks.frontend/components/shared/Footer.tsx (1)
1-6: LGTM!The
'use client'directive is correctly added to support theuseTranslationshook. The footer namespace is properly initialized for localized strings.frontend/components/about/HeroSection.tsx (1)
6-9: LGTM!Good use of nested namespace
"about.hero"to scope translations. This keeps the component focused on its specific translation keys while maintaining a clean structure.frontend/components/about/StatsSection.tsx (1)
19-33: LGTM on the i18n integration.The
useTranslations("about.stats")hook correctly provides localized labels. The GitHub stars fetch has appropriate error handling with a fallback value.frontend/components/about/CommunitySection.tsx (1)
7-52: Coupling betweentestimonialDatalength and translation keys.The pattern
t(\testimonials.${index}`)works well but creates an implicit contract:testimonialDatahas 6 items, and translation files must have keys"0"through"5"`. If these get out of sync, you'll get missing translation warnings.This is acceptable for a small, stable dataset. Consider adding a comment to document this dependency for future maintainers.
frontend/components/about/PricingSection.tsx (3)
116-117: Good use of separate translation namespaces.Using two
useTranslationshooks with different namespaces (about.pricingandabout.pricing.features) improves readability and keeps translation calls concise. This is a clean pattern for nested translation structures.
141-147: LGTM!Translation integration for the title, highlight, and subtitle follows the correct pattern.
191-209: LGTM!CTA buttons and footer text properly use translation keys. The external "Buy Me a Coffee" link is correctly preserved as a static URL.
frontend/components/about/FeaturesSection.tsx (3)
82-83: Good separation of translation namespaces.Using
tProfilefor the nestedabout.features.profilenamespace keeps the translation calls clean and readable in the profile card content.
105-125: LGTM!Feature cards for Q&A, Quiz, and Profile correctly use translation keys for titles and descriptions.
139-151: LGTM!Profile card content (level, achievements, badges, progress labels) properly uses the
tProfilenamespace for all translated strings.frontend/messages/pl.json (4)
56-61: LGTM!Footer translations are well-structured with clear, concise keys.
62-112: LGTM!The
aboutsection structure (hero, stats, features) is comprehensive and well-organized. The nested structure for profile badges and progress labels matches the component usage patterns.
113-131: LGTM!Pricing section translations are complete with all feature keys matching those used in
PricingSection.tsx.
135-142: No changes needed. The testimonials pattern using numeric string keys ("0", "1", etc.) is intentional and properly implemented. The code inCommunitySection.tsxalready uses indexed access witht(testimonials.${index})to correctly retrieve translations, and this pattern is consistent across all language files (en, pl, uk). The structure pairs structured metadata with indexed translations, which is a valid approach for handling array-like translation content.
Feature/multilingual about
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.