feat: add translations for blog, QA and quiz#126
Conversation
✅ Deploy Preview for develop-devlovers ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
📝 WalkthroughWalkthroughThis pull request adds comprehensive internationalization (i18n) support to quiz functionality by importing translation hooks from next-intl, replacing hardcoded Ukrainian strings with translation keys across 10 frontend files, and introducing new translation strings for quiz, pagination, and related UI elements in three language files. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
frontend/components/quiz/QuizResult.tsx (2)
141-150: Fix incorrect navigation URL for login button.The first button is labeled with
t('loginButton')but navigates to the/signupURL. This creates a confusing user experience where clicking "Login" takes users to the signup page.🔧 Proposed fix
<Button onClick={() => { - const url = `/${locale}/signup?returnTo=/quiz/${quizSlug}`; + const url = `/${locale}/login?returnTo=/quiz/${quizSlug}`; console.log('Navigating to signup:', url); window.location.href = url; }} variant="primary" > {t('loginButton')} </Button>
144-144: Remove debug console.log statement.The console.log on Line 144 appears to be a debug artifact and should be removed before merging to production.
🧹 Proposed fix
onClick={() => { const url = `/${locale}/login?returnTo=/quiz/${quizSlug}`; - console.log('Navigating to signup:', url); window.location.href = url; }}
🧹 Nitpick comments (3)
frontend/messages/en.json (1)
52-153: Tighten a few user-facing English strings before shipping.
Some strings read a bit off (e.g., “Time almost up!”, missing punctuation in a couple result messages). Consider quick copy edits now since these are primary UX strings.Proposed copy tweaks (optional)
- "almostDone": "⚠️ Time almost up!", + "almostDone": "⚠️ Time is almost up!", - "message": "You didn't manage to answer any questions. Try again and manage your time better" + "message": "You didn't manage to answer any questions. Try again and manage your time better."frontend/components/quiz/CountdownTimer.tsx (1)
4-4: Separate emojis from i18n strings for consistent accessibility control.The warning (
⚠️ ) and alarm (⏰) emojis are currently embedded in translated strings. For consistent screen-reader behavior across locales, render them in JSX and applyaria-hidden="true"(since they're decorative):{percentage <= 10 ? ( <> <span aria-hidden="true">⚠️</span> {t('almostDone')} </> ) : ( <> <span aria-hidden="true">⏰</span> {t('hurryUp')} </> )}Keep translated strings text-only so translators aren't responsible for emoji placement or accessibility semantics.
Also applies to: 18-18, 84-84
frontend/components/quiz/QuizCard.tsx (1)
69-69: Consider using next-intl's built-in pluralization.The manual pluralization logic works but doesn't scale well across languages with complex plural rules. next-intl supports ICU message format for robust pluralization.
♻️ Recommended pluralization approach
Update the translation key to use ICU plural format in your message files:
{ "quiz": { "card": { "attemptsCount": "{count, plural, one {# attempt} other {# attempts}}" } } }Then simplify the code:
-{userProgress.attemptsCount} {userProgress.attemptsCount === 1 ? t('attempt') : t('attempts')} +{t('attemptsCount', { count: userProgress.attemptsCount })}This approach:
- Handles complex pluralization rules in languages like Polish (which has 3 plural forms)
- Centralizes pluralization logic in translation files
- Reduces code complexity
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
frontend/app/[locale]/quiz/[slug]/page.tsxfrontend/app/[locale]/quizzes/page.tsxfrontend/components/q&a/Pagination.tsxfrontend/components/quiz/CountdownTimer.tsxfrontend/components/quiz/QuizCard.tsxfrontend/components/quiz/QuizContainer.tsxfrontend/components/quiz/QuizProgress.tsxfrontend/components/quiz/QuizQuestion.tsxfrontend/components/quiz/QuizResult.tsxfrontend/components/quiz/QuizzesSection.tsxfrontend/messages/en.jsonfrontend/messages/pl.jsonfrontend/messages/uk.json
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/components/quiz/QuizCard.tsx (2)
frontend/db/seed-quiz-types.ts (2)
t(42-48)p(37-40)frontend/components/ui/badge.tsx (1)
Badge(36-36)
🔇 Additional comments (20)
frontend/messages/en.json (1)
42-50:qa.paginationstructure +{page}placeholder look correct.
Namespaces match expecteduseTranslations('qa.pagination'), and{page}is consistent with next-intl interpolation.frontend/messages/pl.json (2)
42-50:qa.paginationkeys +{page}placeholder mirror en.json correctly.
This should line up with theqa.paginationnamespace usage in the components.
52-153:quiz.*surface matches en.json; placeholders look consistent.
Good coverage for the components mentioned in the PR summary (page/list/rules/question/progress/timer/result/card/section).frontend/app/[locale]/quiz/[slug]/page.tsx (1)
3-3: Server-sidequiz.pagetranslations correctly wired (keys + namespace match next-intl 4.6.1 API).
All translation keys (noQuestions,questionsLabel,timeLabel,minutes) exist in thequiz.pagenamespace. UsinggetTranslations({ locale, namespace: 'quiz.page' })is the proper API for Next.js App Router server components and enables static rendering.frontend/components/quiz/QuizProgress.tsx (1)
3-3: i18n change is clean and consistent (quiz.progress.label+{current}/{total}).
No behavioral changes beyond swapping the label source. TheuseTranslations('quiz.progress')scoped namespace pattern with placeholder parameters is the recommended approach for Client Components in next-intl 4.6.1 + React 19 / Next.js App Router.frontend/app/[locale]/quizzes/page.tsx (2)
3-3: LGTM! Correct server-side translation usage.The implementation correctly uses
getTranslationsfromnext-intl/serverfor server components, which is the appropriate pattern for Next.js 15 async server components.Also applies to: 12-12
27-27: All translation keys exist in the message files.The translation keys (
title,noQuizzes,practice,subtitle) are correctly defined in thequiz.listnamespace across all locale files (en.json, pl.json, uk.json) and their usage in the component is correct.frontend/components/q&a/Pagination.tsx (2)
3-3: LGTM! Accessibility preserved with translated labels.The i18n implementation correctly maintains all accessibility features by translating
aria-labelattributes. This ensures screen readers will announce pagination controls in the user's language.Also applies to: 17-17, 63-63, 75-77, 119-121
100-100: Translation key format is correct.The interpolated pattern
t('page', { page })properly matches the translation files. All locale files (English, Polish, Ukrainian) infrontend/messages/contain theqa.pagination.pagekey with the correct placeholder:"Page {page}","Strona {page}", and"Сторінка {page}"respectively. No changes needed.frontend/components/quiz/QuizCard.tsx (2)
3-3: LGTM with a recommended improvement for pluralization.The i18n implementation is functional and correctly replaces hardcoded strings across the quiz card. All translation keys are appropriately namespaced under
quiz.card.Also applies to: 25-25, 33-77
33-77: All translation keys in QuizCard.tsx are present and correctly configured in the translation files.frontend/components/quiz/QuizContainer.tsx (3)
3-3: LGTM! Well-structured translation implementation.The translation hook is appropriately named (
tRules) to scope it to the rules section, and the addition ofuseLocale()enables locale-aware navigation. This follows next-intl best practices.Also applies to: 117-117, 128-128
276-276: Verify interpolation parameter name matches message file.The interpolation passes
secondsparameter. Ensure the message file uses the same parameter name, e.g.,"description": "You have {seconds} seconds per question".
234-284: All hierarchical translation keys are correctly structured and present in message files.Verification confirms that all nested keys (
general.title,general.description,forbidden.copyPaste,forbidden.contextMenu,forbidden.tabSwitch,forbidden.externalSources,control.title,control.description,time.title,time.description, andstartButton) exist across all three language files (en.json, pl.json, uk.json). The interpolation format intime.descriptioncorrectly uses{seconds}placeholder, matching the code's usage of{ seconds: totalQuestions * 3 }.frontend/components/quiz/QuizzesSection.tsx (1)
5-5: Implementation follows next-intl best practices for client components.The i18n setup is correct. The
useTranslations('quiz.section')hook initialization is proper, and the translation keynoQuizzesis present in all locale files (en, pl, uk) with appropriate translations for each language.frontend/components/quiz/QuizQuestion.tsx (2)
3-3: LGTM! Clean i18n integration.The translation setup follows next-intl best practices by importing
useTranslationsand creating a scoped translation function for the 'quiz.question' namespace.Also applies to: 27-27
68-68: All translation keys are correctly implemented.All translation keys (
correct,incorrect,explanationLabel,recommendation.title,recommendation.description,loading,nextButton) are properly defined in the Ukrainian translations file and correctly referenced here.Also applies to: 73-73, 88-88, 104-107, 119-119
frontend/messages/uk.json (1)
43-153: LGTM! Comprehensive Ukrainian translations added.The new
qa.paginationandquiztranslation blocks provide complete localization coverage for quiz functionality. The nested structure is well-organized, and parameter templates (e.g.,{page},{count},{points}) follow next-intl conventions correctly.frontend/components/quiz/QuizResult.tsx (2)
3-3: LGTM! Proper i18n setup.The component correctly imports and uses both
useLocaleanduseTranslationshooks from next-intl with the 'quiz.result' namespace.Also applies to: 33-33
38-71: Translation implementation is correct.All translation keys are properly defined in the Ukrainian translations file, and parameter interpolation (
{count},{points}) follows next-intl conventions correctly.Also applies to: 87-87, 112-112, 128-129, 137-137, 149-149, 155-155, 162-162, 165-165
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.