Skip to content

web-next: Replace AppSidebar with responsive Navigation#194

Closed
yihyunjoon wants to merge 11 commits intohackers-pub:mainfrom
yihyunjoon:navigation
Closed

web-next: Replace AppSidebar with responsive Navigation#194
yihyunjoon wants to merge 11 commits intohackers-pub:mainfrom
yihyunjoon:navigation

Conversation

@yihyunjoon
Copy link
Contributor

@yihyunjoon yihyunjoon commented Jan 24, 2026

Summary

  • Replace AppSidebar and FloatingComposeButton with a unified Navigation component
  • Add mobile bottom navigation bar with key nav items and compose button
  • Add responsive breakpoints: icon-only sidebar at sm, full sidebar with labels at lg
  • Extract Footer into a standalone component
  • Add left padding to nav list at lg for better visual alignment

Screenshots

Screenshot 2026-01-24 at 4 41 57 PM Screenshot 2026-01-24 at 4 41 47 PM Screenshot 2026-01-24 at 4 41 29 PM
sm (640px) md (768px) lg (1024px)

Summary by CodeRabbit

  • New Features

    • Added a new responsive navigation bar and a footer with Code of Conduct and project links.
  • Refactor

    • Removed the legacy sidebar and floating compose button; restructured app layout and root content rendering for updated UX.
  • Localization

    • Updated translations for English, Japanese, Korean, Simplified Chinese, and Traditional Chinese to reflect navigation/footer changes.

Replace FloatingComposeButton with a full Navigation component that
provides iOS-style tab bar navigation for mobile users. The navigation
includes Feed, Notifications, Create, Search, and Profile tabs with
the user's avatar displayed for the profile link.
Remove AppSidebar component and enhance Navigation to serve as
the primary navigation. Navigation now displays as a bottom bar
on mobile and a sticky left sidebar on sm+ screens with logo.
- lg: 200px width with text labels next to icons
- Dark/light mode logo switching using picture element
- Hover states for menu items
Move Create Note button to a prominent position in sidebar with
primary button styling, adjust logo size, and use rounded-full
for hover states.
Add reusable Footer component with Code of Conduct link and
license information, integrate it into Navigation sidebar.
# Conflicts:
#	web-next/src/components/AppSidebar.tsx
#	web-next/src/components/FloatingComposeButton.tsx
#	web-next/src/locales/en-US/messages.po
#	web-next/src/locales/ja-JP/messages.po
#	web-next/src/locales/ko-KR/messages.po
#	web-next/src/locales/zh-CN/messages.po
#	web-next/src/locales/zh-TW/messages.po
#	web-next/src/routes/(root).tsx
Add left padding to nav list at lg breakpoint and move compose button
outside the ul element for proper sizing and semantic correctness.
@coderabbitai
Copy link

coderabbitai bot commented Jan 24, 2026

📝 Walkthrough

Walkthrough

This PR removes the old AppSidebar and FloatingComposeButton, introduces new Navigation and Footer components, updates the root layout to render Navigation, and relocates/deprecates numerous translation strings across locale files to reflect the new navigation structure.

Changes

Cohort / File(s) Summary
Removed navigation UI
web-next/src/components/AppSidebar.tsx, web-next/src/components/FloatingComposeButton.tsx
Complete deletion of the sidebar and floating compose button components, their fragments, event handlers, mutations, and related UI/layout logic.
Added navigation UI
web-next/src/components/Navigation.tsx, web-next/src/components/Footer.tsx
New Navigation component (responsive bottom/side bar, avatar, compose trigger) and Footer (Code of Conduct / GitHub / license links) with Relay fragments and i18n.
Layout / routing
web-next/src/routes/(root).tsx
Replace AppSidebar/FloatingComposeButton with internal RootLayoutContent that conditionally renders Navigation; update viewer fragment spreads and adjust main content width constraint.
Localization updates
web-next/src/locales/en-US/messages.po, web-next/src/locales/ja-JP/messages.po, web-next/src/locales/ko-KR/messages.po, web-next/src/locales/zh-CN/messages.po, web-next/src/locales/zh-TW/messages.po
Relocate and deprecate many msgids from removed components to Navigation/Footer, add new keys (e.g., "Main navigation", "Profile"), and apply wording/punctuation refinements across locales.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • dahlia

Poem

🐰 The sidebar tiptoes off the lawn, the floating button hops away,
Navigation springs up at dusk, Footer hums the end-of-day,
Routes retie their ribbons, translations find their new nest,
A rabbit claps its paws — the app looks dressed its best! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: replacing AppSidebar with responsive Navigation, which is the primary objective reflected throughout the diff.

✏️ 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

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @yihyunjoon, 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 significantly refactors the application's primary navigation system to enhance responsiveness and user experience across various devices. It consolidates previous sidebar and floating action button functionalities into a new, unified Navigation component, which dynamically adjusts its layout and features based on screen size, including a dedicated mobile bottom navigation bar.

Highlights

  • Unified Navigation Component: The AppSidebar and FloatingComposeButton components have been replaced by a single, unified Navigation component.
  • Responsive Design Implementation: The new Navigation component incorporates responsive breakpoints, displaying an icon-only sidebar on small screens (sm) and a full sidebar with labels on larger screens (lg).
  • Mobile Bottom Navigation Bar: A dedicated bottom navigation bar has been added for mobile devices, providing easy access to key navigation items and a compose button.
  • Footer Component Extraction: The application's footer content has been extracted into a standalone Footer component for better modularity and reusability.
  • Visual Alignment Improvement: Left padding has been added to the navigation list on large screens to enhance visual alignment and overall aesthetics.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

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 is a great step forward in improving the application's responsiveness by replacing the AppSidebar and FloatingComposeButton with a new, unified Navigation component. The implementation uses responsive design principles effectively. I've identified a potential functional regression and a minor code cleanup opportunity that would further enhance the quality of these changes. Overall, this is a solid and well-executed refactoring.

Comment on lines +147 to +156
<div class="hidden sm:flex w-full px-2 mt-5">
<button
type="button"
onClick={openNoteCompose}
class="flex lg:flex-1 items-center justify-center p-3 rounded-full bg-primary text-primary-foreground transition-colors hover:bg-primary/90"
aria-label={t`Create Note`}
>
<IconSquarePen class="size-5" aria-hidden="true" />
</button>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The new unified navigation is a significant improvement. However, it seems the "Create Article" functionality, which was available in both the previous sidebar and the floating action button, has been omitted. Both the mobile and desktop versions of the new compose button only trigger the note composition modal.

If this omission was unintentional, you might consider reintroducing this feature. For the desktop view, a dropdown menu on the compose button could be an effective way to offer both "Create Note" and "Create Article" options, similar to the previous implementation.

Comment on lines 53 to +57
<SidebarProvider>
<AppSidebar
$signedAccount={signedAccount()?.viewer}
signedAccountLoaded={!signedAccount.pending}
/>
<RootLayoutContent signedAccount={signedAccount}>
{props.children}
</RootLayoutContent>
</SidebarProvider>
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The SidebarProvider appears to be a remnant from the old AppSidebar component. Since the new Navigation component does not utilize the useSidebar context, this provider is likely no longer necessary. Removing it, along with its import, will help clean up the code and improve maintainability.

      <RootLayoutContent signedAccount={signedAccount}>
        {props.children}
      </RootLayoutContent>

@yihyunjoon yihyunjoon marked this pull request as ready for review January 24, 2026 08:29
Copy link

@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

🤖 Fix all issues with AI agents
In `@web-next/src/components/Footer.tsx`:
- Around line 23-35: The external anchor elements in Footer.tsx that render the
"GitHub repository" and the "AGPL-3.0" links use target="_blank" but lack rel
attributes, creating a tabnabbing risk; update the anchor JSX (the <a> elements
that produce the "GitHub repository" and the link for "AGPL-3.0") to include
rel="noopener noreferrer" alongside target="_blank" so external links open
safely in a new tab.
- Around line 19-40: The Trans message placeholders do not match the locale's
numeric placeholders, so update the usage in Footer.tsx to use the same numeric
placeholders or update the values keys accordingly: change the message prop to
use {0} and {1} instead of ${"GITHUB_REPOSITORY"} and ${"AGPL-3.0"}, or
alternatively replace the values keys GITHUB_REPOSITORY and "AGPL-3.0" with
numeric keys (0 and 1) so the Trans component injects the anchor elements into
the placeholders; modify the Trans call and its values object (referencing the
Trans component, the message prop, and the values entries) to ensure placeholder
names match the locale format.

In `@web-next/src/components/Navigation.tsx`:
- Around line 123-136: The Profile nav item only checks for exact match against
location.pathname, so subroutes like /@username/notes aren't treated as active;
update the logic in Navigation.tsx (the A element's aria-current and the Avatar
classList check around account.username and location.pathname) to use a prefix
match (e.g., location.pathname.startsWith(`/@${account.username}`)) or compute
an isProfileRoute variable and reuse it for both aria-current and the "ring-2
ring-foreground" class so the profile tab stays active on subroutes.

In `@web-next/src/locales/zh-CN/messages.po`:
- Around line 1207-1212: The translation swaps the placeholder order: msgid uses
{0} for repository and {1} for license but msgstr in
web-next/src/locales/zh-CN/messages.po places them opposite; update the msgstr
so that {0} corresponds to the repository and {1} to the license (as used by
src/components/Footer.tsx) to preserve correct semantics.
🧹 Nitpick comments (2)
web-next/src/components/Footer.tsx (1)

8-14: Destructure props in the component signature.

This keeps component style consistent with project conventions.

♻️ Suggested refactor
-export function Footer(props: FooterProps) {
+export function Footer({ class: className }: FooterProps) {
   const { t } = useLingui();

   return (
     <footer
-      class={`p-4 text-xs text-muted-foreground ${props.class ?? ""}`}
+      class={`p-4 text-xs text-muted-foreground ${className ?? ""}`}
     >

As per coding guidelines, use functional components with props destructuring.

web-next/src/components/Navigation.tsx (1)

19-32: Destructure props in the component signature.

Keeps component style consistent across the codebase.

♻️ Suggested refactor
-export function Navigation(props: NavigationProps) {
+export function Navigation({ $signedAccount }: NavigationProps) {
@@
-    () => props.$signedAccount,
+    () => $signedAccount,

As per coding guidelines, use functional components with props destructuring.

Comment on lines +19 to +40
<Trans
message={t`The source code of this website is available on ${"GITHUB_REPOSITORY"} under the ${"AGPL-3.0"} license.`}
values={{
GITHUB_REPOSITORY: () => (
<a
href="https://github.com/hackers-pub/hackerspub"
target="_blank"
class="underline"
>
{t`GitHub repository`}
</a>
),
"AGPL-3.0": () => (
<a
href="https://www.gnu.org/licenses/agpl-3.0.en.html"
target="_blank"
class="underline"
>
AGPL 3.0
</a>
),
}}
Copy link

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
# Find all .po files and search for the message
fd -e po . web-next/src/locales --exec grep -l "The source code of this website is available on" {} \;

Repository: hackers-pub/hackerspub

Length of output: 260


🏁 Script executed:

#!/bin/bash
# Get details of the message in locale files
rg -A 3 "The source code of this website is available on" web-next/src/locales

Repository: hackers-pub/hackerspub

Length of output: 1898


Align Trans component placeholders with locale file format.

The locale entries use {0} and {1} placeholders, but the Trans component uses named placeholders (GITHUB_REPOSITORY and "AGPL-3.0"). This mismatch prevents the values object from properly injecting the anchor elements.

✅ Correct placeholder names
           values={{
-            GITHUB_REPOSITORY: () => (
+            "{0}": () => (
               <a
                 href="https://github.com/hackers-pub/hackerspub"
                 target="_blank"
                 class="underline"
               >
                 {t`GitHub repository`}
               </a>
             ),
-            "AGPL-3.0": () => (
+            "{1}": () => (
               <a
                 href="https://www.gnu.org/licenses/agpl-3.0.en.html"
                 target="_blank"
                 class="underline"
               >
                 AGPL 3.0
               </a>
             ),
           }}
🧰 Tools
🪛 Biome (2.1.2)

[error] 25-25: Avoid using target="_blank" without rel="noopener" or rel="noreferrer".

Opening external links in new tabs without rel="noopener" is a security risk. See the explanation for more details.
Safe fix: Add the rel="noopener" attribute.

(lint/security/noBlankTarget)


[error] 34-34: Avoid using target="_blank" without rel="noopener" or rel="noreferrer".

Opening external links in new tabs without rel="noopener" is a security risk. See the explanation for more details.
Safe fix: Add the rel="noopener" attribute.

(lint/security/noBlankTarget)

🤖 Prompt for AI Agents
In `@web-next/src/components/Footer.tsx` around lines 19 - 40, The Trans message
placeholders do not match the locale's numeric placeholders, so update the usage
in Footer.tsx to use the same numeric placeholders or update the values keys
accordingly: change the message prop to use {0} and {1} instead of
${"GITHUB_REPOSITORY"} and ${"AGPL-3.0"}, or alternatively replace the values
keys GITHUB_REPOSITORY and "AGPL-3.0" with numeric keys (0 and 1) so the Trans
component injects the anchor elements into the placeholders; modify the Trans
call and its values object (referencing the Trans component, the message prop,
and the values entries) to ensure placeholder names match the locale format.

Comment on lines +23 to +35
<a
href="https://github.com/hackers-pub/hackerspub"
target="_blank"
class="underline"
>
{t`GitHub repository`}
</a>
),
"AGPL-3.0": () => (
<a
href="https://www.gnu.org/licenses/agpl-3.0.en.html"
target="_blank"
class="underline"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add rel="noopener noreferrer" to external links opened in a new tab.

Both external anchors open in a new tab without rel, which is a tabnabbing risk.

🛡️ Proposed fix
               <a
                 href="https://github.com/hackers-pub/hackerspub"
                 target="_blank"
+                rel="noopener noreferrer"
                 class="underline"
               >
...
               <a
                 href="https://www.gnu.org/licenses/agpl-3.0.en.html"
                 target="_blank"
+                rel="noopener noreferrer"
                 class="underline"
               >
📝 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
<a
href="https://github.com/hackers-pub/hackerspub"
target="_blank"
class="underline"
>
{t`GitHub repository`}
</a>
),
"AGPL-3.0": () => (
<a
href="https://www.gnu.org/licenses/agpl-3.0.en.html"
target="_blank"
class="underline"
<a
href="https://github.com/hackers-pub/hackerspub"
target="_blank"
rel="noopener noreferrer"
class="underline"
>
{t`GitHub repository`}
</a>
),
"AGPL-3.0": () => (
<a
href="https://www.gnu.org/licenses/agpl-3.0.en.html"
target="_blank"
rel="noopener noreferrer"
class="underline"
🧰 Tools
🪛 Biome (2.1.2)

[error] 25-25: Avoid using target="_blank" without rel="noopener" or rel="noreferrer".

Opening external links in new tabs without rel="noopener" is a security risk. See the explanation for more details.
Safe fix: Add the rel="noopener" attribute.

(lint/security/noBlankTarget)


[error] 34-34: Avoid using target="_blank" without rel="noopener" or rel="noreferrer".

Opening external links in new tabs without rel="noopener" is a security risk. See the explanation for more details.
Safe fix: Add the rel="noopener" attribute.

(lint/security/noBlankTarget)

🤖 Prompt for AI Agents
In `@web-next/src/components/Footer.tsx` around lines 23 - 35, The external anchor
elements in Footer.tsx that render the "GitHub repository" and the "AGPL-3.0"
links use target="_blank" but lack rel attributes, creating a tabnabbing risk;
update the anchor JSX (the <a> elements that produce the "GitHub repository" and
the link for "AGPL-3.0") to include rel="noopener noreferrer" alongside
target="_blank" so external links open safely in a new tab.

Comment on lines +123 to +136
<A
href={`/@${account.username}`}
class="flex items-center justify-center py-3 sm:p-3 lg:justify-start lg:gap-3 lg:rounded-full lg:hover:bg-accent"
aria-label={t`Profile`}
aria-current={location.pathname === `/@${account.username}`
? "page"
: undefined}
>
<Avatar
class="size-6 shrink-0"
classList={{
"ring-2 ring-foreground": location.pathname ===
`/@${account.username}`,
}}
Copy link

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 Profile nav item active on subroutes.

Currently the profile item is only active on the exact /@username path. Subpages like /@username/notes won’t highlight the profile tab.

✅ Proposed fix
-      {(account) => (
+      {(account) => {
+        const profilePath = `/@${account.username}`;
+        const profileActive = isActive(profilePath);
+        return (
         <nav
           class="fixed sm:flex sm:flex-col z-50 border-border bg-background/95 bottom-0 left-0 right-0 border-t sm:sticky sm:top-0 sm:h-screen sm:w-16 sm:shrink-0 sm:border-t-0 sm:border-r lg:w-50 sm:py-3"
           role="navigation"
           aria-label={t`Main navigation`}
         >
@@
             <li class="flex-1 sm:flex-none sm:w-full">
               <A
-                href={`/@${account.username}`}
+                href={profilePath}
                 class="flex items-center justify-center py-3 sm:p-3 lg:justify-start lg:gap-3 lg:rounded-full lg:hover:bg-accent"
                 aria-label={t`Profile`}
-                aria-current={location.pathname === `/@${account.username}`
-                  ? "page"
-                  : undefined}
+                aria-current={profileActive ? "page" : undefined}
               >
                 <Avatar
                   class="size-6 shrink-0"
                   classList={{
-                    "ring-2 ring-foreground": location.pathname ===
-                      `/@${account.username}`,
+                    "ring-2 ring-foreground": profileActive,
                   }}
                 >
@@
-        </nav>
-      )}
+        </nav>
+      );}}
🤖 Prompt for AI Agents
In `@web-next/src/components/Navigation.tsx` around lines 123 - 136, The Profile
nav item only checks for exact match against location.pathname, so subroutes
like /@username/notes aren't treated as active; update the logic in
Navigation.tsx (the A element's aria-current and the Avatar classList check
around account.username and location.pathname) to use a prefix match (e.g.,
location.pathname.startsWith(`/@${account.username}`)) or compute an
isProfileRoute variable and reuse it for both aria-current and the "ring-2
ring-foreground" class so the profile tab stays active on subroutes.

Comment on lines 1207 to 1212
#. placeholder {0}: "GITHUB_REPOSITORY"
#. placeholder {1}: "AGPL-3.0"
#: src/components/AppSidebar.tsx:536
#: src/components/Footer.tsx:20
msgid "The source code of this website is available on {0} under the {1} license."
msgstr "可在 {1} 上以 {0} 许可获取该网站的源代码。"

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Swap the placeholder order to keep meaning correct.

{0} is the repository and {1} is the license, but the translation currently places them in the opposite semantic roles.

📝 Proposed fix
-msgstr "可在 {1} 上以 {0} 许可获取该网站的源代码。"
+msgstr "可在 {0} 上以 {1} 许可获取该网站的源代码。"
🤖 Prompt for AI Agents
In `@web-next/src/locales/zh-CN/messages.po` around lines 1207 - 1212, The
translation swaps the placeholder order: msgid uses {0} for repository and {1}
for license but msgstr in web-next/src/locales/zh-CN/messages.po places them
opposite; update the msgstr so that {0} corresponds to the repository and {1} to
the license (as used by src/components/Footer.tsx) to preserve correct
semantics.

Copy link

@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: 3

🧹 Nitpick comments (2)
web-next/src/locales/ko-KR/messages.po (1)

14-14: Consider adding Korean plural form specification.

The Plural-Forms header is empty. While Lingui uses ICU MessageFormat which handles pluralization independently, adding the correct specification improves file completeness and documentation:

-"Plural-Forms: \n"
+"Plural-Forms: nplurals=1; plural=0;\n"

This documents that Korean has no grammatical plural distinction.

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

In `@web-next/src/locales/ko-KR/messages.po` at line 14, Add the Korean plural
form specification to the PO header by populating the "Plural-Forms" entry; set
it to indicate a single plural form for Korean (e.g., nplurals=1; plural=0;) so
the "Plural-Forms" header in web-next/src/locales/ko-KR/messages.po is not empty
and documents that Korean has no grammatical plural distinction.
web-next/src/locales/ja-JP/messages.po (1)

29-29: Polish overflow-count wording for more natural Japanese UI

Line 29’s +# 他 is understandable but a bit unnatural. +#件 is usually clearer in compact count badges.

Optional wording tweak
-msgstr "{0, plural, other {+# 他}}"
+msgstr "{0, plural, other {+#件}}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web-next/src/locales/ja-JP/messages.po` at line 29, Update the Japanese
pluralization message string: replace the current msgstr value "{+# 他}" with the
more natural compact badge wording "{+#件}" in the messages.po entry (the msgstr
for the plural "other" form) so count badges read e.g. "+3件" instead of "+3 他".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web-next/src/locales/en-US/messages.po`:
- Around line 289-294: The translation catalog contains active references
pointing to a removed component AppSidebar.tsx; for each affected msgid (e.g.,
"Code of conduct", "GitHub repository", "Notifications") open the messages.po
entries and either remove the stale AppSidebar.tsx references or replace them
with the correct source locations (for example Footer.tsx or Navigation.tsx) so
references point to existing components; ensure you update all occurrences
(including the ranges called out around lines 580-583 and 938-942) and keep the
msgid/msgstr pairs intact while only changing the reference lines.

In `@web-next/src/locales/ja-JP/messages.po`:
- Line 459: The Japanese translation for the error message currently uses the
truncated phrase "クリックして再試行" in the msgstr that reads
"下書きの読み込みに失敗しました。クリックして再試行"; update this msgstr to append "してください" so it becomes
"下書きの読み込みに失敗しました。クリックして再試行してください" to match the established error-action tone and
complete the instruction phrase.

In `@web-next/src/locales/zh-CN/messages.po`:
- Around line 235-237: The translation for msgid "article-url-slug" currently
uses "文章URL数据域" which misrenders "slug"; update the msgstr for msgid
"article-url-slug" (and any duplicate entries with the same msgid) to a correct
localized term such as "URL 别名" or "URL 别名(Slug)" to preserve meaning and
optionally include the English "Slug" in parentheses for clarity; ensure the
same corrected msgstr is applied consistently across all occurrences of the
"article-url-slug" key in messages.po and add the preferred term to the locale
glossary file (glossary.txt) to prevent regressions.

---

Nitpick comments:
In `@web-next/src/locales/ja-JP/messages.po`:
- Line 29: Update the Japanese pluralization message string: replace the current
msgstr value "{+# 他}" with the more natural compact badge wording "{+#件}" in the
messages.po entry (the msgstr for the plural "other" form) so count badges read
e.g. "+3件" instead of "+3 他".

In `@web-next/src/locales/ko-KR/messages.po`:
- Line 14: Add the Korean plural form specification to the PO header by
populating the "Plural-Forms" entry; set it to indicate a single plural form for
Korean (e.g., nplurals=1; plural=0;) so the "Plural-Forms" header in
web-next/src/locales/ko-KR/messages.po is not empty and documents that Korean
has no grammatical plural distinction.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eaee1e8 and 0603dd3.

📒 Files selected for processing (5)
  • web-next/src/locales/en-US/messages.po
  • web-next/src/locales/ja-JP/messages.po
  • web-next/src/locales/ko-KR/messages.po
  • web-next/src/locales/zh-CN/messages.po
  • web-next/src/locales/zh-TW/messages.po
🚧 Files skipped from review as they are similar to previous changes (1)
  • web-next/src/locales/zh-TW/messages.po

Comment on lines +289 to 294
#: src/components/Footer.tsx:16
#: src/components/AppSidebar.tsx:532
#: src/routes/(root)/coc.tsx:47
#: src/routes/(root)/sign/up/[token].tsx:457
msgid "Code of conduct"
msgstr "Code of conduct"
Copy link

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

# 1) Check whether AppSidebar component still exists
echo "=== Checking if AppSidebar.tsx exists ==="
fd 'AppSidebar\.tsx$'

# 2) Check whether AppSidebar is still referenced in TS/TSX source
echo ""
echo "=== Checking for AppSidebar references in TS/TSX source ==="
rg -nP --type=ts --type=tsx -C2 '\bAppSidebar\b' | head -50

# 3) Show active (non-obsolete) AppSidebar refs in this catalog
echo ""
echo "=== Checking active AppSidebar references in messages.po ==="
python - <<'PY'
from pathlib import Path
p = Path("web-next/src/locales/en-US/messages.po")
if not p.exists():
    print(f"File not found: {p}")
else:
    lines = p.read_text(encoding="utf-8").splitlines()
    for i, line in enumerate(lines):
        if line.startswith("#:") and "src/components/AppSidebar.tsx" in line:
            window = "\n".join(lines[i:i+5])
            if "#~ msgid" not in window:
                print(f"Line {i+1}: {line}")
PY

Repository: hackers-pub/hackerspub

Length of output: 213


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Explore the directory structure
echo "=== Directory structure of web-next/src ==="
fd --type d '' web-next/src/ | head -20

# 2) Check if AppSidebar exists anywhere
echo ""
echo "=== Searching for AppSidebar file or references ==="
fd 'AppSidebar' web-next/src/ 2>/dev/null || echo "No AppSidebar files found"

# 3) Search for AppSidebar references in source files without type restriction
echo ""
echo "=== Searching for AppSidebar in source files ==="
rg 'AppSidebar' web-next/src/ -l 2>/dev/null | head -20

# 4) Check the messages.po file structure
echo ""
echo "=== Checking messages.po file for AppSidebar references ==="
if [ -f "web-next/src/locales/en-US/messages.po" ]; then
    # Show all lines with AppSidebar references
    rg 'AppSidebar' web-next/src/locales/en-US/messages.po -B1 -A4
else
    echo "messages.po not found"
fi

# 5) Check web-next/src/components directory
echo ""
echo "=== Contents of web-next/src/components ==="
ls -la web-next/src/components/ 2>/dev/null || echo "Directory not found"

Repository: hackers-pub/hackerspub

Length of output: 6996


🏁 Script executed:

#!/bin/bash

# Check what's in drafts/index.tsx that references AppSidebar
echo "=== AppSidebar reference in drafts/index.tsx ==="
rg 'AppSidebar' web-next/src/routes/\(root\)/\[handle\]/drafts/index.tsx -B2 -A2

# Look at the specific lines in messages.po mentioned in the review
echo ""
echo "=== Lines 289-294 in messages.po ==="
sed -n '287,296p' web-next/src/locales/en-US/messages.po

echo ""
echo "=== Lines 580-583 in messages.po ==="
sed -n '578,586p' web-next/src/locales/en-US/messages.po

echo ""
echo "=== Lines 938-942 in messages.po ==="
sed -n '936,946p' web-next/src/locales/en-US/messages.po

# Count total active vs obsolete AppSidebar references
echo ""
echo "=== Summary of AppSidebar references in messages.po ==="
echo "Active (non-obsolete) AppSidebar references:"
rg 'src/components/AppSidebar\.tsx' web-next/src/locales/en-US/messages.po | grep -v '^#~' | wc -l
echo "Obsolete AppSidebar references:"
rg 'src/components/AppSidebar\.tsx' web-next/src/locales/en-US/messages.po | grep '^#~' | wc -l

Repository: hackers-pub/hackerspub

Length of output: 1372


Remove active AppSidebar references from translation catalog or update source locations.

The AppSidebar.tsx component no longer exists in the codebase, but the translation catalog contains 14 active (non-obsolete) references to it. Examples: "Code of conduct" references AppSidebar.tsx:532, "GitHub repository" references AppSidebar.tsx:544, and "Notifications" references AppSidebar.tsx:317. These stale references should be removed from the catalog or the source lines should be corrected to point to the components that actually contain these strings (e.g., Footer.tsx, Navigation.tsx).

Also applies to lines 580-583, 938-942, and all other active AppSidebar references in the catalog.

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

In `@web-next/src/locales/en-US/messages.po` around lines 289 - 294, The
translation catalog contains active references pointing to a removed component
AppSidebar.tsx; for each affected msgid (e.g., "Code of conduct", "GitHub
repository", "Notifications") open the messages.po entries and either remove the
stale AppSidebar.tsx references or replace them with the correct source
locations (for example Footer.tsx or Navigation.tsx) so references point to
existing components; ensure you update all occurrences (including the ranges
called out around lines 580-583 and 938-942) and keep the msgid/msgstr pairs
intact while only changing the reference lines.

#: src/routes/(root)/[handle]/drafts/index.tsx:325
msgid "Failed to load more drafts; click to retry"
msgstr "下書きの読み込みに失敗しました。クリックして再試行してください"
msgstr "下書きの読み込みに失敗しました。クリックして再試行"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Line 459 has an incomplete retry phrase

クリックして再試行 reads truncated in Japanese. Please add してください to match the established error-action tone.

Suggested fix
-msgstr "下書きの読み込みに失敗しました。クリックして再試行"
+msgstr "下書きの読み込みに失敗しました。クリックして再試行してください"
📝 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
msgstr "下書きの読み込みに失敗しました。クリックして再試行"
msgstr "下書きの読み込みに失敗しました。クリックして再試行してください"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web-next/src/locales/ja-JP/messages.po` at line 459, The Japanese translation
for the error message currently uses the truncated phrase "クリックして再試行" in the
msgstr that reads "下書きの読み込みに失敗しました。クリックして再試行"; update this msgstr to append
"してください" so it becomes "下書きの読み込みに失敗しました。クリックして再試行してください" to match the
established error-action tone and complete the instruction phrase.

Comment on lines 235 to +237
#: src/components/article-composer/ArticleComposerPublishFields.tsx:24
msgid "article-url-slug"
msgstr "文章网址别名"
msgstr "文章URL数据域"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

“Slug” is mistranslated as “数据域”; this changes the meaning.

Line 237, Line 1245, and Line 1249 should use a URL-slug term (e.g., “URL 别名” / “Slug”) instead of “数据域”, otherwise the field intent becomes unclear.

📝 Suggested wording update
-msgstr "文章URL数据域"
+msgstr "文章 URL 别名"

-msgstr "数据域 (URL)"
+msgstr "URL 别名 (Slug)"

-msgstr "数据域不能为空"
+msgstr "URL 别名不能为空"

As per coding guidelines, "In new stack (web-next/), use Lingui with gettext-style approach (source text as key); translation files at web-next/src/locales/{locale}/messages.po with terminology glossaries at web-next/src/locales/{locale}/glossary.txt".

Also applies to: 1243-1249

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

In `@web-next/src/locales/zh-CN/messages.po` around lines 235 - 237, The
translation for msgid "article-url-slug" currently uses "文章URL数据域" which
misrenders "slug"; update the msgstr for msgid "article-url-slug" (and any
duplicate entries with the same msgid) to a correct localized term such as "URL
别名" or "URL 别名(Slug)" to preserve meaning and optionally include the English
"Slug" in parentheses for clarity; ensure the same corrected msgstr is applied
consistently across all occurrences of the "article-url-slug" key in messages.po
and add the preferred term to the locale glossary file (glossary.txt) to prevent
regressions.

@yihyunjoon yihyunjoon closed this Mar 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant