Skip to content

feat: add translations for blog, QA and quiz#126

Merged
ViktorSvertoka merged 1 commit into
developfrom
localize-main-pages
Jan 11, 2026
Merged

feat: add translations for blog, QA and quiz#126
ViktorSvertoka merged 1 commit into
developfrom
localize-main-pages

Conversation

@TiZorii
Copy link
Copy Markdown
Collaborator

@TiZorii TiZorii commented Jan 11, 2026

Summary by CodeRabbit

  • Refactor
    • Restructured quiz and pagination UI components to support multiple languages (English, Polish, Ukrainian).
    • Updated quiz page, quizzes list, pagination controls, countdown timer, quiz cards, quiz rules, progress tracker, questions, results, and related sections with localized text.

✏️ Tip: You can customize this high-level summary in your review settings.

@netlify
Copy link
Copy Markdown

netlify Bot commented Jan 11, 2026

Deploy Preview for develop-devlovers ready!

Name Link
🔨 Latest commit bb166b2
🔍 Latest deploy log https://app.netlify.com/projects/develop-devlovers/deploys/69640d2f38c0230008db540c
😎 Deploy Preview https://deploy-preview-126--develop-devlovers.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 11, 2026

📝 Walkthrough

Walkthrough

This 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

Cohort / File(s) Summary
Quiz Components
frontend/components/quiz/CountdownTimer.tsx, QuizCard.tsx, QuizContainer.tsx, QuizProgress.tsx, QuizQuestion.tsx, QuizResult.tsx, QuizzesSection.tsx
Added useTranslations hook and replaced hardcoded Ukrainian strings with translation keys (e.g., t('label'), t('completed'), t('correct')). Each component now loads translations from its respective namespace (e.g., quiz.timer, quiz.card, quiz.result). Control flow and component logic unchanged.
Pagination Component
frontend/components/q&a/Pagination.tsx
Integrated useTranslations('qa.pagination') and replaced fixed Ukrainian navigation labels with translated keys (t('label'), t('previousPage'), t('nextPage'), etc.). Navigation logic unchanged.
Quiz Pages
frontend/app/[locale]/quiz/[slug]/page.tsx, frontend/app/[locale]/quizzes/page.tsx
Imported getTranslations and replaced static UI strings with translation lookups for page titles, empty state messages, section labels, and metadata.
Translation Message Files
frontend/messages/en.json, frontend/messages/pl.json, frontend/messages/uk.json
Added 112+ lines of new translation entries for quiz and pagination namespaces, including meta titles, UI labels, button text, result messages, and motivational strings across all three languages.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested reviewers

  • AM1007
  • ViktorSvertoka

Poem

🐰 Strings once frozen, now set free,
In many tongues they'll come to be,
Quiz and timer, card and page,
Speak to all in their own stage,
A rabbit hops through languages new,
Making the world translate for you! 🌍

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding internationalization support for blog, QA, and quiz components through translation strings across multiple frontend files and translation files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a 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

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 /signup URL. 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 apply aria-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

📥 Commits

Reviewing files that changed from the base of the PR and between 89c91ab and bb166b2.

📒 Files selected for processing (13)
  • frontend/app/[locale]/quiz/[slug]/page.tsx
  • frontend/app/[locale]/quizzes/page.tsx
  • frontend/components/q&a/Pagination.tsx
  • frontend/components/quiz/CountdownTimer.tsx
  • frontend/components/quiz/QuizCard.tsx
  • frontend/components/quiz/QuizContainer.tsx
  • frontend/components/quiz/QuizProgress.tsx
  • frontend/components/quiz/QuizQuestion.tsx
  • frontend/components/quiz/QuizResult.tsx
  • frontend/components/quiz/QuizzesSection.tsx
  • frontend/messages/en.json
  • frontend/messages/pl.json
  • frontend/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.pagination structure + {page} placeholder look correct.
Namespaces match expected useTranslations('qa.pagination'), and {page} is consistent with next-intl interpolation.

frontend/messages/pl.json (2)

42-50: qa.pagination keys + {page} placeholder mirror en.json correctly.
This should line up with the qa.pagination namespace 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-side quiz.page translations correctly wired (keys + namespace match next-intl 4.6.1 API).
All translation keys (noQuestions, questionsLabel, timeLabel, minutes) exist in the quiz.page namespace. Using getTranslations({ 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. The useTranslations('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 getTranslations from next-intl/server for 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 the quiz.list namespace 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-label attributes. 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) in frontend/messages/ contain the qa.pagination.page key 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 of useLocale() 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 seconds parameter. 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, and startButton) exist across all three language files (en.json, pl.json, uk.json). The interpolation format in time.description correctly 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 key noQuizzes is 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 useTranslations and 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.pagination and quiz translation 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 useLocale and useTranslations hooks 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants