Skip to content

feat(i18n): add Portuguese Brazilian (pt-BR) localization#1957

Open
gustavorodcruz96 wants to merge 4 commits intoAndyMik90:developfrom
gustavorodcruz96:feat/i18n-pt-br
Open

feat(i18n): add Portuguese Brazilian (pt-BR) localization#1957
gustavorodcruz96 wants to merge 4 commits intoAndyMik90:developfrom
gustavorodcruz96:feat/i18n-pt-br

Conversation

@gustavorodcruz96
Copy link

@gustavorodcruz96 gustavorodcruz96 commented Mar 16, 2026

Summary

  • Add complete Brazilian Portuguese (pt-BR) localization with 11 translation files covering all namespaces (common, settings, dialogs, navigation, onboarding, tasks, terminal, errors, welcome, gitlab, taskReview)
  • Migrate 8+ components from hardcoded strings to i18n translation keys (RoadmapTabs, FeatureCard, TerminalGrid, Worktrees, ChangelogList, TaskDetailModal, etc.)
  • Add language-aware AI roadmap generation so AI-generated content respects the user's locale
  • Register pt-BR locale in i18n configuration with proper language metadata

Details

  • 3,874 lines added across 37 files
  • All existing English and French translations remain untouched
  • New translation keys added to English namespace files where components were migrated from hardcoded strings
  • Roadmap AI runner now passes the user's language preference to generate content in the correct language

Test plan

  • Verify app loads correctly with pt-BR selected as language
  • Check all navigation items display translated text without truncation
  • Verify settings page renders all sections in Portuguese
  • Test roadmap generation produces Portuguese content when pt-BR is active
  • Confirm no regressions in English and French locales

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • App-wide Brazilian Portuguese (pt-BR) localization added.
    • Roadmap generation and AI outputs can be produced in the app’s selected language (human-readable content localized; technical identifiers remain English).
  • Chores

    • Extensive internationalization across UI components and locale files (en/fr/pt-BR).
    • App language propagated into agent prompts and generation flows.
    • Minor UI layout tweak: wider settings sidebar.

- Add complete pt-BR translation files for all 11 namespaces
  (common, dialogs, errors, gitlab, navigation, onboarding,
  settings, taskReview, tasks, terminal, welcome)
- Register pt-BR locale in i18n config and resource loader
- Migrate 12 components from hardcoded strings to t() calls
  (Roadmap, Terminal, Changelog, Worktrees, TaskDetail, etc.)
- Add missing English translation keys for newly internationalized strings
- Wire language parameter through roadmap AI generation pipeline
  so AI-generated content respects the user's locale

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@CLAassistant
Copy link

CLAassistant commented Mar 16, 2026

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 16, 2026

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json, !**/package-lock.json

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 668d4a12-654d-40ad-82ae-3ceadce931d5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Threads application language into agent sessions and roadmap generation, injects language instructions into prompt construction, extends types/configs with a language field, and adds pt-BR localization resources while localizing many renderer components.

Changes

Cohort / File(s) Summary
Language infra & resources
apps/desktop/src/main/app-language.ts, apps/desktop/src/shared/constants/i18n.ts, apps/desktop/src/shared/i18n/index.ts, apps/desktop/src/shared/i18n/locales/pt-BR/*, apps/desktop/src/shared/i18n/locales/en/*, apps/desktop/src/shared/i18n/locales/fr/*
Adds getAppLanguage() helper, extends SupportedLanguage with pt-BR, registers pt‑BR resource bundles, and adds/updates many translation keys across en/fr and new pt‑BR locale files.
Agent / Roadmap wiring
apps/desktop/src/main/agent/agent-manager.ts, apps/desktop/src/main/agent/agent-queue.ts, apps/desktop/src/main/agent/types.ts, apps/desktop/src/main/ipc-handlers/roadmap-handlers.ts, apps/desktop/src/main/ai/runners/roadmap.ts
Threads language into session and roadmap configs; adds language to RoadmapConfig and phase signatures; defaults to 'en' and passes language into discovery/features phases and roadmap generator calls.
Worker & prompt changes
apps/desktop/src/main/ai/agent/types.ts, apps/desktop/src/main/ai/agent/worker.ts, apps/desktop/src/main/ai/prompts/prompt-loader.ts, apps/desktop/src/main/ai/prompts/types.ts
Adds optional language to SerializableSessionConfig/PromptContext; assemblePrompt/injectContext include language; prompt-loader conditionally prepends an "OUTPUT LANGUAGE" instruction when language is set and not 'en'.
Renderer i18n updates
apps/desktop/src/renderer/components/...
Roadmap*, Task*, TerminalGrid.tsx, Worktrees.tsx, AddFeatureDialog.tsx, ChangelogList.tsx, SortableFeatureCard.tsx, FeatureCard.tsx, FeatureDetailPanel.tsx, RoadmapTabs.tsx, RoadmapEmptyState.tsx, TaskDetailModal.tsx, TaskHeader.tsx, TaskMetadata.tsx
Replaces hard-coded UI strings with useTranslation lookups across many components, updates namespaces, and localizes labels, badges, messages, dialogs, and terminal/worktree text.
Constants localization
apps/desktop/src/shared/constants/roadmap.ts
Replaces literal English labels with i18n keys for priority, status columns, and status labels.
Spellcheck labels
apps/desktop/src/shared/constants/spellcheck.ts
Adds pt-BR mapping and dictionary label.
i18n JSON additions
apps/desktop/src/shared/i18n/locales/en/*, apps/desktop/src/shared/i18n/locales/fr/*, apps/desktop/src/shared/i18n/locales/pt-BR/*
Adds/extends many translation keys (roadmap, changelog, terminal, tasks, dialogs, settings, navigation, onboarding, gitlab, etc.), including large pt‑BR payloads.
Build config
apps/desktop/electron.vite.config.ts
Adds new externals to electron bundling exclusions.
Minor UI tweak
apps/desktop/src/renderer/components/settings/AppSettings.tsx
Increases sidebar width (styling only).

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant App as Application
    participant IPC as IPC Handler
    participant Agent as Agent Pipeline
    participant Worker as AI Worker
    participant Loader as Prompt Loader
    participant LLM as Language Model

    User->>App: select language (e.g., pt-BR)
    App->>IPC: ROADMAP_GENERATE (calls getAppLanguage() → pt-BR)
    IPC->>Agent: startRoadmap { model, thinkingLevel, language: 'pt-BR' }
    Agent->>Agent: runDiscoveryPhase(..., language='pt-BR')
    Agent->>Worker: assemblePrompt(session { language: 'pt-BR', ... })
    Worker->>Loader: injectContext(context { language: 'pt-BR', ... })
    alt language != 'en'
        Loader->>Loader: prepend "OUTPUT LANGUAGE" instruction (pt-BR)
    end
    Loader->>LLM: send prompt
    LLM-->>Loader: localized response
    Loader-->>Agent: stream/enriched content
    Agent-->>App: roadmap results (localized content)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

area/frontend, size/XL

Poem

🐰 I hopped through strings and prompts today,
Portuguese petals on every display,
Sessions now carry a language note,
Prompts whisper in pt‑BR as they float,
A rabbit cheers — translations all the way!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.10% 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 and concisely describes the main change: adding Brazilian Portuguese localization support to the application.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Tip

CodeRabbit can use your project's `biome` configuration to improve the quality of JS/TS/CSS/JSON code reviews.

Add a configuration file to your project to customize how CodeRabbit runs biome.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

🎉 Thanks for your first PR!

A maintainer will review it soon. Please make sure:

  • Your branch is synced with develop
  • CI checks pass
  • You've followed our contribution guide

Welcome to the Auto Claude community!

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces full support for Brazilian Portuguese (pt-BR) localization, significantly expanding the application's international reach. It involves adding a complete set of translation files for pt-BR and updating various UI components to dynamically fetch text based on the active language. A key enhancement is the integration of language awareness into the AI roadmap generation feature, allowing AI-generated content to be localized according to the user's preference. This change improves user experience for Portuguese-speaking users and lays the groundwork for further internationalization efforts.

Highlights

  • Brazilian Portuguese Localization: Added comprehensive Brazilian Portuguese (pt-BR) translation files across all application namespaces, enabling the UI to be displayed in pt-BR.
  • UI Component Internationalization: Migrated numerous UI components (e.g., RoadmapTabs, FeatureCard, TerminalGrid, Worktrees, ChangelogList, TaskDetailModal) from hardcoded strings to use i18n translation keys, supporting dynamic language display.
  • Language-Aware AI Roadmap Generation: Implemented functionality to pass the user's selected language to the AI roadmap generation process, ensuring AI-generated content respects the user's locale.
  • i18n Configuration Update: Registered the new pt-BR locale within the application's i18n configuration, including its language metadata.
Changelog
  • apps/desktop/src/main/agent/agent-manager.ts
    • Imported getAppLanguage and passed the detected app language to the AgentConfig in two locations.
  • apps/desktop/src/main/agent/agent-queue.ts
    • Passed the language property from the roadmap configuration to the runRoadmapGeneration function.
  • apps/desktop/src/main/agent/types.ts
    • Added an optional language property to the RoadmapConfig interface to specify the language for generated content.
  • apps/desktop/src/main/ai/agent/types.ts
    • Included an optional language property in the SerializableSessionConfig interface for language-aware content generation.
  • apps/desktop/src/main/ai/agent/worker.ts
    • Passed the session's language to the assemblePrompt function to incorporate language context into AI prompts.
  • apps/desktop/src/main/ai/prompts/prompt-loader.ts
    • Implemented logic to inject a language instruction block into AI prompts if a language other than English is specified in the context.
  • apps/desktop/src/main/ai/prompts/types.ts
    • Added an optional language property to the PromptContext interface for specifying the target language of AI-generated content.
  • apps/desktop/src/main/ai/runners/roadmap.ts
    • Modified roadmap generation functions (runDiscoveryPhase, runFeaturesPhase, runRoadmapGeneration) to accept and utilize a language parameter, injecting language-specific instructions into the AI prompts.
  • apps/desktop/src/main/ipc-handlers/roadmap-handlers.ts
    • Imported getAppLanguage and passed the current application language to the RoadmapConfig when generating or refreshing roadmaps.
  • apps/desktop/src/renderer/components/AddFeatureDialog.tsx
    • Updated useTranslation to include the 'common' namespace and translated roadmap priority labels using i18n keys.
  • apps/desktop/src/renderer/components/RoadmapKanbanView.tsx
    • Integrated useTranslation for the 'common' namespace and translated various UI elements such as column labels, empty state messages, and status labels.
  • apps/desktop/src/renderer/components/SortableFeatureCard.tsx
    • Applied i18n translation to roadmap priority, complexity, and impact labels displayed on feature cards.
  • apps/desktop/src/renderer/components/TerminalGrid.tsx
    • Updated useTranslation to include the 'terminal' namespace and translated terminal grid titles, descriptions, button texts, and session counts.
  • apps/desktop/src/renderer/components/Worktrees.tsx
    • Expanded useTranslation to include the 'terminal' namespace and translated worktree titles, descriptions, empty states, and dialog messages.
  • apps/desktop/src/renderer/components/changelog/ChangelogList.tsx
    • Imported useTranslation and translated changelog summary counts, labels, empty states, and action buttons.
  • apps/desktop/src/renderer/components/roadmap/FeatureCard.tsx
    • Translated roadmap priority, complexity, impact, and insight labels on feature cards.
  • apps/desktop/src/renderer/components/roadmap/FeatureDetailPanel.tsx
    • Translated roadmap priority, complexity, and impact labels within the feature detail panel.
  • apps/desktop/src/renderer/components/roadmap/RoadmapEmptyState.tsx
    • Imported useTranslation and translated the roadmap empty state title, description, and generate button text.
  • apps/desktop/src/renderer/components/roadmap/RoadmapTabs.tsx
    • Translated roadmap tab labels, priority labels, feature counts, and action buttons.
  • apps/desktop/src/renderer/components/task-detail/TaskDetailModal.tsx
    • Updated useTranslation to include the 'common' namespace and translated task recovery, resume, start/stop actions, and various status badges.
  • apps/desktop/src/renderer/components/task-detail/TaskHeader.tsx
    • Translated task status labels (stuck, incomplete) and review reasons in the task header.
  • apps/desktop/src/shared/constants/i18n.ts
    • Extended the SupportedLanguage type and AVAILABLE_LANGUAGES array to include 'pt-BR' (Brazilian Portuguese).
  • apps/desktop/src/shared/constants/roadmap.ts
    • Modified roadmap priority and status labels to use i18n keys instead of hardcoded strings.
  • apps/desktop/src/shared/i18n/index.ts
    • Imported and registered all new Brazilian Portuguese (pt-BR) translation files into the i18n configuration.
  • apps/desktop/src/shared/i18n/locales/en/common.json
    • Added new translation keys for roadmap-related texts and changelog messages.
  • apps/desktop/src/shared/i18n/locales/en/terminal.json
    • Introduced new translation keys for the terminal grid UI elements.
  • apps/desktop/src/shared/i18n/locales/pt-BR/common.json
    • Added a new JSON file containing Brazilian Portuguese translations for common application strings.
  • apps/desktop/src/shared/i18n/locales/pt-BR/dialogs.json
    • Added a new JSON file containing Brazilian Portuguese translations for various dialogs.
  • apps/desktop/src/shared/i18n/locales/pt-BR/errors.json
    • Added a new JSON file containing Brazilian Portuguese translations for error messages.
  • apps/desktop/src/shared/i18n/locales/pt-BR/gitlab.json
    • Added a new JSON file containing Brazilian Portuguese translations for GitLab integration.
  • apps/desktop/src/shared/i18n/locales/pt-BR/navigation.json
    • Added a new JSON file containing Brazilian Portuguese translations for navigation elements.
  • apps/desktop/src/shared/i18n/locales/pt-BR/onboarding.json
    • Added a new JSON file containing Brazilian Portuguese translations for onboarding flows.
  • apps/desktop/src/shared/i18n/locales/pt-BR/settings.json
    • Added a new JSON file containing Brazilian Portuguese translations for application settings.
  • apps/desktop/src/shared/i18n/locales/pt-BR/taskReview.json
    • Added a new JSON file containing Brazilian Portuguese translations for task review elements.
  • apps/desktop/src/shared/i18n/locales/pt-BR/tasks.json
    • Added a new JSON file containing Brazilian Portuguese translations for task management.
  • apps/desktop/src/shared/i18n/locales/pt-BR/terminal.json
    • Added a new JSON file containing Brazilian Portuguese translations for terminal-related texts.
  • apps/desktop/src/shared/i18n/locales/pt-BR/welcome.json
    • Added a new JSON file containing Brazilian Portuguese translations for the welcome screen.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces comprehensive Brazilian Portuguese (pt-BR) localization across the application. The changes are well-executed, including the addition of translation files, migrating numerous components from hardcoded strings to i18n keys, and making the AI roadmap generation language-aware. The overall implementation is solid. I've included a couple of suggestions to improve code readability and maintainability.

Comment on lines +248 to +255
sections.push(
`## OUTPUT LANGUAGE\n\n` +
`You MUST write ALL human-readable text content in **${context.language}**. ` +
`This includes: titles, descriptions, rationale, acceptance criteria, user stories, ` +
`phase names, status messages, and any text shown to the user. ` +
`Keep JSON keys, code, file paths, technical identifiers, and enum values in English.\n\n` +
`---\n\n`
);
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

For better readability and maintainability, you could use a single multi-line template literal here instead of concatenating multiple strings with +.

    sections.push(`## OUTPUT LANGUAGE

You MUST write ALL human-readable text content in **${context.language}**. This includes: titles, descriptions, rationale, acceptance criteria, user stories, phase names, status messages, and any text shown to the user. Keep JSON keys, code, file paths, technical identifiers, and enum values in English.

---

`);

Comment on lines 407 to 411
{task.reviewReason === 'completed' ? t('tasks:reviewReason.completed') :
task.reviewReason === 'errors' ? t('tasks:reviewReason.hasErrors') :
task.reviewReason === 'plan_review' ? t('tasks:reviewReason.approvePlan') :
task.reviewReason === 'stopped' ? t('tasks:reviewReason.stopped') : t('tasks:reviewReason.qaIssues')}
</Badge>
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This long ternary chain for translating reviewReason is a bit hard to read and maintain. This pattern is also repeated in TaskHeader.tsx.

Consider refactoring this to use a mapping object or a dynamic key, which would make the code cleaner and more scalable if new reasons are added. For example:

const getReviewReasonTranslation = (reason: string | undefined): string => {
  const keyMap: Record<string, string> = {
    completed: 'completed',
    errors: 'hasErrors',
    plan_review: 'approvePlan',
    stopped: 'stopped',
  };
  const reasonKey = keyMap[reason || ''] || 'qaIssues'; // Default to 'qaIssues'
  return t(`tasks:reviewReason.${reasonKey}`);
};

// Then in your component:
{getReviewReasonTranslation(task.reviewReason)}

Copy link
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: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (16)
apps/desktop/src/renderer/components/task-detail/TaskDetailModal.tsx (2)

417-419: ⚠️ Potential issue | 🟠 Major

Some UI labels are still hardcoded and bypass i18n.

Overview, Subtasks, Logs, the subtasks suffix, and sr-only Close are still plain English strings.

🌐 Suggested patch
-                        <span className="text-xs text-muted-foreground ml-1">
-                          {completedSubtasks}/{totalSubtasks} subtasks
-                        </span>
+                        <span className="text-xs text-muted-foreground ml-1">
+                          {t('tasks:labels.subtasksProgress', { completed: completedSubtasks, total: totalSubtasks })}
+                        </span>
@@
-                      <span className="sr-only">Close</span>
+                      <span className="sr-only">{t('common:buttons.close')}</span>
@@
-                    Overview
+                    {t('tasks:tabs.overview')}
@@
-                    Subtasks ({task.subtasks.length})
+                    {t('tasks:tabs.subtasks', { count: task.subtasks.length })}
@@
-                    Logs
+                    {t('tasks:tabs.logs')}

Based on learnings, "All frontend user-facing text must use react-i18next translation keys. Hardcoded strings in JSX/TSX break localization for non-English users. Add keys to both en/*.json and fr/*.json translation files."

Also applies to: 448-448, 485-497

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/task-detail/TaskDetailModal.tsx` around
lines 417 - 419, Replace hardcoded UI strings in TaskDetailModal (the JSX
rendering "Overview", "Subtasks", "Logs", the subtasks suffix text shown near
{completedSubtasks}/{totalSubtasks}, and the sr-only "Close") with react-i18next
translation keys using the useTranslation hook (t('...')). Update the
corresponding translation files by adding those keys to both en/*.json and
fr/*.json so the labels are localized; ensure keys are descriptive (e.g.,
taskDetail.overview, taskDetail.subtasks, taskDetail.logs,
taskDetail.subtasksSuffix, taskDetail.close) and used consistently in the
component.

99-103: ⚠️ Potential issue | 🟠 Major

Localize remaining error/toast fallback messages in handlers.

User-visible messages are still hardcoded in English (resume failure and several fallback errors). These should use t(...) keys to avoid mixed-language UX.

🌐 Suggested patch
       if (state.isIncomplete) {
         const isValid = await state.reloadPlanForIncompleteTask();
         if (!isValid) {
           toast({
-            title: 'Cannot Resume Task',
-            description: 'Failed to load implementation plan. Please try again or check the task files.',
+            title: t('tasks:notifications.cannotResumeTitle'),
+            description: t('tasks:notifications.cannotResumeDescription'),
             variant: 'destructive',
             duration: 5000,
           });
           return;
         }
       }
@@
-      state.setDeleteError(result.error || 'Failed to delete task');
+      state.setDeleteError(result.error || t('tasks:errors.deleteFailed'));
@@
-        state.setWorkspaceError(result.data?.message || result.error || 'Failed to merge changes');
+        state.setWorkspaceError(result.data?.message || result.error || t('tasks:errors.mergeFailed'));
@@
-      state.setWorkspaceError(error instanceof Error ? error.message : 'Unknown error during merge');
+      state.setWorkspaceError(error instanceof Error ? error.message : t('tasks:errors.mergeUnknown'));
@@
-      state.setWorkspaceError(result.data?.message || result.error || 'Failed to discard changes');
+      state.setWorkspaceError(result.data?.message || result.error || t('tasks:errors.discardFailed'));

As per coding guidelines, "All frontend user-facing text must use react-i18next translation keys. Hardcoded strings in JSX/TSX break localization for non-English users. Add keys to both en/*.json and fr/*.json translation files."

Also applies to: 151-152, 171-175, 188-188

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/task-detail/TaskDetailModal.tsx` around
lines 99 - 103, Replace the hardcoded English toast/error strings in
TaskDetailModal handlers (calls to toast and any fallback error messages inside
the resume/handler functions) with react-i18next translation lookups using the
t(...) function (e.g., t('taskDetail.resumeError.title'),
t('taskDetail.resumeError.description')). Update the corresponding translation
keys in both en/*.json and fr/*.json (add keys such as
taskDetail.resumeError.title, taskDetail.resumeError.description and any others
used for the fallback messages referenced around the toast calls and other
handlers) so all user-facing strings are localized and no plain English literals
remain in TaskDetailModal.
apps/desktop/src/main/ai/runners/roadmap.ts (1)

343-350: ⚠️ Potential issue | 🔴 Critical

Concurrent roadmap writes can clobber each other.

This block uses a PID-only temp filename and no shared lock. Two concurrent writes in the same process can collide on the same .tmp path, and this also bypasses the lock-based writer used by other roadmap update paths.

🔒 Suggested hardening (unique temp file + lock alignment)
+import { randomUUID } from 'node:crypto';
...
-              const tmpFile = `${roadmapFile}.tmp.${process.pid}`;
+              const tmpFile = `${roadmapFile}.tmp.${process.pid}.${randomUUID()}`;
               writeFileSync(tmpFile, merged, 'utf-8');
               renameSync(tmpFile, roadmapFile);

Please also align this write with the same file-lock mechanism used in apps/desktop/src/main/utils/roadmap-utils.ts to avoid cross-path races.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/main/ai/runners/roadmap.ts` around lines 343 - 350, The
atomic write in the preserved-features merge block can collide because tmp
filename uses only process.pid and skips the shared file-lock; update the block
around mergeFeatures/data to (1) obtain the same roadmap file lock used in
apps/desktop/src/main/utils/roadmap-utils.ts (e.g., call the lock helper such as
withRoadmapLock/ acquireRoadmapLock or the equivalent exported function) before
writing, and (2) create a truly unique temp file name for roadmapFile (include a
random suffix or use a secure UUID/crypto random bytes or mkstemp-style temp
name instead of `${process.pid}`) then write and rename while holding the lock;
ensure you reference mergeFeatures and roadmapFile in the change so the
operation remains atomic and consistent with other update paths.
apps/desktop/src/renderer/components/SortableFeatureCard.tsx (1)

105-106: ⚠️ Potential issue | 🟠 Major

Several user-facing strings are still hardcoded in English.

This component is only partially localized; these tooltip/source strings should also move to translation keys.

🌐 Suggested localization pass
-                  <TooltipContent>
-                    Phase: {phaseName}
-                  </TooltipContent>
+                  <TooltipContent>
+                    {t('roadmap.phaseLabel', { phase: phaseName })}
+                  </TooltipContent>
...
-                  <TooltipContent>
-                    This feature addresses competitor pain points
-                  </TooltipContent>
+                  <TooltipContent>
+                    {t('roadmap.competitorInsightTooltip')}
+                  </TooltipContent>
...
-              <TooltipContent>
-                {feature.votes} votes from user feedback
-              </TooltipContent>
+              <TooltipContent>
+                {t('roadmap.votesFromFeedback', { count: feature.votes })}
+              </TooltipContent>
...
-                  {feature.source?.provider === 'canny' ? 'Canny' : 'External'}
+                  {feature.source?.provider === 'canny' ? 'Canny' : t('roadmap.externalSource')}
...
-              <TooltipContent>
-                Imported from {feature.source?.provider}
-              </TooltipContent>
+              <TooltipContent>
+                {t('roadmap.importedFrom', { provider: feature.source?.provider })}
+              </TooltipContent>
As per coding guidelines: “All frontend user-facing text must use `react-i18next` translation keys. Hardcoded strings in JSX/TSX break localization for non-English users. Add keys to both `en/*.json` and `fr/*.json` translation files.”

Also applies to: 120-121, 215-216, 227-227, 231-232

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/SortableFeatureCard.tsx` around lines
105 - 106, The SortableFeatureCard component contains hardcoded user-facing
strings (e.g., "Phase: {phaseName}" and other tooltip/source strings rendered
inside TooltipContent) that must be replaced with react-i18next translation
keys; update the JSX in SortableFeatureCard to use the t('...') hook for each
string (injecting variables like phaseName via interpolation or t('key', {
phaseName })), add corresponding entries to both en/*.json and fr/*.json
translation files for each new key, and ensure you import/use the useTranslation
hook at the top of the component so all tooltips and labels (including the other
strings referenced in the comment) are fully localized.
apps/desktop/src/renderer/components/task-detail/TaskHeader.tsx (1)

71-73: ⚠️ Potential issue | 🟡 Minor

Hardcoded "subtasks" string breaks localization.

The string "subtasks" on line 72 is hardcoded while surrounding labels use t(). This will display English text for non-English users.

🌐 Proposed fix
              <Badge variant="outline" className="text-xs text-orange-400">
-               {taskProgress.completed}/{taskProgress.total} subtasks
+               {t('tasks:labels.subtaskProgress', { completed: taskProgress.completed, total: taskProgress.total })}
              </Badge>

Add the corresponding key to the translation files:

// en/tasks.json
"labels": {
  "subtaskProgress": "{{completed}}/{{total}} subtasks"
}

As per coding guidelines: "All frontend user-facing text must use react-i18next translation keys."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/task-detail/TaskHeader.tsx` around lines
71 - 73, Replace the hardcoded "subtasks" label in TaskHeader.tsx with a
react-i18next translation call: use the t() helper to render the progress text
(e.g., t('labels.subtaskProgress', { completed: taskProgress.completed, total:
taskProgress.total })) inside the Badge where
{taskProgress.completed}/{taskProgress.total} subtasks currently appears, and
add the matching key ("labels.subtaskProgress": "{{completed}}/{{total}}
subtasks") to the translations (e.g., en/tasks.json and other locale files) so
all locales get the localized string.
apps/desktop/src/main/agent/agent-manager.ts (1)

615-639: ⚠️ Potential issue | 🟠 Major

Missing language field in QA process session config.

The startQAProcess method builds a sessionConfig without the language field, while startSpecCreation (line 399) and startTaskExecution (line 524) both include language: getAppLanguage(). This inconsistency means QA-generated content won't respect the user's language preference.

🔧 Proposed fix
    const sessionConfig: SerializableSessionConfig = {
      agentType: 'qa_reviewer',
      systemPrompt,
      initialMessages: qaInitialMessages,
      maxSteps: 1000,
      specDir: effectiveSpecDir,
      projectDir: effectiveProjectDir,
      provider: resolved.provider,
      modelId: resolved.modelId,
      apiKey: resolved.auth?.apiKey,
      baseURL: resolved.auth?.baseURL,
      configDir: resolved.configDir,
      oauthTokenFilePath: resolved.auth?.oauthTokenFilePath,
+     language: getAppLanguage(),
      mcpOptions: {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/main/agent/agent-manager.ts` around lines 615 - 639, The QA
sessionConfig built in startQAProcess is missing the language property so QA
output won't respect user preferences; update the SerializableSessionConfig
object (the sessionConfig inside startQAProcess) to include language:
getAppLanguage() just like startSpecCreation and startTaskExecution do, ensuring
the QA reviewer session uses the app language.
apps/desktop/src/renderer/components/roadmap/FeatureCard.tsx (1)

46-55: ⚠️ Potential issue | 🟡 Minor

Hardcoded "Competitor Insight" strings break localization.

The "Competitor Insight" badge text (line 51) and tooltip content (line 54) are hardcoded while other labels in this component use t().

🌐 Proposed fix
            {hasCompetitorInsight && (
              <Tooltip>
                <TooltipTrigger asChild>
                  <Badge variant="outline" className="text-xs text-primary border-primary/50">
                    <TrendingUp className="h-3 w-3 mr-1" />
-                   Competitor Insight
+                   {t('roadmap.competitorInsight.badge')}
                  </Badge>
                </TooltipTrigger>
-               <TooltipContent>This feature addresses competitor pain points</TooltipContent>
+               <TooltipContent>{t('roadmap.competitorInsight.tooltip')}</TooltipContent>
              </Tooltip>
            )}

As per coding guidelines: "All frontend user-facing text must use react-i18next translation keys."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/roadmap/FeatureCard.tsx` around lines 46
- 55, The "Competitor Insight" badge and tooltip are hardcoded; replace both
occurrences with translation calls using the existing react-i18next t() function
(e.g., t('roadmap.competitorInsight.badge') for the Badge text and
t('roadmap.competitorInsight.tooltip') for TooltipContent) inside the
FeatureCard component where hasCompetitorInsight is used (update Tooltip,
TooltipTrigger/Badge text and TooltipContent); add the corresponding i18n keys
to the translations files. Ensure you use the same t() import already used in
this file.
apps/desktop/src/renderer/components/TerminalGrid.tsx (1)

556-566: ⚠️ Potential issue | 🟡 Minor

Hardcoded "Files" string breaks localization.

The "Files" button text on line 564 is hardcoded while other buttons in this component use t().

🌐 Proposed fix
            {projectPath && (
              <Button
                variant={fileExplorerOpen ? 'default' : 'outline'}
                size="sm"
                className="h-7 text-xs gap-1.5"
                onClick={toggleFileExplorer}
              >
                <FolderTree className="h-3 w-3" />
-               Files
+               {t('common:actions.files')}
              </Button>
            )}

As per coding guidelines: "All frontend user-facing text must use react-i18next translation keys."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/TerminalGrid.tsx` around lines 556 -
566, The "Files" button text is hardcoded; update the JSX to use the i18n
translation function `t()` instead. Locate the Button rendering guarded by
`projectPath` in TerminalGrid (the element with props variant, size, className
and onClick={toggleFileExplorer}) and replace the literal "Files" with a
translated string such as t('terminal.files') (or the appropriate key used
elsewhere). Ensure `t` is imported/available in this component and add the
translation key to your locale files if missing.
apps/desktop/src/renderer/components/roadmap/FeatureDetailPanel.tsx (1)

97-99: ⚠️ Potential issue | 🟠 Major

FeatureDetailPanel still has non-localized user-facing text.

This component still renders many hardcoded English labels/messages (e.g., section headers and delete dialog copy), so users in pt-BR/fr will see mixed-language UI.

As per coding guidelines apps/desktop/src/renderer/**/*.{tsx,jsx}: all frontend user-facing text must use react-i18next translation keys.

Also applies to: 103-107, 118-129, 135-155, 170-173, 187-190, 212-213, 280-291

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/roadmap/FeatureDetailPanel.tsx` around
lines 97 - 99, FeatureDetailPanel renders hardcoded English UI text; import and
use react-i18next's useTranslation in the FeatureDetailPanel component and
replace all user-facing hardcoded strings (e.g., "Description", section headers,
delete dialog title/body, confirm/cancel button labels, and any labels showing
statuses) with translation keys via t('featureDetail.description'),
t('featureDetail.delete.confirmTitle'), t('featureDetail.delete.confirmBody'),
t('common.confirm'), t('common.cancel'), etc.; update the JSX in
FeatureDetailPanel (and any inline dialog functions like the delete dialog
handler or confirmDelete/onDelete callbacks) to call t(...) and pass
interpolations for dynamic values (e.g., feature.title) so all visible text uses
i18n keys and add the corresponding keys to the translation resource files.
apps/desktop/src/renderer/components/changelog/ChangelogList.tsx (1)

173-179: ⚠️ Potential issue | 🟠 Major

Remove hardcoded plural suffix and add missing French translations for changelog badge.

Line 178 appends 's' manually for English pluralization, breaking localization for French and Portuguese. Additionally, the French translation file is missing the entire changelog section containing task, commit, and item keys.

The pattern {getSummaryCount() !== 1 ? 's' : ''} violates the i18n guideline since user-facing text must use react-i18next translation keys for all languages.

Suggested fix
-  const getSummaryLabel = () => {
+  const getSummaryLabelKey = () => {
     switch (sourceMode) {
       case 'tasks':
-        return t('changelog.task');
+        return 'changelog.task';
       case 'git-history':
       case 'branch-diff':
-        return t('changelog.commit');
+        return 'changelog.commit';
       default:
-        return t('changelog.item');
+        return 'changelog.item';
     }
   };
@@
             <Badge variant="secondary" className="ml-2">
-              {getSummaryCount()} {getSummaryLabel()}{getSummaryCount() !== 1 ? 's' : ''}
+              {t(getSummaryLabelKey(), { count: getSummaryCount() })}
             </Badge>

Add the changelog section to apps/desktop/src/shared/i18n/locales/fr/common.json:

"changelog": {
  "task": "tâche",
  "task_plural": "tâches",
  "commit": "commit",
  "commit_plural": "commits",
  "item": "élément",
  "item_plural": "éléments"
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/changelog/ChangelogList.tsx` around
lines 173 - 179, Remove the hardcoded "'s'" plural suffix in the Badge rendering
(referencing getSummaryCount(), getSummaryLabel(), Badge, Button) and instead
use react-i18next pluralization by calling the translation key with the count
(e.g. t('changelog.item', { count: getSummaryCount() })) or update
getSummaryLabel() to return a translated, count-aware label; additionally add
the missing French changelog keys to the French locale common.json so
translations exist: provide "task"/"task_plural", "commit"/"commit_plural", and
"item"/"item_plural" entries as described so getSummaryLabel()/t(...) work for
French.
apps/desktop/src/renderer/components/Worktrees.tsx (6)

465-471: ⚠️ Potential issue | 🟡 Minor

Hardcoded string breaks localization.

This message needs to use a translation key.

🌐 Suggested fix
   if (!selectedProject) {
     return (
       <div className="flex h-full items-center justify-center">
-        <p className="text-muted-foreground">Select a project to view worktrees</p>
+        <p className="text-muted-foreground">{t('dialogs:worktrees.selectProject')}</p>
       </div>
     );
   }

As per coding guidelines: "All frontend user-facing text must use react-i18next translation keys. Hardcoded strings in JSX/TSX break localization for non-English users."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/Worktrees.tsx` around lines 465 - 471,
The hardcoded placeholder text in the Worktrees component (inside the
selectedProject null check) must use react-i18next; replace the literal "Select
a project to view worktrees" with a translation lookup via useTranslation (or t)
and a new translation key (e.g., worktrees.selectProjectMessage), update the
component to import/use the t function and call
t('worktrees.selectProjectMessage') in the JSX, and add the corresponding
key/value to the i18n resource files so localization works.

620-639: ⚠️ Potential issue | 🟡 Minor

Multiple hardcoded strings in stats section.

Several UI strings are not internationalized: "files changed", "commits ahead".

🌐 Suggested fix
                         <div className="flex flex-wrap gap-4 text-sm mb-4">
                           <div className="flex items-center gap-1.5 text-muted-foreground">
                             <FileCode className="h-3.5 w-3.5" />
-                            <span>{worktree.filesChanged ?? 0} files changed</span>
+                            <span>{t('dialogs:worktrees.filesChanged', { count: worktree.filesChanged ?? 0 })}</span>
                           </div>
                           <div className="flex items-center gap-1.5 text-muted-foreground">
                             <ChevronRight className="h-3.5 w-3.5" />
-                            <span>{worktree.commitCount ?? 0} commits ahead</span>
+                            <span>{t('dialogs:worktrees.commitsAhead', { count: worktree.commitCount ?? 0 })}</span>
                           </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/Worktrees.tsx` around lines 620 - 639,
The stats UI in Worktrees.tsx uses hardcoded strings ("files changed", "commits
ahead") inside the CardContent block; replace those literals with i18n
translation calls (e.g., use the project's translation hook/function) and add
corresponding keys for worktree.filesChanged and worktree.commitCount (for
example "worktree.filesChanged" and "worktree.commitsAhead") to the translation
files; update the component to import/use the translator (e.g., useTranslation
or t) and call it where the span text is rendered so the UI strings are
localized consistently.

758-786: ⚠️ Potential issue | 🟡 Minor

Hardcoded strings in terminal worktrees section.

Lines 761, 776, 785 contain hardcoded English text: "Created", "Copy Path", "Delete".

🌐 Suggested fix
                       {wt.createdAt && (
                         <div className="text-xs text-muted-foreground mb-4">
-                          Created {new Date(wt.createdAt).toLocaleDateString()}
+                          {t('dialogs:worktrees.createdAt', { date: new Date(wt.createdAt).toLocaleDateString() })}
                         </div>
                       )}

                       {/* Actions */}
                       <div className="flex flex-wrap gap-2">
                         <Button
                           variant="outline"
                           size="sm"
                           onClick={() => {
                             navigator.clipboard.writeText(wt.worktreePath);
                           }}
                         >
                           <FolderOpen className="h-3.5 w-3.5 mr-1.5" />
-                          Copy Path
+                          {t('dialogs:worktrees.copyPath')}
                         </Button>
                         <Button
                           variant="outline"
                           size="sm"
                           className="text-destructive hover:text-destructive hover:bg-destructive/10"
                           onClick={() => setTerminalWorktreeToDelete(wt)}
                         >
                           <Trash2 className="h-3.5 w-3.5 mr-1.5" />
-                          Delete
+                          {t('common:buttons.delete')}
                         </Button>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/Worktrees.tsx` around lines 758 - 786,
Replace hardcoded English UI strings in the Worktrees component with calls to
the app's i18n/translation utility (e.g., t or translate) so the text can be
localized: change the "Created" label that renders when wt.createdAt is present
to use t('worktrees.created') (or equivalent), replace the Button label "Copy
Path" (the navigator.clipboard.writeText handler) with t('worktrees.copyPath'),
and replace the Delete button label that triggers
setTerminalWorktreeToDelete(wt) with t('worktrees.delete'); ensure you import
the translation hook/function used across the app and update any aria/tooltip
text if present to use the same keys.

650-700: ⚠️ Potential issue | 🟡 Minor

Multiple hardcoded button labels.

Lines 657, 688, 698 contain hardcoded English text: "Merge to {branch}", "Copy Path", "Delete".

🌐 Suggested fix
                         <Button
                           variant="default"
                           size="sm"
                           onClick={() => openMergeDialog(worktree)}
                           disabled={!task}
                         >
                           <GitMerge className="h-3.5 w-3.5 mr-1.5" />
-                          Merge to {worktree.baseBranch}
+                          {t('dialogs:worktrees.mergeTo', { branch: worktree.baseBranch })}
                         </Button>
                         <Button
                           variant="outline"
                           size="sm"
                           onClick={() => {
                             navigator.clipboard.writeText(worktree.path);
                           }}
                         >
                           <FolderOpen className="h-3.5 w-3.5 mr-1.5" />
-                          Copy Path
+                          {t('dialogs:worktrees.copyPath')}
                         </Button>
                         <Button
                           variant="outline"
                           size="sm"
                           className="text-destructive hover:text-destructive hover:bg-destructive/10"
                           onClick={() => confirmDelete(worktree)}
                           disabled={!task && !worktree.isOrphaned}
                         >
                           <Trash2 className="h-3.5 w-3.5 mr-1.5" />
-                          Delete
+                          {t('common:buttons.delete')}
                         </Button>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/Worktrees.tsx` around lines 650 - 700,
Replace the hardcoded English button labels in the Worktrees component with i18n
translations using the existing t(...) function: use a translation key that
accepts interpolation for the merge button (e.g., t('worktrees:mergeTo', {
branch: worktree.baseBranch })) for "Merge to {branch}", and replace "Copy Path"
and "Delete" with t('common:buttons.copyPath') and t('common:buttons.delete')
(or equivalent keys you add); update the translation resource files to include
these keys and ensure callers remain openMergeDialog(worktree) and
confirmDelete(worktree) unchanged.

811-865: ⚠️ Potential issue | 🟡 Minor

Hardcoded strings in merge dialog.

Multiple hardcoded strings in the merge dialog: "Source Branch", "Target Branch", "Changes", "commits", "files", "Merge Successful", "Merge Failed", "Conflicting files:".

🌐 Suggested fix
               <div className="rounded-lg bg-muted p-4 text-sm space-y-3">
                 <div className="flex items-center justify-between">
-                  <span className="text-muted-foreground">Source Branch</span>
+                  <span className="text-muted-foreground">{t('dialogs:worktrees.sourceBranch')}</span>
                   <span className="font-mono text-info">{selectedWorktree.isOrphaned ? t('common:labels.orphaned') : selectedWorktree.branch}</span>
                 </div>
                 <div className="flex items-center justify-center">
                   <ChevronRight className="h-4 w-4 text-muted-foreground rotate-90" />
                 </div>
                 <div className="flex items-center justify-between">
-                  <span className="text-muted-foreground">Target Branch</span>
+                  <span className="text-muted-foreground">{t('dialogs:worktrees.targetBranch')}</span>
                   <span className="font-mono">{selectedWorktree.baseBranch}</span>
                 </div>
                 <div className="border-t border-border pt-3 mt-3">
                   <div className="flex items-center justify-between text-xs">
-                    <span className="text-muted-foreground">Changes</span>
+                    <span className="text-muted-foreground">{t('dialogs:worktrees.changes')}</span>
                     <span>
-                      {selectedWorktree.commitCount ?? 0} commits, {selectedWorktree.filesChanged ?? 0} files
+                      {t('dialogs:worktrees.changesSummary', { commits: selectedWorktree.commitCount ?? 0, files: selectedWorktree.filesChanged ?? 0 })}
                     </span>
                   </div>
                 </div>
               </div>
                   <p className={`font-medium ${mergeResult.success ? 'text-success' : 'text-destructive'}`}>
-                    {mergeResult.success ? 'Merge Successful' : 'Merge Failed'}
+                    {mergeResult.success ? t('dialogs:worktrees.mergeSuccessful') : t('dialogs:worktrees.mergeFailed')}
                   </p>
                   <p className="text-muted-foreground mt-1">{mergeResult.message}</p>
                   {mergeResult.conflictFiles && mergeResult.conflictFiles.length > 0 && (
                     <div className="mt-2">
-                      <p className="text-xs font-medium">Conflicting files:</p>
+                      <p className="text-xs font-medium">{t('dialogs:worktrees.conflictingFiles')}</p>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/Worktrees.tsx` around lines 811 - 865,
The merge dialog contains hardcoded UI strings (e.g., "Source Branch", "Target
Branch", "Changes", "commits", "files", "Merge Successful", "Merge Failed",
"Conflicting files:") inside the Worktrees component around the selectedWorktree
and mergeResult rendering; replace each literal with the i18n translation
function (t) using descriptive keys (e.g., t('worktrees:sourceBranch'),
t('worktrees:targetBranch'), t('worktrees:changes'), t('worktrees:commits'),
t('worktrees:files'), t('worktrees:mergeSuccessful'),
t('worktrees:mergeFailed'), t('worktrees:conflictingFiles')) so strings are
localized, and add those keys to the appropriate locale resource files; ensure
you update the places that render mergeResult.success, mergeResult.message, and
the conflictFiles header to use the translated keys while preserving the
existing structure and classes.

544-555: ⚠️ Potential issue | 🟡 Minor

Hardcoded "Error" label.

The error label on line 550 is hardcoded in English.

🌐 Suggested fix
             <div>
-              <p className="font-medium text-destructive">Error</p>
+              <p className="font-medium text-destructive">{t('common:labels.error')}</p>
               <p className="text-muted-foreground mt-1 whitespace-pre-line">{error}</p>
             </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/Worktrees.tsx` around lines 544 - 555,
The "Error" heading in the Worktrees component is hardcoded; replace the literal
text in the element that renders the label (the <p className="font-medium
text-destructive">Error</p> in
apps/desktop/src/renderer/components/Worktrees.tsx) with a localized string
obtained from your project's i18n mechanism (e.g., call a translation function
like t('error') or useTranslation().t('worktrees.error') and add the
corresponding key to your locale files), and add/update the necessary import(s)
for the translation hook/function so the component compiles.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/desktop/src/renderer/components/roadmap/RoadmapEmptyState.tsx`:
- Around line 2-19: The French locale is missing the translation keys used by
RoadmapEmptyState; add entries for "roadmap.emptyTitle",
"roadmap.emptyDescription", and "roadmap.generateButton" to fr/common.json using
appropriate French strings so useTranslation('common') in RoadmapEmptyState (and
the keys referenced) can resolve; ensure key names exactly match those in
en/common.json and pt-BR/common.json and follow the same JSON structure and
encoding.

In `@apps/desktop/src/renderer/components/SortableFeatureCard.tsx`:
- Around line 196-201: The badge text is ambiguous because it renders only
t(`roadmap.impact.${feature.impact}`); update the Badge content to use the label
template key so it provides context (e.g., use the "label" key under
roadmap.impact with the impact level injected or a dedicated label key like
roadmap.impact.label.<level>), referencing the Badge component,
ROADMAP_IMPACT_COLORS, feature.impact and the t() call in
SortableFeatureCard.tsx to locate the change.

In `@apps/desktop/src/shared/constants/i18n.ts`:
- Around line 6-12: The spellcheck mappings are missing entries for pt-BR; add a
mapping for the SupportedLanguage key 'pt-BR' in both SPELL_CHECK_LANGUAGE_MAP
(map 'pt-BR' to the correct spellchecker locale used by your engine, e.g.,
'pt-BR' or 'pt_BR' consistent with existing keys) and ADD_TO_DICTIONARY_LABELS
(add a Portuguese label such as "Adicionar ao dicionário" for the 'pt-BR' key)
so that when users select pt-BR the spellchecker and "Add to Dictionary" context
menu use Portuguese instead of falling back to en-US; update the objects named
SPELL_CHECK_LANGUAGE_MAP and ADD_TO_DICTIONARY_LABELS accordingly.

In `@apps/desktop/src/shared/i18n/index.ts`:
- Around line 71-84: Update the two spellcheck constants so pt-BR is supported:
in SPELL_CHECK_LANGUAGE_MAP add a "pt-BR" entry mapping to the appropriate
spellchecker codes (e.g. ["pt-BR"] or ["pt-BR","pt-PT"]) and in
ADD_TO_DICTIONARY_LABELS add "pt-BR": "Adicionar ao dicionário"; modify the
constants named SPELL_CHECK_LANGUAGE_MAP and ADD_TO_DICTIONARY_LABELS to include
these entries so Brazilian Portuguese uses the correct spellchecker and
context-menu label.

In `@apps/desktop/src/shared/i18n/locales/en/common.json`:
- Around line 743-744: The key "featuresCount" currently always uses the plural
form ("{{count}} features"), which is incorrect for count=1; update the locale
to supply singular and plural variants by adding a singular base "featuresCount"
(e.g., "{{count}} feature") and a corresponding "featuresCount_plural" (e.g.,
"{{count}} features") so i18n pluralization logic can pick the right form;
ensure you keep the "{{count}}" interpolation token in both strings.

In `@apps/desktop/src/shared/i18n/locales/en/terminal.json`:
- Around line 23-34: Add the missing French translations by adding the entire
"grid" object with these keys to the fr/terminal.json file: title, description,
newTerminal, terminalCount, history, restoreSessionsFrom, sessionCount,
sessionCount_plural, invokeClaudeAll, and clearTask; mirror the structure and
placeholders from the en/terminal.json "grid" object (e.g., "{{count}} / {{max}}
terminals" and pluralization keys) and provide appropriate French strings for
each key so fr/terminal.json matches the new UI entries introduced in
en/terminal.json.

In `@apps/desktop/src/shared/i18n/locales/pt-BR/common.json`:
- Around line 476-477: The pluralization key is inconsistent: change
"messageCount_other" to "messageCount_plural" in the locale object to match the
project's plural suffix convention (e.g., bulkDeleteSuccess_plural,
worktrees.bulkDeleteSuccess_plural); then search for any code referencing
"messageCount_other" and update those references to "messageCount_plural" (or
use i18n.t('messageCount', { count })) so runtime lookups use the unified plural
key.

In `@apps/desktop/src/shared/i18n/locales/pt-BR/terminal.json`:
- Around line 1-70: The French terminal locale is missing the entire "grid"
keyset (grid.title, grid.description, grid.newTerminal, grid.terminalCount,
grid.history, grid.restoreSessionsFrom, grid.sessionCount,
grid.sessionCount_plural, grid.invokeClaudeAll, grid.clearTask); add a "grid"
object to fr/terminal.json mirroring the keys present in pt-BR/terminal.json
(use the same key names and plural forms) and provide appropriate French
translations for each value so the FR locale matches the structure of EN/PT-BR
and avoids missing-key errors when code references grid.*.

---

Outside diff comments:
In `@apps/desktop/src/main/agent/agent-manager.ts`:
- Around line 615-639: The QA sessionConfig built in startQAProcess is missing
the language property so QA output won't respect user preferences; update the
SerializableSessionConfig object (the sessionConfig inside startQAProcess) to
include language: getAppLanguage() just like startSpecCreation and
startTaskExecution do, ensuring the QA reviewer session uses the app language.

In `@apps/desktop/src/main/ai/runners/roadmap.ts`:
- Around line 343-350: The atomic write in the preserved-features merge block
can collide because tmp filename uses only process.pid and skips the shared
file-lock; update the block around mergeFeatures/data to (1) obtain the same
roadmap file lock used in apps/desktop/src/main/utils/roadmap-utils.ts (e.g.,
call the lock helper such as withRoadmapLock/ acquireRoadmapLock or the
equivalent exported function) before writing, and (2) create a truly unique temp
file name for roadmapFile (include a random suffix or use a secure UUID/crypto
random bytes or mkstemp-style temp name instead of `${process.pid}`) then write
and rename while holding the lock; ensure you reference mergeFeatures and
roadmapFile in the change so the operation remains atomic and consistent with
other update paths.

In `@apps/desktop/src/renderer/components/changelog/ChangelogList.tsx`:
- Around line 173-179: Remove the hardcoded "'s'" plural suffix in the Badge
rendering (referencing getSummaryCount(), getSummaryLabel(), Badge, Button) and
instead use react-i18next pluralization by calling the translation key with the
count (e.g. t('changelog.item', { count: getSummaryCount() })) or update
getSummaryLabel() to return a translated, count-aware label; additionally add
the missing French changelog keys to the French locale common.json so
translations exist: provide "task"/"task_plural", "commit"/"commit_plural", and
"item"/"item_plural" entries as described so getSummaryLabel()/t(...) work for
French.

In `@apps/desktop/src/renderer/components/roadmap/FeatureCard.tsx`:
- Around line 46-55: The "Competitor Insight" badge and tooltip are hardcoded;
replace both occurrences with translation calls using the existing react-i18next
t() function (e.g., t('roadmap.competitorInsight.badge') for the Badge text and
t('roadmap.competitorInsight.tooltip') for TooltipContent) inside the
FeatureCard component where hasCompetitorInsight is used (update Tooltip,
TooltipTrigger/Badge text and TooltipContent); add the corresponding i18n keys
to the translations files. Ensure you use the same t() import already used in
this file.

In `@apps/desktop/src/renderer/components/roadmap/FeatureDetailPanel.tsx`:
- Around line 97-99: FeatureDetailPanel renders hardcoded English UI text;
import and use react-i18next's useTranslation in the FeatureDetailPanel
component and replace all user-facing hardcoded strings (e.g., "Description",
section headers, delete dialog title/body, confirm/cancel button labels, and any
labels showing statuses) with translation keys via
t('featureDetail.description'), t('featureDetail.delete.confirmTitle'),
t('featureDetail.delete.confirmBody'), t('common.confirm'), t('common.cancel'),
etc.; update the JSX in FeatureDetailPanel (and any inline dialog functions like
the delete dialog handler or confirmDelete/onDelete callbacks) to call t(...)
and pass interpolations for dynamic values (e.g., feature.title) so all visible
text uses i18n keys and add the corresponding keys to the translation resource
files.

In `@apps/desktop/src/renderer/components/SortableFeatureCard.tsx`:
- Around line 105-106: The SortableFeatureCard component contains hardcoded
user-facing strings (e.g., "Phase: {phaseName}" and other tooltip/source strings
rendered inside TooltipContent) that must be replaced with react-i18next
translation keys; update the JSX in SortableFeatureCard to use the t('...') hook
for each string (injecting variables like phaseName via interpolation or
t('key', { phaseName })), add corresponding entries to both en/*.json and
fr/*.json translation files for each new key, and ensure you import/use the
useTranslation hook at the top of the component so all tooltips and labels
(including the other strings referenced in the comment) are fully localized.

In `@apps/desktop/src/renderer/components/task-detail/TaskDetailModal.tsx`:
- Around line 417-419: Replace hardcoded UI strings in TaskDetailModal (the JSX
rendering "Overview", "Subtasks", "Logs", the subtasks suffix text shown near
{completedSubtasks}/{totalSubtasks}, and the sr-only "Close") with react-i18next
translation keys using the useTranslation hook (t('...')). Update the
corresponding translation files by adding those keys to both en/*.json and
fr/*.json so the labels are localized; ensure keys are descriptive (e.g.,
taskDetail.overview, taskDetail.subtasks, taskDetail.logs,
taskDetail.subtasksSuffix, taskDetail.close) and used consistently in the
component.
- Around line 99-103: Replace the hardcoded English toast/error strings in
TaskDetailModal handlers (calls to toast and any fallback error messages inside
the resume/handler functions) with react-i18next translation lookups using the
t(...) function (e.g., t('taskDetail.resumeError.title'),
t('taskDetail.resumeError.description')). Update the corresponding translation
keys in both en/*.json and fr/*.json (add keys such as
taskDetail.resumeError.title, taskDetail.resumeError.description and any others
used for the fallback messages referenced around the toast calls and other
handlers) so all user-facing strings are localized and no plain English literals
remain in TaskDetailModal.

In `@apps/desktop/src/renderer/components/task-detail/TaskHeader.tsx`:
- Around line 71-73: Replace the hardcoded "subtasks" label in TaskHeader.tsx
with a react-i18next translation call: use the t() helper to render the progress
text (e.g., t('labels.subtaskProgress', { completed: taskProgress.completed,
total: taskProgress.total })) inside the Badge where
{taskProgress.completed}/{taskProgress.total} subtasks currently appears, and
add the matching key ("labels.subtaskProgress": "{{completed}}/{{total}}
subtasks") to the translations (e.g., en/tasks.json and other locale files) so
all locales get the localized string.

In `@apps/desktop/src/renderer/components/TerminalGrid.tsx`:
- Around line 556-566: The "Files" button text is hardcoded; update the JSX to
use the i18n translation function `t()` instead. Locate the Button rendering
guarded by `projectPath` in TerminalGrid (the element with props variant, size,
className and onClick={toggleFileExplorer}) and replace the literal "Files" with
a translated string such as t('terminal.files') (or the appropriate key used
elsewhere). Ensure `t` is imported/available in this component and add the
translation key to your locale files if missing.

In `@apps/desktop/src/renderer/components/Worktrees.tsx`:
- Around line 465-471: The hardcoded placeholder text in the Worktrees component
(inside the selectedProject null check) must use react-i18next; replace the
literal "Select a project to view worktrees" with a translation lookup via
useTranslation (or t) and a new translation key (e.g.,
worktrees.selectProjectMessage), update the component to import/use the t
function and call t('worktrees.selectProjectMessage') in the JSX, and add the
corresponding key/value to the i18n resource files so localization works.
- Around line 620-639: The stats UI in Worktrees.tsx uses hardcoded strings
("files changed", "commits ahead") inside the CardContent block; replace those
literals with i18n translation calls (e.g., use the project's translation
hook/function) and add corresponding keys for worktree.filesChanged and
worktree.commitCount (for example "worktree.filesChanged" and
"worktree.commitsAhead") to the translation files; update the component to
import/use the translator (e.g., useTranslation or t) and call it where the span
text is rendered so the UI strings are localized consistently.
- Around line 758-786: Replace hardcoded English UI strings in the Worktrees
component with calls to the app's i18n/translation utility (e.g., t or
translate) so the text can be localized: change the "Created" label that renders
when wt.createdAt is present to use t('worktrees.created') (or equivalent),
replace the Button label "Copy Path" (the navigator.clipboard.writeText handler)
with t('worktrees.copyPath'), and replace the Delete button label that triggers
setTerminalWorktreeToDelete(wt) with t('worktrees.delete'); ensure you import
the translation hook/function used across the app and update any aria/tooltip
text if present to use the same keys.
- Around line 650-700: Replace the hardcoded English button labels in the
Worktrees component with i18n translations using the existing t(...) function:
use a translation key that accepts interpolation for the merge button (e.g.,
t('worktrees:mergeTo', { branch: worktree.baseBranch })) for "Merge to
{branch}", and replace "Copy Path" and "Delete" with
t('common:buttons.copyPath') and t('common:buttons.delete') (or equivalent keys
you add); update the translation resource files to include these keys and ensure
callers remain openMergeDialog(worktree) and confirmDelete(worktree) unchanged.
- Around line 811-865: The merge dialog contains hardcoded UI strings (e.g.,
"Source Branch", "Target Branch", "Changes", "commits", "files", "Merge
Successful", "Merge Failed", "Conflicting files:") inside the Worktrees
component around the selectedWorktree and mergeResult rendering; replace each
literal with the i18n translation function (t) using descriptive keys (e.g.,
t('worktrees:sourceBranch'), t('worktrees:targetBranch'),
t('worktrees:changes'), t('worktrees:commits'), t('worktrees:files'),
t('worktrees:mergeSuccessful'), t('worktrees:mergeFailed'),
t('worktrees:conflictingFiles')) so strings are localized, and add those keys to
the appropriate locale resource files; ensure you update the places that render
mergeResult.success, mergeResult.message, and the conflictFiles header to use
the translated keys while preserving the existing structure and classes.
- Around line 544-555: The "Error" heading in the Worktrees component is
hardcoded; replace the literal text in the element that renders the label (the
<p className="font-medium text-destructive">Error</p> in
apps/desktop/src/renderer/components/Worktrees.tsx) with a localized string
obtained from your project's i18n mechanism (e.g., call a translation function
like t('error') or useTranslation().t('worktrees.error') and add the
corresponding key to your locale files), and add/update the necessary import(s)
for the translation hook/function so the component compiles.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 84d629f8-5d8f-4ed8-b568-1be317504980

📥 Commits

Reviewing files that changed from the base of the PR and between 3f8e16e and 8d4e637.

📒 Files selected for processing (37)
  • apps/desktop/src/main/agent/agent-manager.ts
  • apps/desktop/src/main/agent/agent-queue.ts
  • apps/desktop/src/main/agent/types.ts
  • apps/desktop/src/main/ai/agent/types.ts
  • apps/desktop/src/main/ai/agent/worker.ts
  • apps/desktop/src/main/ai/prompts/prompt-loader.ts
  • apps/desktop/src/main/ai/prompts/types.ts
  • apps/desktop/src/main/ai/runners/roadmap.ts
  • apps/desktop/src/main/ipc-handlers/roadmap-handlers.ts
  • apps/desktop/src/renderer/components/AddFeatureDialog.tsx
  • apps/desktop/src/renderer/components/RoadmapKanbanView.tsx
  • apps/desktop/src/renderer/components/SortableFeatureCard.tsx
  • apps/desktop/src/renderer/components/TerminalGrid.tsx
  • apps/desktop/src/renderer/components/Worktrees.tsx
  • apps/desktop/src/renderer/components/changelog/ChangelogList.tsx
  • apps/desktop/src/renderer/components/roadmap/FeatureCard.tsx
  • apps/desktop/src/renderer/components/roadmap/FeatureDetailPanel.tsx
  • apps/desktop/src/renderer/components/roadmap/RoadmapEmptyState.tsx
  • apps/desktop/src/renderer/components/roadmap/RoadmapTabs.tsx
  • apps/desktop/src/renderer/components/task-detail/TaskDetailModal.tsx
  • apps/desktop/src/renderer/components/task-detail/TaskHeader.tsx
  • apps/desktop/src/shared/constants/i18n.ts
  • apps/desktop/src/shared/constants/roadmap.ts
  • apps/desktop/src/shared/i18n/index.ts
  • apps/desktop/src/shared/i18n/locales/en/common.json
  • apps/desktop/src/shared/i18n/locales/en/terminal.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/common.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/dialogs.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/errors.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/gitlab.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/navigation.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/onboarding.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/settings.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/taskReview.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/tasks.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/terminal.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/welcome.json

Comment on lines +2 to +19
import { useTranslation } from 'react-i18next';
import { Button } from '../ui/button';
import { Card } from '../ui/card';
import type { RoadmapEmptyStateProps } from './types';

export function RoadmapEmptyState({ onGenerate }: RoadmapEmptyStateProps) {
const { t } = useTranslation('common');
return (
<div className="flex h-full items-center justify-center">
<Card className="w-full max-w-lg p-8 text-center">
<Map className="h-12 w-12 text-muted-foreground mx-auto mb-4" />
<h2 className="text-xl font-semibold mb-2">No Roadmap Yet</h2>
<h2 className="text-xl font-semibold mb-2">{t('roadmap.emptyTitle')}</h2>
<p className="text-muted-foreground mb-6">
Generate an AI-powered roadmap that understands your project's target audience and
creates a strategic feature plan.
{t('roadmap.emptyDescription')}
</p>
<Button onClick={onGenerate} size="lg">
<Sparkles className="h-4 w-4 mr-2" />
Generate Roadmap
{t('roadmap.generateButton')}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify roadmap translation keys exist in all locale files
for locale in en fr pt-BR; do
  echo "=== Checking $locale/common.json ==="
  fd -t f "common.json" "apps/desktop/src/shared/i18n/locales/$locale" --exec cat {} | \
    jq '.roadmap | keys' 2>/dev/null || echo "roadmap key not found or file missing"
done

Repository: AndyMik90/Aperant

Length of output: 1393


French translation keys missing for roadmap component.

The component correctly uses useTranslation('common') and replaces hardcoded strings with translation keys. However, verification shows that the required keys (roadmap.emptyTitle, roadmap.emptyDescription, roadmap.generateButton) are present in en/common.json and pt-BR/common.json but missing from fr/common.json. Add these translations to the French locale file to complete localization support.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/roadmap/RoadmapEmptyState.tsx` around
lines 2 - 19, The French locale is missing the translation keys used by
RoadmapEmptyState; add entries for "roadmap.emptyTitle",
"roadmap.emptyDescription", and "roadmap.generateButton" to fr/common.json using
appropriate French strings so useTranslation('common') in RoadmapEmptyState (and
the keys referenced) can resolve; ensure key names exactly match those in
en/common.json and pt-BR/common.json and follow the same JSON structure and
encoding.

Comment on lines 196 to 201
<Badge
variant="outline"
className={cn('text-[10px] px-1.5 py-0', ROADMAP_IMPACT_COLORS[feature.impact])}
>
{feature.impact}
{t(`roadmap.impact.${feature.impact}`)}
</Badge>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Impact badge lost context and can be confused with complexity.

Rendering only roadmap.impact.<level> makes the badge ambiguous (e.g., two “Low” badges). Use the label template key for clearer output.

🎯 Suggested patch
-            {t(`roadmap.impact.${feature.impact}`)}
+            {t('roadmap.impact.label', { impact: t(`roadmap.impact.${feature.impact}`) })}
📝 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
<Badge
variant="outline"
className={cn('text-[10px] px-1.5 py-0', ROADMAP_IMPACT_COLORS[feature.impact])}
>
{feature.impact}
{t(`roadmap.impact.${feature.impact}`)}
</Badge>
<Badge
variant="outline"
className={cn('text-[10px] px-1.5 py-0', ROADMAP_IMPACT_COLORS[feature.impact])}
>
{t('roadmap.impact.label', { impact: t(`roadmap.impact.${feature.impact}`) })}
</Badge>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/SortableFeatureCard.tsx` around lines
196 - 201, The badge text is ambiguous because it renders only
t(`roadmap.impact.${feature.impact}`); update the Badge content to use the label
template key so it provides context (e.g., use the "label" key under
roadmap.impact with the impact level injected or a dedicated label key like
roadmap.impact.label.<level>), referencing the Badge component,
ROADMAP_IMPACT_COLORS, feature.impact and the t() call in
SortableFeatureCard.tsx to locate the change.

Comment on lines +399 to 402
language: getAppLanguage(),
mcpOptions: {
context7Enabled: true,
memoryEnabled: !!process.env.GRAPHITI_MCP_URL,

This comment was marked as outdated.

Copy link
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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/desktop/src/shared/i18n/locales/en/common.json (1)

691-759: ⚠️ Potential issue | 🟠 Major

Mirror these new common keys into fr/common.json before shipping.

This adds roadmap and changelog UI copy in English, but the French locale only picked up roadmap.featureDetail. The new empty-state strings, status/priority/complexity/impact labels, tabs, kanban text, insight, unknownStatus, and the whole changelog.* block will fall back to English for an already supported locale.

As per coding guidelines "When adding new UI text, add keys to ALL language files in en/*.json and fr/*.json."

Also applies to: 987-1003

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/shared/i18n/locales/en/common.json` around lines 691 - 759,
Add the new English localization keys into the French common file: mirror all
keys added in en/common.json (e.g. "emptyTitle", "emptyDescription",
"generateButton", "showMoreFeatures"/"showMoreFeatures_plural",
"showLessFeatures",
"archiveFeatureConfirmTitle"/"archiveFeatureConfirmDescription", "status"
object, "priority" object, "complexity" object, "featureDetail" entries like
"severityLabel", "impact" object, "tabs", "kanban" object, "insight",
"featuresCount", "unknownStatus", and the entire "changelog.*" block) into
fr/common.json with appropriate French translations (or placeholders if
translation is pending) so the French locale doesn't fall back to English.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/desktop/src/renderer/components/roadmap/FeatureDetailPanel.tsx`:
- Line 53: In the FeatureDetailPanel component, update the drawer container div
(the element with className containing w-[30rem]) to use responsive sizing by
replacing w-[30rem] with w-full max-w-[30rem]; i.e., locate the div in
FeatureDetailPanel.tsx that currently reads className="fixed inset-y-0 right-0
w-[30rem] bg-card border-l border-border shadow-lg flex flex-col z-50" and
change it to className="fixed inset-y-0 right-0 w-full max-w-[30rem] bg-card
border-l border-border shadow-lg flex flex-col z-50".
- Line 212: The severity enum is being passed raw into the translation key,
causing mixed-language output; update FeatureDetailPanel (where
t('roadmap.featureDetail.severityLabel', { severity: insight.severity }) is
used) to first translate the severity via
t('roadmap.featureDetail.severity.{low|medium|high}', { }), then pass that
translated string into the severityLabel interpolation (e.g. severity: t(...));
also add the new keys roadmap.featureDetail.severity.low, .medium, and .high
with correct translations to all locale files (en/common.json, fr/common.json,
pt-BR/common.json).

In `@apps/desktop/src/renderer/components/task-detail/TaskMetadata.tsx`:
- Around line 172-175: The hardcoded English fragments in formatRelativeTime
produce mixed-language timestamps; update formatRelativeTime (in
apps/desktop/src/renderer/lib/utils.ts) to use Intl.RelativeTimeFormat with the
current i18next language (or accept a locale parameter) and return a fully
localized string, then keep TaskMetadata.tsx using t('tasks:metadata.created', {
time: formatRelativeTime(task.createdAt) }); ensure you handle fallbacks for
environments without Intl.RelativeTimeFormat and preserve existing granularity
(seconds/minutes/hours/days).

In `@apps/desktop/src/shared/i18n/locales/pt-BR/common.json`:
- Around line 345-349: The "merged" PR state in the JSON "state" object is still
in English; update the "merged" key value to the Portuguese translation (e.g.,
"Mesclado") so the pt-BR locale shows all PR states translated, and keep the
keys "state", "open", "closed", "merged" intact to preserve usage elsewhere.

In `@apps/desktop/src/shared/i18n/locales/pt-BR/settings.json`:
- Around line 32-39: The settings.json locale file contains partial English in
the "accounts" and "updates" entries; update the "accounts.description" value to
a full Portuguese string (e.g., replace "Claude e API endpoints" with a proper
translation like "Claude e endpoints da API") and translate
"updates.description" from "Updates do app" to full Portuguese (e.g.,
"Atualizações do aplicativo"), then scan the rest of pt-BR locale files for any
remaining English phrases and complete all translations before enabling the
pt-BR locale; target the JSON keys "accounts.title", "accounts.description",
"updates.title", and "updates.description" to make the edits.

---

Outside diff comments:
In `@apps/desktop/src/shared/i18n/locales/en/common.json`:
- Around line 691-759: Add the new English localization keys into the French
common file: mirror all keys added in en/common.json (e.g. "emptyTitle",
"emptyDescription", "generateButton",
"showMoreFeatures"/"showMoreFeatures_plural", "showLessFeatures",
"archiveFeatureConfirmTitle"/"archiveFeatureConfirmDescription", "status"
object, "priority" object, "complexity" object, "featureDetail" entries like
"severityLabel", "impact" object, "tabs", "kanban" object, "insight",
"featuresCount", "unknownStatus", and the entire "changelog.*" block) into
fr/common.json with appropriate French translations (or placeholders if
translation is pending) so the French locale doesn't fall back to English.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 65c3d531-924e-4040-9543-c0c5c24814ba

📥 Commits

Reviewing files that changed from the base of the PR and between 8d4e637 and 83c762f.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json, !**/package-lock.json
📒 Files selected for processing (11)
  • apps/desktop/electron.vite.config.ts
  • apps/desktop/src/renderer/components/roadmap/FeatureDetailPanel.tsx
  • apps/desktop/src/renderer/components/settings/AppSettings.tsx
  • apps/desktop/src/renderer/components/task-detail/TaskMetadata.tsx
  • apps/desktop/src/shared/i18n/locales/en/common.json
  • apps/desktop/src/shared/i18n/locales/en/tasks.json
  • apps/desktop/src/shared/i18n/locales/fr/common.json
  • apps/desktop/src/shared/i18n/locales/fr/tasks.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/common.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/settings.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/tasks.json


return (
<div className="fixed inset-y-0 right-0 w-96 bg-card border-l border-border shadow-lg flex flex-col z-50">
<div className="fixed inset-y-0 right-0 w-[30rem] bg-card border-l border-border shadow-lg flex flex-col z-50">
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Keep the drawer width responsive.

w-[30rem] forces a 480px panel even when the desktop window is narrower, so part of the drawer can end up off-screen. w-full max-w-[30rem] keeps the extra room for localized copy without breaking small windows.

♻️ Proposed fix
-    <div className="fixed inset-y-0 right-0 w-[30rem] bg-card border-l border-border shadow-lg flex flex-col z-50">
+    <div className="fixed inset-y-0 right-0 w-full max-w-[30rem] bg-card border-l border-border shadow-lg flex flex-col z-50">
📝 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
<div className="fixed inset-y-0 right-0 w-[30rem] bg-card border-l border-border shadow-lg flex flex-col z-50">
<div className="fixed inset-y-0 right-0 w-full max-w-[30rem] bg-card border-l border-border shadow-lg flex flex-col z-50">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/roadmap/FeatureDetailPanel.tsx` at line
53, In the FeatureDetailPanel component, update the drawer container div (the
element with className containing w-[30rem]) to use responsive sizing by
replacing w-[30rem] with w-full max-w-[30rem]; i.e., locate the div in
FeatureDetailPanel.tsx that currently reads className="fixed inset-y-0 right-0
w-[30rem] bg-card border-l border-border shadow-lg flex flex-col z-50" and
change it to className="fixed inset-y-0 right-0 w-full max-w-[30rem] bg-card
border-l border-border shadow-lg flex flex-col z-50".

}`}
>
{insight.severity} severity
{t('roadmap.featureDetail.severityLabel', { severity: insight.severity })}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

python - <<'PY'
import json
from pathlib import Path

root = Path("apps/desktop/src/shared/i18n/locales")
for path in sorted(root.glob("*/common.json")):
    data = json.loads(path.read_text(encoding="utf-8"))
    feature_detail = data.get("roadmap", {}).get("featureDetail", {})
    severity = feature_detail.get("severity")
    print(path)
    print("  severityLabel:", feature_detail.get("severityLabel"))
    print("  severity keys:", sorted(severity.keys()) if isinstance(severity, dict) else None)
PY

echo
rg -n -C2 "severityLabel|insight\\.severity" apps/desktop/src/renderer/components/roadmap/FeatureDetailPanel.tsx || true

Repository: AndyMik90/Aperant

Length of output: 1040


Translate the severity value before interpolating it.

insight.severity is the raw enum (high/medium/low), so this badge renders mixed-language text like Severidade high in pt-BR. Add locale keys for the severity values and pass the translated value into severityLabel.

♻️ Proposed fix
-                      {t('roadmap.featureDetail.severityLabel', { severity: insight.severity })}
+                      {t('roadmap.featureDetail.severityLabel', {
+                        severity: t(`roadmap.featureDetail.severity.${insight.severity}`),
+                      })}

Add roadmap.featureDetail.severity.{low,medium,high} keys to all locale files (en/common.json, fr/common.json, pt-BR/common.json) with appropriate translations for each language.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/roadmap/FeatureDetailPanel.tsx` at line
212, The severity enum is being passed raw into the translation key, causing
mixed-language output; update FeatureDetailPanel (where
t('roadmap.featureDetail.severityLabel', { severity: insight.severity }) is
used) to first translate the severity via
t('roadmap.featureDetail.severity.{low|medium|high}', { }), then pass that
translated string into the severityLabel interpolation (e.g. severity: t(...));
also add the new keys roadmap.featureDetail.severity.low, .medium, and .high
with correct translations to all locale files (en/common.json, fr/common.json,
pt-BR/common.json).

Comment on lines +172 to +175
{t('tasks:metadata.created', { time: formatRelativeTime(task.createdAt) })}
</span>
<span className="text-border">•</span>
<span>Updated {formatRelativeTime(task.updatedAt)}</span>
<span>{t('tasks:metadata.updated', { time: formatRelativeTime(task.updatedAt) })}</span>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Definition(s) and call sites:"
rg -n -C4 -g '*.ts' -g '*.tsx' 'formatRelativeTime' apps/desktop/src

echo
echo "Potential hardcoded relative-time fragments:"
rg -n -C2 -g '*.ts' -g '*.tsx' '"Just now"|"m ago"|"h ago"|"d ago"' apps/desktop/src

Repository: AndyMik90/Aperant

Length of output: 6670


🏁 Script executed:

cat -n apps/desktop/src/renderer/lib/utils.ts | sed -n '23,60p'

Repository: AndyMik90/Aperant

Length of output: 1739


Move relative time formatting into i18n or use locale-aware Intl.RelativeTimeFormat.

The formatRelativeTime() function in apps/desktop/src/renderer/lib/utils.ts (lines 34–37) hardcodes English fragments ('just now', 'm ago', 'h ago', 'd ago') regardless of the active language. This causes mixed-language timestamps in the UI—for example, a French user will see "Créé 2m ago" (French translation key + English time fragment).

Options:

  1. Refactor formatRelativeTime() to use Intl.RelativeTimeFormat with the current i18next language
  2. Move relative time formatting into the i18n translation keys (e.g., tasks:metadata.created could handle the "2m ago" → "il y a 2m" conversion)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/task-detail/TaskMetadata.tsx` around
lines 172 - 175, The hardcoded English fragments in formatRelativeTime produce
mixed-language timestamps; update formatRelativeTime (in
apps/desktop/src/renderer/lib/utils.ts) to use Intl.RelativeTimeFormat with the
current i18next language (or accept a locale parameter) and return a fully
localized string, then keep TaskMetadata.tsx using t('tasks:metadata.created', {
time: formatRelativeTime(task.createdAt) }); ensure you handle fallbacks for
environments without Intl.RelativeTimeFormat and preserve existing granularity
(seconds/minutes/hours/days).

Comment on lines +345 to +349
"state": {
"open": "Aberto",
"closed": "Fechado",
"merged": "Merged"
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Localize the merged PR state too.

open and closed are translated, but merged is still English. That leaves the PR state badge mixed-language in the pt-BR UI.

♻️ Proposed fix
       "open": "Aberto",
       "closed": "Fechado",
-      "merged": "Merged"
+      "merged": "Mesclado"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/shared/i18n/locales/pt-BR/common.json` around lines 345 -
349, The "merged" PR state in the JSON "state" object is still in English;
update the "merged" key value to the Portuguese translation (e.g., "Mesclado")
so the pt-BR locale shows all PR states translated, and keep the keys "state",
"open", "closed", "merged" intact to preserve usage elsewhere.

Comment on lines +32 to +39
"accounts": {
"title": "Contas",
"description": "Claude e API endpoints"
},
"updates": {
"title": "Atualizações",
"description": "Updates do app"
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Finish the remaining pt-BR copy pass before enabling this locale.

The first settings screen still mixes English into the Portuguese UI (API endpoints, Updates do app), so users will immediately get a partial translation experience.

📝 Example fix
     "accounts": {
       "title": "Contas",
-      "description": "Claude e API endpoints"
+      "description": "Claude e endpoints de API"
     },
     "updates": {
       "title": "Atualizações",
-      "description": "Updates do app"
+      "description": "Atualizações do app"
     },

Based on learnings "Before adding a new language to AVAILABLE_LANGUAGES, ensure UI translations exist and are complete in apps/frontend/src/shared/i18n/locales. Do not advertise official support for a language until its locale files are fully translated and validated, to avoid user-facing issues."

📝 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
"accounts": {
"title": "Contas",
"description": "Claude e API endpoints"
},
"updates": {
"title": "Atualizações",
"description": "Updates do app"
},
"accounts": {
"title": "Contas",
"description": "Claude e endpoints de API"
},
"updates": {
"title": "Atualizações",
"description": "Atualizações do app"
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/shared/i18n/locales/pt-BR/settings.json` around lines 32 -
39, The settings.json locale file contains partial English in the "accounts" and
"updates" entries; update the "accounts.description" value to a full Portuguese
string (e.g., replace "Claude e API endpoints" with a proper translation like
"Claude e endpoints da API") and translate "updates.description" from "Updates
do app" to full Portuguese (e.g., "Atualizações do aplicativo"), then scan the
rest of pt-BR locale files for any remaining English phrases and complete all
translations before enabling the pt-BR locale; target the JSON keys
"accounts.title", "accounts.description", "updates.title", and
"updates.description" to make the edits.

…ded strings, fix race condition, add missing locale keys
Copy link
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: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/desktop/src/renderer/components/TerminalGrid.tsx (1)

653-657: ⚠️ Potential issue | 🟡 Minor

Hardcoded fallback string breaks localization.

The 'Terminal' fallback on line 656 is a user-facing string that should use a translation key to maintain localization for non-English users.

Proposed fix
          {draggingTerminal && (
            <div className="flex items-center gap-2 bg-card border border-primary rounded-md px-3 py-2 shadow-lg">
              <TerminalSquare className="h-4 w-4 text-primary" />
-              <span className="text-sm font-medium">{draggingTerminal.title || 'Terminal'}</span>
+              <span className="text-sm font-medium">{draggingTerminal.title || t('terminal:grid.newTerminal')}</span>
            </div>
          )}

As per coding guidelines: "All frontend user-facing text must use react-i18next translation keys. Hardcoded strings in JSX/TSX break localization for non-English users."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/TerminalGrid.tsx` around lines 653 -
657, The hardcoded fallback 'Terminal' breaks localization; replace it with a
react-i18next translation key by using the useTranslation hook's t function and
feeding t('terminal.fallback') (or your existing key like t('terminal.label'))
instead of the literal string in the JSX where draggingTerminal.title is used;
ensure the component (TerminalGrid / the function rendering the dragging
preview) imports and calls const { t } = useTranslation() and that the chosen
translation key is added to your i18n resource files.
apps/desktop/src/renderer/components/task-detail/TaskDetailModal.tsx (1)

164-164: ⚠️ Potential issue | 🟡 Minor

Hardcoded fallback string breaks localization.

The fallback message 'Changes staged in main project' bypasses i18n. This should use a translation key for consistency with the rest of the component.

🌐 Proposed fix
-          state.setStagedSuccess(result.data.message || 'Changes staged in main project');
+          state.setStagedSuccess(result.data.message || t('tasks:notifications.changesStaged'));

Ensure the key tasks:notifications.changesStaged is added to all locale files (en/tasks.json, fr/tasks.json, pt-BR/tasks.json).

Based on learnings: "All frontend user-facing text must use react-i18next translation keys. Hardcoded strings in JSX/TSX break localization for non-English users."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/task-detail/TaskDetailModal.tsx` at line
164, Replace the hardcoded fallback string in the state.setStagedSuccess call
with a react-i18next translation key (use
t('tasks:notifications.changesStaged')) so the message is localized; update the
useTranslation usage in this component if needed to ensure t is available, and
add the key tasks:notifications.changesStaged to all locale files
(en/tasks.json, fr/tasks.json, pt-BR/tasks.json) with appropriate translations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/desktop/src/main/ai/runners/roadmap.ts`:
- Around line 129-132: Duplicate multilingual instruction strings
(languageInstruction used in the discovery phase and the similar features-phase
text) should be extracted into a single helper function to avoid duplication and
ease maintenance; add a function (e.g., buildLanguageInstruction(language:
string | undefined, enumExamples: string): string) that returns '' for
undefined/'en' and otherwise composes the LANGUAGE block with the provided
enumExamples, then replace the inline constructions used to set
languageInstruction and the features-phase equivalent with calls to
buildLanguageInstruction (pass the appropriate enumExamples for discovery vs
features) so callers like the discovery contextBlock and the features context
block reuse the single helper.

In `@apps/desktop/src/renderer/components/SortableFeatureCard.tsx`:
- Line 227: The hardcoded provider label in SortableFeatureCard.tsx bypasses
i18n; replace the conditional that currently renders {feature.source?.provider
=== 'canny' ? 'Canny' : t('roadmap.externalSource')} with a translation lookup
(e.g., use t('roadmap.providers.canny') when feature.source?.provider ===
'canny') and fallback to t('roadmap.externalSource') for others, and add the
corresponding "roadmap.providers.canny" key to the locale files so the provider
name is localized consistently.

In `@apps/desktop/src/renderer/components/task-detail/TaskDetailModal.tsx`:
- Around line 407-416: Extract the inline reviewReasonKeyMap inside
TaskDetailModal to a module-level constant named REVIEW_REASON_KEY_MAP (place it
near the top of the file after imports), keep the same key/value pairs
(completed, errors -> hasErrors, plan_review -> approvePlan, stopped ->
stopped), and then update the JSX where reviewReasonKeyMap is referenced to use
REVIEW_REASON_KEY_MAP and preserve the existing logic that resolves reasonKey
with REVIEW_REASON_KEY_MAP[task.reviewReason || ''] || 'qaIssues' before passing
to t(`tasks:reviewReason.${reasonKey}`).

In `@apps/desktop/src/shared/i18n/locales/en/dialogs.json`:
- Around line 66-79: Add the 13 missing French translations for the new worktree
UI keys to the fr/dialogs.json file: add entries for "selectProject",
"filesChanged", "commitsAhead", "mergeTo", "copyPath", "createdAt",
"sourceBranch", "targetBranch", "changes", "changesSummary", "mergeSuccessful",
"mergeFailed", and "conflictingFiles" with appropriate French strings (e.g.,
"Select a project to view worktrees" -> "Sélectionnez un projet pour afficher
les worktrees", "filesChanged" -> "{{count}} fichiers modifiés", "commitsAhead"
-> "{{count}} commits d'avance", "mergeTo" -> "Fusionner vers {{branch}}",
"copyPath" -> "Copier le chemin", "createdAt" -> "Créé le {{date}}",
"sourceBranch" -> "Branche source", "targetBranch" -> "Branche cible", "changes"
-> "Modifications", "changesSummary" -> "{{commits}} commits, {{files}}
fichiers", "mergeSuccessful" -> "Fusion réussie", "mergeFailed" -> "Échec de la
fusion", "conflictingFiles" -> "Fichiers en conflit :"), ensure keys match
exactly the English identifiers and the JSON stays valid (comma placement,
escaping).

In `@apps/desktop/src/shared/i18n/locales/en/tasks.json`:
- Around line 35-37: Remove the duplicate translation key by deleting the unused
"subtasksProgress" entry and keep only "subtaskProgress" (or vice-versa if you
prefer) in both locales so there's a single canonical key; also verify
TaskHeader.tsx references the retained key (subtaskProgress) and update the fr
locale to mirror the same change to keep translations in sync.

In `@apps/desktop/src/shared/i18n/locales/fr/tasks.json`:
- Around line 35-37: Duplicate translation keys subtaskProgress and
subtasksProgress both map to the same French string; TaskHeader.tsx only uses
subtaskProgress, so remove the unused key or confirm both are required. Locate
the keys subtaskProgress and subtasksProgress in the locales/fr/tasks.json and
delete subtasksProgress (or rename/merge if another component needs it), then
run a quick search for subtasksProgress usage across the codebase to ensure no
other component depends on it and update any references to use subtaskProgress
if necessary.

In `@apps/desktop/src/shared/i18n/locales/pt-BR/tasks.json`:
- Around line 36-38: The two i18n keys "subtasksProgress" and "subtaskProgress"
contain identical Portuguese values and likely represent a duplicate or naming
mistake; inspect usages of subtasksProgress and subtaskProgress across the
codebase (components and react-i18next calls) to determine which one is actually
referenced, then either remove the unused key or consolidate them into a single
key and update callers accordingly; if pluralization is intended, follow
react-i18next conventions (use a single base key with plural/_plural or add
count usage) and rename keys to a clear, distinct name to reflect singular vs
plural contexts.

---

Outside diff comments:
In `@apps/desktop/src/renderer/components/task-detail/TaskDetailModal.tsx`:
- Line 164: Replace the hardcoded fallback string in the state.setStagedSuccess
call with a react-i18next translation key (use
t('tasks:notifications.changesStaged')) so the message is localized; update the
useTranslation usage in this component if needed to ensure t is available, and
add the key tasks:notifications.changesStaged to all locale files
(en/tasks.json, fr/tasks.json, pt-BR/tasks.json) with appropriate translations.

In `@apps/desktop/src/renderer/components/TerminalGrid.tsx`:
- Around line 653-657: The hardcoded fallback 'Terminal' breaks localization;
replace it with a react-i18next translation key by using the useTranslation
hook's t function and feeding t('terminal.fallback') (or your existing key like
t('terminal.label')) instead of the literal string in the JSX where
draggingTerminal.title is used; ensure the component (TerminalGrid / the
function rendering the dragging preview) imports and calls const { t } =
useTranslation() and that the chosen translation key is added to your i18n
resource files.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0a159722-4995-42a9-8598-57af25ca04f5

📥 Commits

Reviewing files that changed from the base of the PR and between 83c762f and b104447.

📒 Files selected for processing (20)
  • apps/desktop/src/main/agent/agent-manager.ts
  • apps/desktop/src/main/ai/prompts/prompt-loader.ts
  • apps/desktop/src/main/ai/runners/roadmap.ts
  • apps/desktop/src/renderer/components/SortableFeatureCard.tsx
  • apps/desktop/src/renderer/components/TerminalGrid.tsx
  • apps/desktop/src/renderer/components/Worktrees.tsx
  • apps/desktop/src/renderer/components/changelog/ChangelogList.tsx
  • apps/desktop/src/renderer/components/roadmap/FeatureCard.tsx
  • apps/desktop/src/renderer/components/task-detail/TaskDetailModal.tsx
  • apps/desktop/src/renderer/components/task-detail/TaskHeader.tsx
  • apps/desktop/src/shared/constants/spellcheck.ts
  • apps/desktop/src/shared/i18n/locales/en/common.json
  • apps/desktop/src/shared/i18n/locales/en/dialogs.json
  • apps/desktop/src/shared/i18n/locales/en/tasks.json
  • apps/desktop/src/shared/i18n/locales/fr/common.json
  • apps/desktop/src/shared/i18n/locales/fr/tasks.json
  • apps/desktop/src/shared/i18n/locales/fr/terminal.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/common.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/dialogs.json
  • apps/desktop/src/shared/i18n/locales/pt-BR/tasks.json

Comment on lines +129 to +132
const languageInstruction = language && language !== 'en'
? `\n\n**LANGUAGE**: You MUST write ALL human-readable text content in ${language}. This includes: project descriptions, pain points, goals, vision statements, value propositions, success metrics, feature names, known gaps, differentiators, market position, and constraints. Keep JSON keys, technical terms (framework names, language names), and file paths in English.`
: '';
const contextBlock = `\n\n---\n\n## CONTEXT (injected by runner)\n\n**Project Directory**: ${projectDir}\n**Project Index**: ${projectIndexFile}\n**Output Directory**: ${outputDir}\n**Output File**: ${discoveryFile}\n\nUse the paths above when reading input files and writing output.${languageInstruction}`;
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider extracting duplicated language instruction string.

The language instruction text is nearly identical between discovery and features phases. While the enum value lists differ slightly, the core pattern is duplicated. Consider extracting to a helper function for maintainability.

♻️ Suggested refactor
function buildLanguageInstruction(language: string | undefined, enumExamples: string): string {
  if (!language || language === 'en') return '';
  return `\n\n**LANGUAGE**: You MUST write ALL human-readable text content in ${language}. This includes: ${enumExamples}. Keep JSON keys, technical terms (framework names, language names), file paths, and enum values in English.`;
}

// Usage in discovery:
const languageInstruction = buildLanguageInstruction(
  language,
  'project descriptions, pain points, goals, vision statements, value propositions, success metrics, feature names, known gaps, differentiators, market position, and constraints'
);

// Usage in features:
const featuresLanguageInstruction = buildLanguageInstruction(
  language,
  'feature titles, descriptions, rationales, acceptance criteria, user stories, phase names, phase descriptions, milestone titles, milestone descriptions, vision statement, and audience descriptions'
);

Also applies to: 265-268

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/main/ai/runners/roadmap.ts` around lines 129 - 132,
Duplicate multilingual instruction strings (languageInstruction used in the
discovery phase and the similar features-phase text) should be extracted into a
single helper function to avoid duplication and ease maintenance; add a function
(e.g., buildLanguageInstruction(language: string | undefined, enumExamples:
string): string) that returns '' for undefined/'en' and otherwise composes the
LANGUAGE block with the provided enumExamples, then replace the inline
constructions used to set languageInstruction and the features-phase equivalent
with calls to buildLanguageInstruction (pass the appropriate enumExamples for
discovery vs features) so callers like the discovery contextBlock and the
features context block reuse the single helper.

className="text-[10px] px-1.5 py-0 text-orange-500 border-orange-500/30"
>
{feature.source?.provider === 'canny' ? 'Canny' : 'External'}
{feature.source?.provider === 'canny' ? 'Canny' : t('roadmap.externalSource')}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Hardcoded brand name 'Canny' bypasses localization.

While 'Canny' is a proper noun (company name), the conditional logic shows inconsistent treatment—other external sources use t('roadmap.externalSource') but Canny gets a hardcoded string. Consider using a translation key like t('roadmap.providers.canny') for consistency, even if the value is the same across locales.

♻️ Suggested fix
-                  {feature.source?.provider === 'canny' ? 'Canny' : t('roadmap.externalSource')}
+                  {t(`roadmap.providers.${feature.source?.provider}`, { defaultValue: t('roadmap.externalSource') })}

Then add to locale files:

"roadmap": {
  "providers": {
    "canny": "Canny"
  }
}

As per coding guidelines: "All frontend user-facing text must use react-i18next translation keys."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/SortableFeatureCard.tsx` at line 227,
The hardcoded provider label in SortableFeatureCard.tsx bypasses i18n; replace
the conditional that currently renders {feature.source?.provider === 'canny' ?
'Canny' : t('roadmap.externalSource')} with a translation lookup (e.g., use
t('roadmap.providers.canny') when feature.source?.provider === 'canny') and
fallback to t('roadmap.externalSource') for others, and add the corresponding
"roadmap.providers.canny" key to the locale files so the provider name is
localized consistently.

Comment on lines +407 to +416
{(() => {
const reviewReasonKeyMap: Record<string, string> = {
completed: 'completed',
errors: 'hasErrors',
plan_review: 'approvePlan',
stopped: 'stopped',
};
const reasonKey = reviewReasonKeyMap[task.reviewReason || ''] || 'qaIssues';
return t(`tasks:reviewReason.${reasonKey}`);
})()}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Extract reviewReasonKeyMap as a module-level constant.

The mapping object is recreated on every render inside the JSX. Moving it outside the component improves readability and avoids unnecessary allocations.

♻️ Proposed refactor

Add near the top of the file (after imports):

const REVIEW_REASON_KEY_MAP: Record<string, string> = {
  completed: 'completed',
  errors: 'hasErrors',
  plan_review: 'approvePlan',
  stopped: 'stopped',
};

Then simplify the JSX:

-                              {(() => {
-                              const reviewReasonKeyMap: Record<string, string> = {
-                                completed: 'completed',
-                                errors: 'hasErrors',
-                                plan_review: 'approvePlan',
-                                stopped: 'stopped',
-                              };
-                              const reasonKey = reviewReasonKeyMap[task.reviewReason || ''] || 'qaIssues';
-                              return t(`tasks:reviewReason.${reasonKey}`);
-                            })()}
+                              {t(`tasks:reviewReason.${REVIEW_REASON_KEY_MAP[task.reviewReason || ''] || 'qaIssues'}`)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/task-detail/TaskDetailModal.tsx` around
lines 407 - 416, Extract the inline reviewReasonKeyMap inside TaskDetailModal to
a module-level constant named REVIEW_REASON_KEY_MAP (place it near the top of
the file after imports), keep the same key/value pairs (completed, errors ->
hasErrors, plan_review -> approvePlan, stopped -> stopped), and then update the
JSX where reviewReasonKeyMap is referenced to use REVIEW_REASON_KEY_MAP and
preserve the existing logic that resolves reasonKey with
REVIEW_REASON_KEY_MAP[task.reviewReason || ''] || 'qaIssues' before passing to
t(`tasks:reviewReason.${reasonKey}`).

Comment on lines +66 to +79
"deleteSelected": "Delete Selected",
"selectProject": "Select a project to view worktrees",
"filesChanged": "{{count}} files changed",
"commitsAhead": "{{count}} commits ahead",
"mergeTo": "Merge to {{branch}}",
"copyPath": "Copy Path",
"createdAt": "Created {{date}}",
"sourceBranch": "Source Branch",
"targetBranch": "Target Branch",
"changes": "Changes",
"changesSummary": "{{commits}} commits, {{files}} files",
"mergeSuccessful": "Merge Successful",
"mergeFailed": "Merge Failed",
"conflictingFiles": "Conflicting files:"
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check if French dialogs.json has the new worktree keys

echo "=== Checking fr/dialogs.json for new worktree keys ==="
FR_FILE="apps/desktop/src/shared/i18n/locales/fr/dialogs.json"

if [ -f "$FR_FILE" ]; then
  echo "French dialogs.json exists. Checking for keys..."
  for key in "deleteSelected" "selectProject" "filesChanged" "commitsAhead" "mergeTo" "copyPath" "createdAt" "sourceBranch" "targetBranch" "changes" "changesSummary" "mergeSuccessful" "mergeFailed" "conflictingFiles"; do
    if grep -q "\"$key\"" "$FR_FILE"; then
      echo "✓ Found: $key"
    else
      echo "✗ Missing: $key"
    fi
  done
else
  echo "French dialogs.json not found at expected path"
  fd -t f "dialogs.json" apps/desktop/src/shared/i18n/locales
fi

Repository: AndyMik90/Aperant

Length of output: 492


Add missing French translations for new worktree keys.

The following 13 keys were added to en/dialogs.json but are missing from fr/dialogs.json, breaking French localization:

  • selectProject
  • filesChanged
  • commitsAhead
  • mergeTo
  • copyPath
  • createdAt
  • sourceBranch
  • targetBranch
  • changes
  • changesSummary
  • mergeSuccessful
  • mergeFailed
  • conflictingFiles

Add these keys with French translations to apps/desktop/src/shared/i18n/locales/fr/dialogs.json to comply with the requirement that all new UI text must be added to ALL language files.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/shared/i18n/locales/en/dialogs.json` around lines 66 - 79,
Add the 13 missing French translations for the new worktree UI keys to the
fr/dialogs.json file: add entries for "selectProject", "filesChanged",
"commitsAhead", "mergeTo", "copyPath", "createdAt", "sourceBranch",
"targetBranch", "changes", "changesSummary", "mergeSuccessful", "mergeFailed",
and "conflictingFiles" with appropriate French strings (e.g., "Select a project
to view worktrees" -> "Sélectionnez un projet pour afficher les worktrees",
"filesChanged" -> "{{count}} fichiers modifiés", "commitsAhead" -> "{{count}}
commits d'avance", "mergeTo" -> "Fusionner vers {{branch}}", "copyPath" ->
"Copier le chemin", "createdAt" -> "Créé le {{date}}", "sourceBranch" ->
"Branche source", "targetBranch" -> "Branche cible", "changes" ->
"Modifications", "changesSummary" -> "{{commits}} commits, {{files}} fichiers",
"mergeSuccessful" -> "Fusion réussie", "mergeFailed" -> "Échec de la fusion",
"conflictingFiles" -> "Fichiers en conflit :"), ensure keys match exactly the
English identifiers and the JSON stays valid (comma placement, escaping).

Comment on lines +35 to +37
"needsResume": "Needs Resume",
"subtasksProgress": "{{completed}}/{{total}} subtasks",
"subtaskProgress": "{{completed}}/{{total}} subtasks"
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Duplicate translation keys with identical values.

Both subtasksProgress (line 36) and subtaskProgress (line 37) have the same value. The context snippet from TaskHeader.tsx shows only subtaskProgress is used. This duplication exists in both en and fr files.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/shared/i18n/locales/en/tasks.json` around lines 35 - 37,
Remove the duplicate translation key by deleting the unused "subtasksProgress"
entry and keep only "subtaskProgress" (or vice-versa if you prefer) in both
locales so there's a single canonical key; also verify TaskHeader.tsx references
the retained key (subtaskProgress) and update the fr locale to mirror the same
change to keep translations in sync.

Comment on lines +35 to +37
"needsResume": "Reprise requise",
"subtaskProgress": "{{completed}}/{{total}} sous-tâches",
"subtasksProgress": "{{completed}}/{{total}} sous-tâches"
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Duplicate translation keys with identical values.

Both subtaskProgress and subtasksProgress have the same French translation. Based on the relevant code snippet from TaskHeader.tsx (line 72), only subtaskProgress is used. Consider removing the duplicate subtasksProgress key or clarifying if both are needed for different contexts.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/shared/i18n/locales/fr/tasks.json` around lines 35 - 37,
Duplicate translation keys subtaskProgress and subtasksProgress both map to the
same French string; TaskHeader.tsx only uses subtaskProgress, so remove the
unused key or confirm both are required. Locate the keys subtaskProgress and
subtasksProgress in the locales/fr/tasks.json and delete subtasksProgress (or
rename/merge if another component needs it), then run a quick search for
subtasksProgress usage across the codebase to ensure no other component depends
on it and update any references to use subtaskProgress if necessary.

Comment on lines +36 to +38
"subtasksProgress": "{{completed}}/{{total}} subtarefas",
"subtaskProgress": "{{completed}}/{{total}} subtarefas"
},
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Potential duplicate keys: subtasksProgress vs subtaskProgress.

Both keys have the same Portuguese value "{{completed}}/{{total}} subtarefas". Typically, react-i18next uses a base key with _plural suffix for pluralization. Having both may indicate:

  1. A typo (one should be removed), or
  2. Different usage contexts that aren't clear from the naming.

Verify if both are intentional. If only one is needed, remove the duplicate to avoid confusion.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/shared/i18n/locales/pt-BR/tasks.json` around lines 36 - 38,
The two i18n keys "subtasksProgress" and "subtaskProgress" contain identical
Portuguese values and likely represent a duplicate or naming mistake; inspect
usages of subtasksProgress and subtaskProgress across the codebase (components
and react-i18next calls) to determine which one is actually referenced, then
either remove the unused key or consolidate them into a single key and update
callers accordingly; if pluralization is intended, follow react-i18next
conventions (use a single base key with plural/_plural or add count usage) and
rename keys to a clear, distinct name to reflect singular vs plural contexts.

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