Skip to content

Add head titles for each page#7603

Open
danielh-official wants to merge 13 commits intoactualbudget:masterfrom
danielh-official:add-head-titles-for-each-page
Open

Add head titles for each page#7603
danielh-official wants to merge 13 commits intoactualbudget:masterfrom
danielh-official:add-head-titles-for-each-page

Conversation

@danielh-official
Copy link
Copy Markdown

@danielh-official danielh-official commented Apr 23, 2026

Description

It adds unique titles for each page as described in #7588.

The original title in the index.html file (Actual) still remains, and is shown before the page is fully mounted. It also serves as a fallback for newer pages that might be missing titles.

Starting with React 19, title elements are detected and hoisted up to head. Each title is written into the HTML as a title above the default.

For instance, the /budget page has the following:

<title>Budget | Actual</title>
<title>Actual</title>

Why?

This makes it so that a user can bookmark different pages of the app and not have to manually change the bookmark name to have its own title instead of "Actual".

It also makes having multiple browser tabs open for the web app less of a pain because the user can tell at a glance which tab aligns with which page.

Related issue(s)

Relates to #7588

Testing

  1. Checkout this branch and run yarn start at the root.
  2. Create test file if not already existing click on the Test Plan if not navigated to it immediately.
  3. You should see a title in the /budget page: "Budget | Actual"
  4. Go down the list and verify the following is true for each page.
    • /budget = "Budget | Actual"
    • /reports/{dashboard id} = "{dashboard name} — Report Dashboard | Actual"
    • /reports/summary/{summary id} = "{summary name} — Report Summary | Actual"
    • /schedules = "Schedules — Actual"
    • /schedules = "Payees — Actual"
    • /schedules = "Rules — Actual"
    • /schedules = "Tags — Actual"
    • /schedules = "Settings — Actual"
    • /accounts = "All Account Transactions — Actual"
    • /accounts/onbudget = "On Budget Account Transactions — Actual"
    • /accounts/offbudget = "Off Budget Account Transactions — Actual"
    • /accounts/{account id} = "{account name} — Account Transactions — Actual"

Checklist

  • Release notes added (see link above)
  • No obvious regressions in affected areas
  • Self-review has been performed - I understand what each change in the code does and why it is needed

Bundle Stats

Bundle Files count Total bundle size % Changed
desktop-client 34 13.88 MB → 13.89 MB (+4.19 kB) +0.03%
loot-core 1 5.27 MB 0%
api 2 3.89 MB 0%
cli 1 7.91 MB 0%
crdt 1 41.83 kB 0%
View detailed bundle stats

desktop-client

Total

Files count Total bundle size % Changed
34 13.88 MB → 13.89 MB (+4.19 kB) +0.03%
Changeset
File Δ Size
src/components/Title.tsx 🆕 +338 B 0 B → 338 B
src/components/banksync/index.tsx 📈 +302 B (+6.10%) 4.83 kB → 5.13 kB
src/components/schedules/index.tsx 📈 +391 B (+6.01%) 6.35 kB → 6.73 kB
src/components/tags/ManageTags.tsx 📈 +296 B (+3.86%) 7.48 kB → 7.77 kB
src/components/budget/index.tsx 📈 +334 B (+2.83%) 11.54 kB → 11.87 kB
src/components/payees/ManagePayees.tsx 📈 +414 B (+2.67%) 15.15 kB → 15.55 kB
src/components/ManageRules.tsx 📈 +305 B (+2.12%) 14.04 kB → 14.34 kB
src/components/accounts/Account.tsx 📈 +936 B (+2.07%) 44.12 kB → 45.03 kB
src/components/reports/Overview.tsx 📈 +536 B (+1.95%) 26.77 kB → 27.3 kB
src/components/reports/reports/Summary.tsx 📈 +357 B (+1.36%) 25.57 kB → 25.92 kB
src/components/settings/index.tsx 📈 +82 B (+0.74%) 10.87 kB → 10.95 kB
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger

Asset File Size % Changed
static/js/index.js 1.86 MB → 1.87 MB (+2.69 kB) +0.14%
static/js/ReportRouter.js 1.22 MB → 1.22 MB (+893 B) +0.07%
static/js/Value.js 4.94 MB → 4.94 MB (+338 B) +0.01%
static/js/PayeeRuleCountLabel.js 52.52 kB → 52.82 kB (+305 B) +0.57%

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
static/js/BackgroundImage.js 121.09 kB 0%
static/js/FormulaEditor.js 962.55 kB 0%
static/js/ScheduleEditForm.js 145.68 kB 0%
static/js/TransactionEdit.js 186.56 kB 0%
static/js/TransactionList.js 85.81 kB 0%
static/js/ca.js 191.49 kB 0%
static/js/chart-theme.js 796.5 kB 0%
static/js/client.js 451.37 kB 0%
static/js/da.js 104.22 kB 0%
static/js/de.js 173.88 kB 0%
static/js/en-GB.js 8.2 kB 0%
static/js/en.js 176.76 kB 0%
static/js/es.js 181.86 kB 0%
static/js/extends.js 518.66 kB 0%
static/js/fr.js 182.5 kB 0%
static/js/indexeddb-main-thread-worker-e59fee74.js 13.46 kB 0%
static/js/it.js 168.33 kB 0%
static/js/narrow.js 364.31 kB 0%
static/js/nb-NO.js 151.39 kB 0%
static/js/nl.js 108.46 kB 0%
static/js/pl.js 88.14 kB 0%
static/js/pt-BR.js 193.27 kB 0%
static/js/resize-observer.js 18.06 kB 0%
static/js/th.js 178.63 kB 0%
static/js/theme.js 31.67 kB 0%
static/js/uk.js 212.03 kB 0%
static/js/useFormatList.js 8.63 kB 0%
static/js/wide.js 453 B 0%
static/js/workbox-window.prod.es5.js 7.33 kB 0%
static/js/zh-Hans.js 119.73 kB 0%

loot-core

Total

Files count Total bundle size % Changed
1 5.27 MB 0%
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
kcab.worker.JKo6NKKa.js 5.27 MB 0%

api

Total

Files count Total bundle size % Changed
2 3.89 MB 0%
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
index.js 3.89 MB 0%
models.js 0 B 0%

cli

Total

Files count Total bundle size % Changed
1 7.91 MB 0%
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
cli.js 7.91 MB 0%

crdt

Total

Files count Total bundle size % Changed
1 41.83 kB 0%
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
index.js 41.83 kB 0%

@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 23, 2026

Deploy Preview for actualbudget ready!

Name Link
🔨 Latest commit 7757a0e
🔍 Latest deploy log https://app.netlify.com/projects/actualbudget/deploys/69ebd51e7c47b40008d2aed0
😎 Deploy Preview https://deploy-preview-7603.demo.actualbudget.org
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

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

@github-actions
Copy link
Copy Markdown
Contributor

👋 Hello contributor!

We would love to review your PR! Before we can do that, please make sure:

  • ✅ All CI checks pass
  • ✅ The PR is moved from draft to open (if applicable)
  • ✅ The "[WIP]" prefix is removed from the PR title
  • ✅ All CodeRabbit code review comments are resolved (if you disagree with anything - reply to the bot with your reasoning so we can read through it). The bot will eventually approve the PR.

We do this to reduce the TOIL the core contributor team has to go through for each PR and to allow for speedy reviews and merges.

For more information, please see our Contributing Guide.

@danielh-official danielh-official marked this pull request as ready for review April 24, 2026 00:09
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 24, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new exported Title component and inserts it into multiple desktop-client pages to render per-page document titles; one page (Account) includes a small helper to choose localized account titles.

Changes

Cohort / File(s) Summary
New Title Component
packages/desktop-client/src/components/Title.tsx
Adds exported Title({ value }: { value: string }) that renders a <title> element with the provided value followed by `
Direct Title Insertions
packages/desktop-client/src/components/ManageRules.tsx, packages/desktop-client/src/components/banksync/index.tsx, packages/desktop-client/src/components/payees/ManagePayees.tsx, packages/desktop-client/src/components/tags/ManageTags.tsx
Imports and renders Title with a translated static label (e.g., "Rules", "Bank Sync", "Payees", "Tags").
Title with Translation Hook
packages/desktop-client/src/components/budget/index.tsx, packages/desktop-client/src/components/schedules/index.tsx, packages/desktop-client/src/components/settings/index.tsx
Adds useTranslation()/t usage and renders Title(t('...')) for localized page titles (Budget, Schedules, Settings).
Account-specific Title Logic
packages/desktop-client/src/components/accounts/Account.tsx
Adds non-exported getAccountTitle(account, id, t) helper and renders computed localized title (special routes or ${account.name} — Account Transactions) via Title.
Report Pages
packages/desktop-client/src/components/reports/Overview.tsx, packages/desktop-client/src/components/reports/reports/Summary.tsx
Renders Title with composed strings like "{name} — Report Dashboard" and "{title} — Report Summary"; minor import reorder in Overview.
Release Notes
upcoming-release-notes/7603.md
Adds release note documenting that unique titles were added for each page.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hop from page to page in springtime light,
Adding names that sit so calm and right.
Budgets, banks, and tags now call,
Each title placed above them all.
A little rabbit nods—hop, neat sight!

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add head titles for each page' accurately reflects the main change—adding HTML title elements to various pages for improved browser tab identification.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description clearly explains the purpose (adding unique page titles), rationale (better bookmarking and tab management), implementation approach (React 19 title hoisting), and includes testing instructions.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (5)
packages/desktop-client/src/components/Title.tsx (1)

1-3: Minor: simplify the JSX expression.

The template literal is unnecessary — JSX can interpolate value directly with adjacent text.

♻️ Proposed simplification
 export function Title({ value }: { value: string }) {
-  return <title>{`${value} | Actual`}</title>;
+  return <title>{value} | Actual</title>;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/desktop-client/src/components/Title.tsx` around lines 1 - 3, The
Title component uses an unnecessary template literal; simplify JSX by
interpolating the prop directly: update the Title function (export function
Title) to return a title element that uses {value} with the adjacent string
separator instead of `${value} | Actual` (e.g., <title>{value} |
Actual</title>), leaving prop typing ({ value }: { value: string }) unchanged.
upcoming-release-notes/7603.md (1)

6-6: Nit: tighten the release-note wording.

The sentence starts with a dangling pronoun ("It"). Release-note entries typically read as a direct statement of the change.

✏️ Proposed phrasing
-It adds unique titles for each page.
+Add unique page titles so browser tabs and bookmarks show page-specific names.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@upcoming-release-notes/7603.md` at line 6, The release note sentence uses a
dangling pronoun ("It adds unique titles for each page."); change it to a direct
present-tense statement by replacing that sentence with "Adds unique titles for
each page." so the entry reads as a concise change summary in the
upcoming-release-notes/7603.md content.
packages/desktop-client/src/components/payees/ManagePayees.tsx (1)

40-57: Consider rendering Title at the top level of ManagePayees rather than inside PayeeTableHeader.

Other pages in this PR (e.g., ManageRules, ManageTags, Schedules, BankSync, Budget) render Title at the root of the page component. Embedding it inside PayeeTableHeader — a sub-component whose name suggests table-header concerns — couples head-title semantics to a presentational row. Moving it to the top of ManagePayees's returned tree keeps the pattern consistent and makes the title's scope obvious.

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

In `@packages/desktop-client/src/components/payees/ManagePayees.tsx` around lines
40 - 57, The Title component is currently rendered inside the PayeeTableHeader
sub-component which couples page-level semantics to a presentational header;
update ManagePayees so Title (using Title value={t('Payees')}) is moved to the
top-level return of the ManagePayees component (above the
TableHeader/PayeeTableHeader) and remove the embedded Title from
PayeeTableHeader so the table header only contains table-related cells
(SelectCell, Cell) and the page title stays consistent with other pages like
ManageRules/ManageTags.
packages/desktop-client/src/components/settings/index.tsx (1)

15-15: Prefer useTranslation() over module-level import { t } from 'i18next' in React components.

About() is a React component, so t should come from useTranslation() (consistent with AdvancedAbout / Settings in this same file). The module-level t won't subscribe the component to language-change re-renders.

♻️ Proposed fix
-import { t } from 'i18next';
-
 import { getLatestAppVersion } from '#app/appSlice';
 function About() {
+  const { t } = useTranslation();
   const version = useServerVersion();

Based on learnings: "importing t directly from 'i18next' is best avoided, and we should almost always prefer using the useTranslation hook if possible." (qedi-r, PR 3527)

Also applies to: 57-57

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

In `@packages/desktop-client/src/components/settings/index.tsx` at line 15,
Replace the module-level import of t from 'i18next' with the useTranslation hook
inside the About React component so it subscribes to language changes: remove
the top-level "import { t } from 'i18next'" and inside the About function call
const { t } = useTranslation() (matching how AdvancedAbout and Settings do it),
then update any uses of t in About to use that local t; ensure you import
useTranslation from 'react-i18next' if not already present.
packages/desktop-client/src/components/accounts/Account.tsx (1)

2092-2107: Avoid shadowing: two getAccountTitle helpers with different return shapes.

There's now a module-level getAccountTitle (returns "… Account Transactions" / `${account.name} — Account Transactions`) and a class-method AccountInternal.getAccountTitle (returns "On Budget Accounts" / account.name) with intentionally different strings. Same name, different results is an easy foot-gun for future edits. Consider renaming the module-level helper to clarify intent, e.g. getAccountPageTitle (and using it only for the <Title> tag).

Also, this helper calls module-scoped t from i18next; that's fine here since the function is invoked per render, but wrapping it into a small hook or passing t in would be more consistent with the rest of the file.

♻️ Proposed rename
-  const accountTitle = getAccountTitle(account, params.id);
+  const accountTitle = getAccountPageTitle(account, params.id);
@@
-function getAccountTitle(account?: AccountEntity, id?: string) {
+function getAccountPageTitle(account?: AccountEntity, id?: string) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/desktop-client/src/components/accounts/Account.tsx` around lines
2092 - 2107, There's a shadowing issue: the module-level function
getAccountTitle returns page-title-style strings while the class method
AccountInternal.getAccountTitle returns account-name-style strings; rename the
module-level helper to something explicit (e.g., getAccountPageTitle) and update
its call sites (such as the <Title> usage) so only the renamed helper is used
for page/title text, leaving AccountInternal.getAccountTitle unchanged;
additionally, to match file conventions, either accept a t parameter or wrap the
renamed helper in a small hook so it doesn't rely on the module-scoped i18next t
directly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/desktop-client/src/components/accounts/Account.tsx`:
- Around line 2040-2044: getAccountTitle can return null, which when rendered
via the template literal `${accountTitle}` produces the string "null" in the
document title; change the rendering so Title is only rendered when accountTitle
is non-null (or use a safe fallback string) — locate the accountTitle variable
and the Title component usage in this file (around the accountTitle =
getAccountTitle(...) and the Title value={`${accountTitle}`} line) and replace
it with a conditional render or conditional value: if accountTitle is null omit
Title entirely or pass a default like the app's base title.

In `@packages/desktop-client/src/components/budget/index.tsx`:
- Line 13: Replace the direct static import "import { t } from 'i18next'" with
the hook-based API inside the React component: remove the top-level t import and
add "const { t } = useTranslation()" inside the functional component (e.g., in
the component that renders the budget UI), then update any usages of t(...) to
use this hooked t so the component reacts to language changes; ensure you import
useTranslation from 'react-i18next' and remove the unused i18next import.

In `@packages/desktop-client/src/components/reports/Overview.tsx`:
- Around line 738-740: The Title usage is building a dynamic i18n key with
t(`${dashboard.name || 'Untitled'} — Report Dashboard`) which prevents
extracting and translating the static suffix and the 'Untitled' fallback;
replace this with an interpolated translation key (e.g. a key like
"reportDashboard.title") and pass dashboard.name (or a translated fallback from
t('Untitled')) as a variable to t so the static "— Report Dashboard" string and
the fallback are localizable while the dashboard.name remains dynamic; update
the Title call to use t('reportDashboard.title', { name: dashboard.name ||
t('Untitled') }) (and add the corresponding translation entries).

In `@packages/desktop-client/src/components/reports/reports/Summary.tsx`:
- Line 351: The translation key is being built dynamically in the Title
component call (Title and t(`${title} — Report Summary`)), which prevents
extraction of the fixed suffix; change the call to use a stable i18n key and
interpolate the widget title via the t function (e.g. t('reports.summary', {
title })) so the static "— Report Summary" text is translatable while passing
the dynamic title as a variable to be inserted by the localization system.

---

Nitpick comments:
In `@packages/desktop-client/src/components/accounts/Account.tsx`:
- Around line 2092-2107: There's a shadowing issue: the module-level function
getAccountTitle returns page-title-style strings while the class method
AccountInternal.getAccountTitle returns account-name-style strings; rename the
module-level helper to something explicit (e.g., getAccountPageTitle) and update
its call sites (such as the <Title> usage) so only the renamed helper is used
for page/title text, leaving AccountInternal.getAccountTitle unchanged;
additionally, to match file conventions, either accept a t parameter or wrap the
renamed helper in a small hook so it doesn't rely on the module-scoped i18next t
directly.

In `@packages/desktop-client/src/components/payees/ManagePayees.tsx`:
- Around line 40-57: The Title component is currently rendered inside the
PayeeTableHeader sub-component which couples page-level semantics to a
presentational header; update ManagePayees so Title (using Title
value={t('Payees')}) is moved to the top-level return of the ManagePayees
component (above the TableHeader/PayeeTableHeader) and remove the embedded Title
from PayeeTableHeader so the table header only contains table-related cells
(SelectCell, Cell) and the page title stays consistent with other pages like
ManageRules/ManageTags.

In `@packages/desktop-client/src/components/settings/index.tsx`:
- Line 15: Replace the module-level import of t from 'i18next' with the
useTranslation hook inside the About React component so it subscribes to
language changes: remove the top-level "import { t } from 'i18next'" and inside
the About function call const { t } = useTranslation() (matching how
AdvancedAbout and Settings do it), then update any uses of t in About to use
that local t; ensure you import useTranslation from 'react-i18next' if not
already present.

In `@packages/desktop-client/src/components/Title.tsx`:
- Around line 1-3: The Title component uses an unnecessary template literal;
simplify JSX by interpolating the prop directly: update the Title function
(export function Title) to return a title element that uses {value} with the
adjacent string separator instead of `${value} | Actual` (e.g., <title>{value} |
Actual</title>), leaving prop typing ({ value }: { value: string }) unchanged.

In `@upcoming-release-notes/7603.md`:
- Line 6: The release note sentence uses a dangling pronoun ("It adds unique
titles for each page."); change it to a direct present-tense statement by
replacing that sentence with "Adds unique titles for each page." so the entry
reads as a concise change summary in the upcoming-release-notes/7603.md content.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ddbb4112-4da6-44f4-88df-af50fcbc3185

📥 Commits

Reviewing files that changed from the base of the PR and between c8224d2 and 59a3ca9.

📒 Files selected for processing (12)
  • packages/desktop-client/src/components/ManageRules.tsx
  • packages/desktop-client/src/components/Title.tsx
  • packages/desktop-client/src/components/accounts/Account.tsx
  • packages/desktop-client/src/components/banksync/index.tsx
  • packages/desktop-client/src/components/budget/index.tsx
  • packages/desktop-client/src/components/payees/ManagePayees.tsx
  • packages/desktop-client/src/components/reports/Overview.tsx
  • packages/desktop-client/src/components/reports/reports/Summary.tsx
  • packages/desktop-client/src/components/schedules/index.tsx
  • packages/desktop-client/src/components/settings/index.tsx
  • packages/desktop-client/src/components/tags/ManageTags.tsx
  • upcoming-release-notes/7603.md

Comment thread packages/desktop-client/src/components/budget/index.tsx Outdated
Comment thread packages/desktop-client/src/components/reports/Overview.tsx
Comment thread packages/desktop-client/src/components/reports/reports/Summary.tsx Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/desktop-client/src/components/accounts/Account.tsx (1)

2092-2107: Duplicate-but-divergent getAccountTitle implementations; filterName state is ignored for the document title.

There are now two getAccountTitle functions with subtly different semantics:

  • AccountInternal.getAccountTitle (Lines 897-918) reads location.state.filterName and returns short labels like "On Budget Accounts" / "Uncategorized" / account name.
  • The new top-level getAccountTitle (Lines 2092-2107) ignores filterName and returns "… Account Transactions" variants.

Consequences:

  1. When the page is reached via a filterName link (e.g., onShowTransactionst('Selected transactions')), the <h1> shows "Selected transactions" but the browser tab shows the generic account/route title — the document title no longer reflects what the user is actually viewing.
  2. The fallback on Line 2103 (return t('Account Transactions')) is only hit when account is undefined AND id is a truthy non-special value. In that window AccountInternal will redirect to /accounts (Lines 1738-1742), so users briefly see "Account Transactions | Actual" for unknown IDs. Consider returning an empty string (or skipping <Title>) instead to let the default "Actual" title from index.html stand.

Consider consolidating the two helpers (e.g., parameterize the suffix) and threading filterName into the standalone version so the tab title matches the header.

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

In `@packages/desktop-client/src/components/accounts/Account.tsx` around lines
2092 - 2107, There are two mismatched title helpers (getAccountTitle and
AccountInternal.getAccountTitle) causing the document title to ignore
location.state.filterName; to fix, consolidate them by updating the top-level
getAccountTitle to accept an optional filterName parameter (the same values read
from location.state.filterName) and make it return the short labels when
filterName is present (e.g., "On Budget Accounts", "Uncategorized", "Selected
transactions") before falling back to account/name-based strings; also change
the fallback for unknown truthy ids to return an empty string (so the <Title>
can be omitted and the default "Actual" remains) and update callers (including
AccountInternal and wherever <Title> is set) to pass through
location.state.filterName to the unified getAccountTitle.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/desktop-client/src/components/accounts/Account.tsx`:
- Around line 2040-2044: Replace the direct i18next import and usage with
react-i18next's useTranslation inside the Account component: call const { t } =
useTranslation() at the top of the Account function and remove the standalone t
import; update getAccountTitle usage so any hardcoded "Account Transactions"
suffix in getAccountTitle or where accountTitle is composed uses t('Account
Transactions') instead of a literal string (ensure special account types still
use t()), and pass the resulting plain string accountTitle (no template literal
wrapper) into <Title value={accountTitle} /> so the component re-renders on
language changes and the suffix is translated.

---

Nitpick comments:
In `@packages/desktop-client/src/components/accounts/Account.tsx`:
- Around line 2092-2107: There are two mismatched title helpers (getAccountTitle
and AccountInternal.getAccountTitle) causing the document title to ignore
location.state.filterName; to fix, consolidate them by updating the top-level
getAccountTitle to accept an optional filterName parameter (the same values read
from location.state.filterName) and make it return the short labels when
filterName is present (e.g., "On Budget Accounts", "Uncategorized", "Selected
transactions") before falling back to account/name-based strings; also change
the fallback for unknown truthy ids to return an empty string (so the <Title>
can be omitted and the default "Actual" remains) and update callers (including
AccountInternal and wherever <Title> is set) to pass through
location.state.filterName to the unified getAccountTitle.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8cfc0b9b-f37f-4c30-b3c3-33ea7ade8840

📥 Commits

Reviewing files that changed from the base of the PR and between 59a3ca9 and c17bee4.

📒 Files selected for processing (4)
  • packages/desktop-client/src/components/accounts/Account.tsx
  • packages/desktop-client/src/components/budget/index.tsx
  • packages/desktop-client/src/components/reports/Overview.tsx
  • packages/desktop-client/src/components/reports/reports/Summary.tsx
✅ Files skipped from review due to trivial changes (1)
  • packages/desktop-client/src/components/reports/Overview.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/desktop-client/src/components/reports/reports/Summary.tsx

Comment thread packages/desktop-client/src/components/accounts/Account.tsx Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/desktop-client/src/components/accounts/Account.tsx`:
- Around line 2093-2116: Rename the getAccountTitle function's translator
parameter to a required t (i.e., getAccountTitle(account?: AccountEntity, id?:
string, t: (key: string) => string): string), remove the optional identity
fallback so t is mandatory, and update all call sites to pass the i18n function
by destructuring (e.g., const { t } = useTranslation() or props) before calling
getAccountTitle; keep the existing returned keys/strings but ensure all
translate(...) usages inside getAccountTitle are renamed to t(...) so
i18next-parser and the actual/no-untranslated-strings lint rule will detect
them.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c6d1e995-9ecc-4ba1-81a2-c43cbfd27a0b

📥 Commits

Reviewing files that changed from the base of the PR and between c17bee4 and 9dd503e.

📒 Files selected for processing (1)
  • packages/desktop-client/src/components/accounts/Account.tsx

Comment thread packages/desktop-client/src/components/accounts/Account.tsx
coderabbitai[bot]
coderabbitai Bot previously approved these changes Apr 24, 2026
danielh-official and others added 12 commits April 24, 2026 16:34
Replace the direct import of `t` from 'i18next' with the `useTranslation` hook from 'react-i18next' in the Budget component. This moves `const { t } = useTranslation()` into the component so translations update correctly (e.g. on language change) and follow React i18next best practices.
Stop passing the whole interpolated title to t(). Previously t() was called on the combined string, which prevented proper localization of the fallback 'Untitled' and the 'Report Dashboard' label. This change calls t('Untitled') and t('Report Dashboard') separately while interpolating dashboard.name, ensuring correct translations.
Stop passing the full template string to the i18n function. Previously `${title} — Report Summary` was sent to `t()`, causing the dynamic title to be treated as a translation key. This change concatenates the raw `title` with `t('Report Summary')` so only the fixed suffix is translated, preserving the dynamic title and fixing translation lookup/interpolation issues.
Co-authored-by: Copilot <copilot@github.com>
Change getAccountTitle to accept a required translator function parameter named `t` and tighten types for `account` and `id`. Remove the previous internal fallback `translate` implementation and replace all uses of `translate` with `t`. This enforces explicit localization handling and clarifies typings for callers (they must now pass a translation function).
@danielh-official danielh-official force-pushed the add-head-titles-for-each-page branch 2 times, most recently from e16c9b1 to f6c6931 Compare April 24, 2026 20:35
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/desktop-client/src/components/accounts/Account.tsx (1)

2045-2045: Drop the redundant template literal.

accountTitle is already typed as string (return type of getAccountTitle), so the wrapping template literal on Line 2045 is unnecessary.

♻️ Proposed tweak
-      <Title value={`${accountTitle}`} />
+      <Title value={accountTitle} />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/desktop-client/src/components/accounts/Account.tsx` at line 2045,
The Title usage wraps accountTitle in an unnecessary template literal; since
getAccountTitle returns a string, change the prop to pass accountTitle directly
(i.e., use <Title value={accountTitle} />) instead of <Title
value={`${accountTitle}`} />—update the JSX where Title is rendered and ensure
accountTitle comes from getAccountTitle unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/desktop-client/src/components/accounts/Account.tsx`:
- Line 2045: The Title usage wraps accountTitle in an unnecessary template
literal; since getAccountTitle returns a string, change the prop to pass
accountTitle directly (i.e., use <Title value={accountTitle} />) instead of
<Title value={`${accountTitle}`} />—update the JSX where Title is rendered and
ensure accountTitle comes from getAccountTitle unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 506c4bec-ca02-41d3-ba19-24ca371ebb7e

📥 Commits

Reviewing files that changed from the base of the PR and between f3ad0e1 and f6c6931.

📒 Files selected for processing (12)
  • packages/desktop-client/src/components/ManageRules.tsx
  • packages/desktop-client/src/components/Title.tsx
  • packages/desktop-client/src/components/accounts/Account.tsx
  • packages/desktop-client/src/components/banksync/index.tsx
  • packages/desktop-client/src/components/budget/index.tsx
  • packages/desktop-client/src/components/payees/ManagePayees.tsx
  • packages/desktop-client/src/components/reports/Overview.tsx
  • packages/desktop-client/src/components/reports/reports/Summary.tsx
  • packages/desktop-client/src/components/schedules/index.tsx
  • packages/desktop-client/src/components/settings/index.tsx
  • packages/desktop-client/src/components/tags/ManageTags.tsx
  • upcoming-release-notes/7603.md
✅ Files skipped from review due to trivial changes (7)
  • packages/desktop-client/src/components/ManageRules.tsx
  • packages/desktop-client/src/components/banksync/index.tsx
  • packages/desktop-client/src/components/tags/ManageTags.tsx
  • upcoming-release-notes/7603.md
  • packages/desktop-client/src/components/Title.tsx
  • packages/desktop-client/src/components/payees/ManagePayees.tsx
  • packages/desktop-client/src/components/settings/index.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/desktop-client/src/components/reports/Overview.tsx
  • packages/desktop-client/src/components/schedules/index.tsx

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant