Skip to content

refactor: simplify translation loaders and improve accessibility#23

Open
adipascu wants to merge 1 commit into
mainfrom
improvements/refactor-and-a11y
Open

refactor: simplify translation loaders and improve accessibility#23
adipascu wants to merge 1 commit into
mainfrom
improvements/refactor-and-a11y

Conversation

@adipascu

@adipascu adipascu commented Jul 10, 2026

Copy link
Copy Markdown
Owner

This MR focuses on two main areas: cleaning up technical debt in the translation system and improving the accessibility (a11y) of the user interface.

🛠️ Changes Made

  • src/translation/index.ts: Refactored dynamic import logic.
  • src/Countdown.tsx: Added ARIA roles, labels, and keyboard event listeners to all interactive elements.

Summary by CodeRabbit

  • Accessibility

    • Improved keyboard navigation for copy and settings controls.
    • Added accessible labels and roles to interactive elements.
    • Identified the age counter as a live timer for assistive technologies.
  • Bug Fixes

    • Copy actions can now be triggered using the Enter key.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Countdown interactions now support keyboard and screen-reader accessibility. Translation loading now selects dynamic imports through a typed map keyed by the matched language.

Changes

Countdown accessibility

Layer / File(s) Summary
Accessible Countdown controls
src/Countdown.tsx
Copy controls and the settings control gain keyboard activation and ARIA metadata, while the age counter is marked with role="timer".

Translation loading

Layer / File(s) Summary
Typed translation loader selection
src/translation/index.ts
Language modules are loaded through a typed map of supported language codes to dynamic import functions.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the two main changes: translation loader refactor and accessibility improvements.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch improvements/refactor-and-a11y

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/Countdown.tsx (1)

89-97: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract shared copy control to eliminate duplication.

The copy control div with its accessibility attributes and event handlers is duplicated at lines 89-97 and 132-138. Extracting a shared component would ensure both instances stay in sync — especially important once Space key support is added to both.

Also applies to: 129-138

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Countdown.tsx` around lines 89 - 97, Extract the duplicated copy control
markup into a shared component or render helper near the relevant Countdown
code, preserving the role, tabIndex, aria-label, onClick, and keyboard handlers.
Replace both instances around the AGE display with this shared control, ensuring
future accessibility changes such as Space-key support are implemented in one
place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Countdown.tsx`:
- Around line 89-92: Clean up src/Countdown.tsx by removing trailing whitespace
from the affected JSX lines and replacing single-quoted "Enter" comparisons with
double-quoted strings in the keyboard handlers around copyAgeToClipboard and
related handlers, matching the project lint configuration.
- Around line 89-97: Update the onKeyDown handlers for copyAgeToClipboard and
the settings and second copy controls to support both Enter and Space keys. Call
preventDefault() for handled keys, then invoke the corresponding action so Space
does not scroll the page.

In `@src/translation/index.ts`:
- Line 38: Update the loaders declaration’s Record key type to wrap typeof
SUPPORTED_LANGUAGES in parentheses and apply the formatter-preferred line
breaks, preserving the existing loaders mapping and return type.

---

Nitpick comments:
In `@src/Countdown.tsx`:
- Around line 89-97: Extract the duplicated copy control markup into a shared
component or render helper near the relevant Countdown code, preserving the
role, tabIndex, aria-label, onClick, and keyboard handlers. Replace both
instances around the AGE display with this shared control, ensuring future
accessibility changes such as Space-key support are implemented in one place.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1ba059fb-59bc-48f4-a007-55394342d06a

📥 Commits

Reviewing files that changed from the base of the PR and between 69c87c8 and d244273.

📒 Files selected for processing (2)
  • src/Countdown.tsx
  • src/translation/index.ts

Comment thread src/Countdown.tsx
Comment on lines +89 to +92
<div
onClick={copyAgeToClipboard}
role="button"
tabIndex={0}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix trailing whitespace and quote consistency flagged by linter.

Static analysis reports trailing whitespace on lines 89-92 and 132-133, and single quotes on 'Enter' that should be double quotes (lines 94, 112, 137) per the project's lint configuration.

🧹 Proposed cleanup
-          <div 
-            onClick={copyAgeToClipboard} 
-            role="button" 
-            tabIndex={0} 
+          <div
+            onClick={copyAgeToClipboard}
+            role="button"
+            tabIndex={0}
             aria-label={`Copy ${AGE} to clipboard`}
-            onKeyDown={(e) => e.key === 'Enter' && copyAgeToClipboard()}
+            onKeyDown={(e) => e.key === "Enter" && copyAgeToClipboard()}
           >
-          <div 
-            onClick={copyAgeToClipboard} 
+          <div
+            onClick={copyAgeToClipboard}
             title={COPY_LABEL}
             role="button"
             tabIndex={0}
-            onKeyDown={(e) => e.key === 'Enter' && copyAgeToClipboard()}
+            onKeyDown={(e) => e.key === "Enter" && copyAgeToClipboard()}
-            onKeyDown={(e) => e.key === 'Enter' && openSettings()}
+            onKeyDown={(e) => e.key === "Enter" && openSettings()}

Also applies to: 94-94, 112-112, 132-133, 137-137

🧰 Tools
🪛 GitHub Actions: CI / 3_lint.txt

[warning] 89-89: ESLint (prettier/prettier): Delete ·


[warning] 90-90: ESLint (prettier/prettier): Delete ·


[warning] 91-91: ESLint (prettier/prettier): Delete ·


[warning] 92-92: ESLint (prettier/prettier): Delete ·

🪛 GitHub Actions: CI / lint

[warning] 89-89: ESLint (prettier/prettier): Delete ·.


[warning] 90-90: ESLint (prettier/prettier): Delete ·.


[warning] 91-91: ESLint (prettier/prettier): Delete ·.


[warning] 92-92: ESLint (prettier/prettier): Delete ·.

🪛 GitHub Check: lint

[warning] 92-92:
Delete ·


[warning] 91-91:
Delete ·


[warning] 90-90:
Delete ·


[warning] 89-89:
Delete ·

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Countdown.tsx` around lines 89 - 92, Clean up src/Countdown.tsx by
removing trailing whitespace from the affected JSX lines and replacing
single-quoted "Enter" comparisons with double-quoted strings in the keyboard
handlers around copyAgeToClipboard and related handlers, matching the project
lint configuration.

Source: Linters/SAST tools

Comment thread src/Countdown.tsx
Comment on lines +89 to +97
<div
onClick={copyAgeToClipboard}
role="button"
tabIndex={0}
aria-label={`Copy ${AGE} to clipboard`}
onKeyDown={(e) => e.key === 'Enter' && copyAgeToClipboard()}
>
{AGE}
</div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add Space key support and preventDefault to keyboard handlers.

Elements with role="button" must activate on both Enter and Space per WAI-ARIA. Currently only Enter is handled, so keyboard users who press Space will scroll the page instead of triggering the action. Additionally, e.preventDefault() should be called to suppress the Space key's default scroll behavior.

♿ Proposed fix for keyboard activation
-            onKeyDown={(e) => e.key === 'Enter' && copyAgeToClipboard()}
+            onKeyDown={(e) => {
+              if (e.key === 'Enter' || e.key === ' ') {
+                e.preventDefault();
+                copyAgeToClipboard();
+              }
+            }}

Apply the same pattern to the settings control (line 112) and the second copy control (line 137):

-            onKeyDown={(e) => e.key === 'Enter' && openSettings()}
+            onKeyDown={(e) => {
+              if (e.key === 'Enter' || e.key === ' ') {
+                e.preventDefault();
+                openSettings();
+              }
+            }}

Also applies to: 109-112, 129-138

🧰 Tools
🪛 GitHub Actions: CI / 3_lint.txt

[warning] 89-89: ESLint (prettier/prettier): Delete ·


[warning] 90-90: ESLint (prettier/prettier): Delete ·


[warning] 91-91: ESLint (prettier/prettier): Delete ·


[warning] 92-92: ESLint (prettier/prettier): Delete ·


[warning] 94-94: ESLint (prettier/prettier): Replace 'Enter' with "Enter"

🪛 GitHub Actions: CI / lint

[warning] 89-89: ESLint (prettier/prettier): Delete ·.


[warning] 90-90: ESLint (prettier/prettier): Delete ·.


[warning] 91-91: ESLint (prettier/prettier): Delete ·.


[warning] 92-92: ESLint (prettier/prettier): Delete ·.


[warning] 94-94: ESLint (prettier/prettier): Replace 'Enter' with "Enter".

🪛 GitHub Check: lint

[warning] 94-94:
Replace 'Enter' with "Enter"


[warning] 92-92:
Delete ·


[warning] 91-91:
Delete ·


[warning] 90-90:
Delete ·


[warning] 89-89:
Delete ·

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Countdown.tsx` around lines 89 - 97, Update the onKeyDown handlers for
copyAgeToClipboard and the settings and second copy controls to support both
Enter and Space keys. Call preventDefault() for handled keys, then invoke the
corresponding action so Space does not scroll the page.

Comment thread src/translation/index.ts
assertUnreachable(path);
}

const loaders: Record<typeof SUPPORTED_LANGUAGES[number], () => Promise<any>> = {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix Prettier formatting on the Record type annotation.

The lint check flags this line for missing parentheses around typeof SUPPORTED_LANGUAGES and preferred line breaks. This will fail the format/lint CI check.

🎨 Proposed formatting fix
-const loaders: Record<typeof SUPPORTED_LANGUAGES[number], () => Promise<any>> = {
+const loaders: Record<
+  (typeof SUPPORTED_LANGUAGES)[number],
+  () => Promise<any>
+> = {
   en: () => import("./en"),
📝 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.

Suggested change
const loaders: Record<typeof SUPPORTED_LANGUAGES[number], () => Promise<any>> = {
const loaders: Record<
(typeof SUPPORTED_LANGUAGES)[number],
() => Promise<any>
> = {
🧰 Tools
🪛 GitHub Check: lint

[warning] 38-38:
Replace typeof·SUPPORTED_LANGUAGES[number],·()·=>·Promise<any> with ⏎··(typeof·SUPPORTED_LANGUAGES)[number],⏎··()·=>·Promise<any>⏎

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/translation/index.ts` at line 38, Update the loaders declaration’s Record
key type to wrap typeof SUPPORTED_LANGUAGES in parentheses and apply the
formatter-preferred line breaks, preserving the existing loaders mapping and
return type.

Source: Linters/SAST tools

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.

1 participant