Skip to content

Feat/status page i18n#1966

Open
aggmoulik wants to merge 24 commits intoopenstatusHQ:mainfrom
aggmoulik:feat/status-page-i18n
Open

Feat/status page i18n#1966
aggmoulik wants to merge 24 commits intoopenstatusHQ:mainfrom
aggmoulik:feat/status-page-i18n

Conversation

@aggmoulik
Copy link
Contributor

No description provided.

@vercel
Copy link

vercel bot commented Mar 11, 2026

@aggmoulik is attempting to deploy a commit to the OpenStatus Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds internationalization (i18n) support to the status-page app using next-intl, introducing locale-aware routing, translated UI strings, and new localized public/auth pages (events, monitors, verify/unsubscribe/manage, feeds, badges).

Changes:

  • Integrates next-intl (config, request routing, Next.js plugin) and adds locale-prefixed route structure under /[domain]/[locale]/....
  • Replaces hard-coded UI strings with next-intl lookups across key status-page components and nav.
  • Adds new localized pages and routes for monitors, events, feeds (RSS/Atom/JSON), verification/unsubscribe, and badges; introduces static components used by the public playground.

Reviewed changes

Copilot reviewed 42 out of 64 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
pnpm-lock.yaml Lockfile updates for next-intl + transitive deps (incl. SWC-related).
apps/status-page/package.json Adds next-intl dependency.
apps/status-page/next.config.ts Wraps Next config with next-intl plugin; adds locale-aware subdomain rewrites.
apps/status-page/src/i18n/config.ts Defines supported locales + default locale.
apps/status-page/src/i18n/routing.ts Adds next-intl routing config.
apps/status-page/src/i18n/request.ts Adds request-time locale/messages loading for next-intl.
apps/status-page/src/proxy.ts Middleware-like proxy: locale detection/redirects + auth gating + rewrites.
apps/status-page/src/hooks/use-pathname-prefix.ts Makes link prefix generation locale-aware.
apps/status-page/src/components/language-switcher.tsx Adds locale switcher UI in footer.
apps/status-page/src/components/nav/header.tsx Translates nav labels and some toast text.
apps/status-page/src/components/nav/footer.tsx Adds language switcher; translates “powered by”.
apps/status-page/src/components/status-page/status-updates.tsx Translates subscription UI strings.
apps/status-page/src/components/status-page/status-tracker.tsx Translates tracker labels/status text.
apps/status-page/src/components/status-page/status-monitor.tsx Translates monitor status/footer text.
apps/status-page/src/components/status-page/status-feed.tsx Translates empty state + CTA copy.
apps/status-page/src/components/status-page/status-events.tsx Translates status/update labels and CTAs.
apps/status-page/src/components/status-page/status-banner.tsx Translates banner “system status” copy; removes old messages import.
apps/status-page/src/components/status-page/messages.ts Removes legacy hard-coded message dictionaries (now handled via i18n).
apps/status-page/src/components/status-page/static/status-banner-static.tsx Adds “static” banner component (used in playground).
apps/status-page/src/components/status-page/static/status-monitor-static.tsx Adds “static” monitor component (used in playground).
apps/status-page/src/components/status-page/static/status-tracker-static.tsx Adds “static” tracker component (used in playground).
apps/status-page/src/components/status-page/static/status-events-static.tsx Adds “static” events timeline component (used in playground).
apps/status-page/src/components/forms/form-email.tsx Translates form labels + toast states.
apps/status-page/src/components/forms/form-password.tsx Translates form labels + toast states.
apps/status-page/src/components/forms/form-subscribe-email.tsx Translates subscribe form labels + toast states + empty states.
apps/status-page/src/components/forms/form-manage-subscription.tsx Translates manage-subscription form strings.
apps/status-page/src/app/(public)/client.tsx Uses new static status components in the public playground.
apps/status-page/src/app/(status-page)/[domain]/[locale]/layout.tsx Adds locale layout with NextIntlClientProvider + message loading.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/layout.tsx Adds shared public layout with Header/Footer.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/page.tsx Adds localized main status-page entry route.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/events/layout.tsx Adds events section layout (loads page header).
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/events/(list)/search-params.ts Adds nuqs search param parsing for events list tab.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/events/(list)/page.tsx Translates events tabs and empty state strings.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/events/(view)/report/[id]/layout.tsx Prefetches report data for hydration.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/events/(view)/report/[id]/page.tsx Translates “not found” copy for report view.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/events/(view)/maintenance/[id]/layout.tsx Prefetches maintenance data for hydration.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/events/(view)/maintenance/[id]/page.tsx Translates “not found” copy for maintenance view.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/monitors/page.tsx Adds localized monitors listing page.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/monitors/[id]/search-params.ts Adds nuqs search param parsing for monitor detail tabs.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/monitors/[id]/page.tsx Translates monitor detail labels/descriptions and empty state.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/feed/json/route.ts Adds JSON feed route (locale-scoped path).
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/feed/[type]/route.ts Adds RSS/Atom feed route.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/badge/route.tsx Adds OG-image badge route.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/badge/v2/route.ts Adds SVG badge route.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/verify/[token]/layout.tsx Adds verify layout (loads page header).
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/verify/[token]/page.tsx Adds verify token page UI.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/unsubscribe/[token]/layout.tsx Adds unsubscribe layout (loads page header).
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/unsubscribe/[token]/page.tsx Adds unsubscribe flow UI.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/manage/layout.tsx Adds manage section layout (loads page header).
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/manage/[token]/layout.tsx Prefetches subscription data for hydration.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/manage/[token]/page.tsx Adds manage subscription UI + unsubscribe dialog.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(auth)/layout.tsx Adds auth layout with page prefetch.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(auth)/login/page.tsx Adds login entry route that selects auth method.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(auth)/login/actions.ts Localizes server action error messages.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(auth)/login/_components/section-password.tsx Localizes password login UI strings.
apps/status-page/src/app/(status-page)/[domain]/[locale]/(auth)/login/_components/section-magic-link.tsx Localizes magic-link login UI strings.
apps/status-page/messages/en.json Adds extracted English messages (hashed keys).
apps/status-page/messages/fr.json Adds extracted French message file (currently empty values).
apps/status-page/messages/de.json Adds extracted German message file (currently empty values).
apps/status-page/messages/es.json Adds extracted Spanish message file (currently empty values).
apps/status-page/messages/pt.json Adds extracted Portuguese message file (currently empty values).
apps/status-page/messages/ja.json Adds extracted Japanese message file (currently empty values).
apps/status-page/messages/zh.json Adds extracted Chinese message file (currently empty values).
apps/status-page/messages/ko.json Adds extracted Korean message file (currently empty values).
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@openstatusHQ openstatusHQ deleted a comment from claude bot Mar 11, 2026
aggmoulik and others added 16 commits March 12, 2026 21:32
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hardcoded strings in status-banner, status-monitor,
status-events, and status-feed with useExtracted() i18n calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Moulik Aggarwal <qwertymoulik@gmail.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…and monitor pages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hardcoded English strings with useExtracted() calls in login
sections, form components, and status updates popover.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Moulik Aggarwal <qwertymoulik@gmail.com>
Remove the old messages.ts file (replaced by useExtracted), update
status-tracker.tsx to use useExtracted, and add a globe-icon language
switcher dropdown in the footer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update usePathnamePrefix hook to include locale segment in prefix
for non-default locales, ensuring internal links work correctly
across all languages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Turbopack doesn't support .po imports natively. Switch to .json which
next-intl handles out of the box. Create empty JSON catalogs for all
supported locales as placeholders for future translations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Moulik Aggarwal <qwertymoulik@gmail.com>
Signed-off-by: Moulik Aggarwal <qwertymoulik@gmail.com>
Signed-off-by: Moulik Aggarwal <qwertymoulik@gmail.com>
Signed-off-by: Moulik Aggarwal <qwertymoulik@gmail.com>
Signed-off-by: Moulik Aggarwal <qwertymoulik@gmail.com>
Signed-off-by: Moulik Aggarwal <qwertymoulik@gmail.com>
@aggmoulik aggmoulik force-pushed the feat/status-page-i18n branch from 0e25322 to 792216b Compare March 12, 2026 16:08
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

10 issues found across 62 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/monitors/[id]/page.tsx">

<violation number="1" location="apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/monitors/[id]/page.tsx:256">
P2: Translating `"regions"` and `"checks"` separately from their counts breaks pluralization in most non-English languages. The number and noun should be part of the same translatable string so translators can apply plural rules (e.g. `t("{count} regions", { count: tempMonitor?.regions.length })` or an ICU-style plural).</violation>
</file>

<file name="apps/status-page/src/components/status-page/status-banner.tsx">

<violation number="1" location="apps/status-page/src/components/status-page/status-banner.tsx:85">
P2: "Downtime Performance" doesn't make semantic sense for the error/outage status. This looks like a copy-paste from "Degraded Performance." Consider something like "Major Outage" or simply "Downtime" (which already exists elsewhere in your translations as `"JOZGPR": "Downtime"`).

Note: the same string exists in `apps/status-page/messages/en.json` and would also need updating.</violation>
</file>

<file name="apps/status-page/src/components/status-page/static/status-monitor-static.tsx">

<violation number="1" location="apps/status-page/src/components/status-page/static/status-monitor-static.tsx:106">
P1: StatusMonitorStatic component contains hardcoded English strings instead of i18n translations. The component defines "today", "Operational", "Degraded", "Downtime", and "Maintenance" as hardcoded strings, while the i18n translations exist in messages/en.json (keys: "kkpP2k", "Dnob31", "VQDmmK", "JOZGPR", "dudqv/"). This contradicts the i18n pattern used in the existing StatusMonitor component which imports `useExtracted` from "next-intl" and uses `t("today")` and similar translations. For consistency across the codebase, StatusMonitorStatic should use the same i18n pattern.</violation>

<violation number="2" location="apps/status-page/src/components/status-page/static/status-monitor-static.tsx:111">
P2: `StatusMonitorIconStatic` is a character-for-character duplicate of the already-exported `StatusMonitorIcon` from `../status-monitor`. Since `StatusMonitorIcon` has no i18n dependency, import it directly instead of re-declaring it.

(Based on your team's feedback about reusing shared utilities from common UI library.) [FEEDBACK_USED]</violation>
</file>

<file name="apps/status-page/src/lib/resolve-route.test.ts">

<violation number="1" location="apps/status-page/src/lib/resolve-route.test.ts:282">
P2: Test description says `→ /status.acme.com/en (custom domain as prefix)` but the assertion expects `rewritePath: "/status/en"` and `prefix: "status"`. The description should match the actual expected output to avoid misleading readers.</violation>
</file>

<file name="apps/status-page/src/components/nav/header.tsx">

<violation number="1" location="apps/status-page/src/components/nav/header.tsx:127">
P1: Operator precedence bug: `||` binds tighter than `?:`, so `page?.homepageUrl` is consumed as a boolean rather than used as the href value. When a homepage URL exists, this always resolves to `"/"` instead of the external URL.

Add parentheses to get the intended fallback behavior.</violation>
</file>

<file name="apps/status-page/src/components/status-page/status-monitor.tsx">

<violation number="1" location="apps/status-page/src/components/status-page/status-monitor.tsx:21">
P0: `useExtracted` is not exported by `next-intl`. The correct hook for translations is `useTranslations`. This will cause a runtime error in both `StatusMonitorFooter` and `StatusMonitorStatus`.</violation>
</file>

<file name="apps/status-page/src/components/locale-switcher.tsx">

<violation number="1" location="apps/status-page/src/components/locale-switcher.tsx:42">
P2: `segments.includes(domain)` matches the domain against *any* path segment, not just the first one. This can produce false positives — e.g., when the domain slug collides with a locale code or appears deeper in the path. Use `segments[1] === domain` to restrict the check to the expected position.</violation>
</file>

<file name="apps/status-page/src/app/(status-page)/[domain]/[locale]/(auth)/login/actions.ts">

<violation number="1" location="apps/status-page/src/app/(status-page)/[domain]/[locale]/(auth)/login/actions.ts:11">
P2: Missed i18n: the identical error string in the outer `catch` block (line ~71) is not wrapped with `t()`, so this error message will always render in English regardless of locale.</violation>
</file>

<file name="apps/status-page/messages/de.json">

<violation number="1" location="apps/status-page/messages/de.json:55">
P2: Both `"80EXUh"` ("Downtime Performance") and `"JOZGPR"` ("Downtime") are translated to the same German string `"Ausfall"`. Consider differentiating them — e.g., `"Ausfallleistung"` or `"Beeinträchtigter Betrieb (Ausfall)"` for the longer variant — so the two labels remain distinguishable in the UI, matching the intent of the English source.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

"-"
)}
</div>
<div>today</div>
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 20, 2026

Choose a reason for hiding this comment

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

P1: StatusMonitorStatic component contains hardcoded English strings instead of i18n translations. The component defines "today", "Operational", "Degraded", "Downtime", and "Maintenance" as hardcoded strings, while the i18n translations exist in messages/en.json (keys: "kkpP2k", "Dnob31", "VQDmmK", "JOZGPR", "dudqv/"). This contradicts the i18n pattern used in the existing StatusMonitor component which imports useExtracted from "next-intl" and uses t("today") and similar translations. For consistency across the codebase, StatusMonitorStatic should use the same i18n pattern.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/status-page/src/components/status-page/static/status-monitor-static.tsx, line 106:

<comment>StatusMonitorStatic component contains hardcoded English strings instead of i18n translations. The component defines "today", "Operational", "Degraded", "Downtime", and "Maintenance" as hardcoded strings, while the i18n translations exist in messages/en.json (keys: "kkpP2k", "Dnob31", "VQDmmK", "JOZGPR", "dudqv/"). This contradicts the i18n pattern used in the existing StatusMonitor component which imports `useExtracted` from "next-intl" and uses `t("today")` and similar translations. For consistency across the codebase, StatusMonitorStatic should use the same i18n pattern.</comment>

<file context>
@@ -0,0 +1,165 @@
+          "-"
+        )}
+      </div>
+      <div>today</div>
+    </div>
+  );
</file context>
Fix with Cubic

) : (
<StatusMonitorTabsTriggerValue>
{tempMonitor?.regions.length} regions{" "}
{tempMonitor?.regions.length} {t("regions")}{" "}
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 20, 2026

Choose a reason for hiding this comment

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

P2: Translating "regions" and "checks" separately from their counts breaks pluralization in most non-English languages. The number and noun should be part of the same translatable string so translators can apply plural rules (e.g. t("{count} regions", { count: tempMonitor?.regions.length }) or an ICU-style plural).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/monitors/[id]/page.tsx, line 256:

<comment>Translating `"regions"` and `"checks"` separately from their counts breaks pluralization in most non-English languages. The number and noun should be part of the same translatable string so translators can apply plural rules (e.g. `t("{count} regions", { count: tempMonitor?.regions.length })` or an ICU-style plural).</comment>

<file context>
@@ -246,13 +247,13 @@ export default function Page() {
               ) : (
                 <StatusMonitorTabsTriggerValue>
-                  {tempMonitor?.regions.length} regions{" "}
+                  {tempMonitor?.regions.length} {t("regions")}{" "}
                   <Badge
                     variant="outline"
</file context>
Fix with Cubic

</span>
<span className="hidden group-data-[status=error]/status-banner:block">
{messages.long.error}
{t("Downtime Performance")}
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 20, 2026

Choose a reason for hiding this comment

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

P2: "Downtime Performance" doesn't make semantic sense for the error/outage status. This looks like a copy-paste from "Degraded Performance." Consider something like "Major Outage" or simply "Downtime" (which already exists elsewhere in your translations as "JOZGPR": "Downtime").

Note: the same string exists in apps/status-page/messages/en.json and would also need updating.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/status-page/src/components/status-page/status-banner.tsx, line 85:

<comment>"Downtime Performance" doesn't make semantic sense for the error/outage status. This looks like a copy-paste from "Degraded Performance." Consider something like "Major Outage" or simply "Downtime" (which already exists elsewhere in your translations as `"JOZGPR": "Downtime"`).

Note: the same string exists in `apps/status-page/messages/en.json` and would also need updating.</comment>

<file context>
@@ -70,19 +72,20 @@ export function StatusBannerMessage({
       </span>
       <span className="hidden group-data-[status=error]/status-banner:block">
-        {messages.long.error}
+        {t("Downtime Performance")}
       </span>
       <span className="hidden group-data-[status=info]/status-banner:block">
</file context>
Fix with Cubic


// Seed page 2: slug "acme", customDomain "status.acme.com"
describe('custom domain routing — status.acme.com (slug "acme")', () => {
test("status.acme.com/ → /status.acme.com/en (custom domain as prefix)", () => {
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 20, 2026

Choose a reason for hiding this comment

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

P2: Test description says → /status.acme.com/en (custom domain as prefix) but the assertion expects rewritePath: "/status/en" and prefix: "status". The description should match the actual expected output to avoid misleading readers.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/status-page/src/lib/resolve-route.test.ts, line 282:

<comment>Test description says `→ /status.acme.com/en (custom domain as prefix)` but the assertion expects `rewritePath: "/status/en"` and `prefix: "status"`. The description should match the actual expected output to avoid misleading readers.</comment>

<file context>
@@ -0,0 +1,364 @@
+
+  // Seed page 2: slug "acme", customDomain "status.acme.com"
+  describe('custom domain routing — status.acme.com (slug "acme")', () => {
+    test("status.acme.com/ → /status.acme.com/en (custom domain as prefix)", () => {
+      const result = resolveRoute({
+        host: "status.acme.com",
</file context>
Fix with Cubic

);
}

function StatusMonitorIconStatic({
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 20, 2026

Choose a reason for hiding this comment

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

P2: StatusMonitorIconStatic is a character-for-character duplicate of the already-exported StatusMonitorIcon from ../status-monitor. Since StatusMonitorIcon has no i18n dependency, import it directly instead of re-declaring it.

(Based on your team's feedback about reusing shared utilities from common UI library.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/status-page/src/components/status-page/static/status-monitor-static.tsx, line 111:

<comment>`StatusMonitorIconStatic` is a character-for-character duplicate of the already-exported `StatusMonitorIcon` from `../status-monitor`. Since `StatusMonitorIcon` has no i18n dependency, import it directly instead of re-declaring it.

(Based on your team's feedback about reusing shared utilities from common UI library.) </comment>

<file context>
@@ -0,0 +1,165 @@
+  );
+}
+
+function StatusMonitorIconStatic({
+  className,
+  ...props
</file context>
Fix with Cubic


// Pathname routing: slug is in the browser URL (e.g., /acme/fr/events)
// Hostname routing: slug is NOT in the browser URL (e.g., /fr/events)
const isPathnameRouting = segments.includes(domain);
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 20, 2026

Choose a reason for hiding this comment

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

P2: segments.includes(domain) matches the domain against any path segment, not just the first one. This can produce false positives — e.g., when the domain slug collides with a locale code or appears deeper in the path. Use segments[1] === domain to restrict the check to the expected position.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/status-page/src/components/locale-switcher.tsx, line 42:

<comment>`segments.includes(domain)` matches the domain against *any* path segment, not just the first one. This can produce false positives — e.g., when the domain slug collides with a locale code or appears deeper in the path. Use `segments[1] === domain` to restrict the check to the expected position.</comment>

<file context>
@@ -0,0 +1,93 @@
+
+      // Pathname routing: slug is in the browser URL (e.g., /acme/fr/events)
+      // Hostname routing: slug is NOT in the browser URL (e.g., /fr/events)
+      const isPathnameRouting = segments.includes(domain);
+      const localeIndex = isPathnameRouting ? 2 : 1;
+      const hasLocaleSegment = (locales as readonly string[]).includes(
</file context>
Fix with Cubic

"krEziQ": "Kontakt aufnehmen",
"BQBZU+": "Alle Systeme betriebsbereit",
"b9fOA1": "Eingeschränkte Leistung",
"80EXUh": "Ausfall",
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 20, 2026

Choose a reason for hiding this comment

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

P2: Both "80EXUh" ("Downtime Performance") and "JOZGPR" ("Downtime") are translated to the same German string "Ausfall". Consider differentiating them — e.g., "Ausfallleistung" or "Beeinträchtigter Betrieb (Ausfall)" for the longer variant — so the two labels remain distinguishable in the UI, matching the intent of the English source.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/status-page/messages/de.json, line 55:

<comment>Both `"80EXUh"` ("Downtime Performance") and `"JOZGPR"` ("Downtime") are translated to the same German string `"Ausfall"`. Consider differentiating them — e.g., `"Ausfallleistung"` or `"Beeinträchtigter Betrieb (Ausfall)"` for the longer variant — so the two labels remain distinguishable in the UI, matching the intent of the English source.</comment>

<file context>
@@ -0,0 +1,88 @@
+  "krEziQ": "Kontakt aufnehmen",
+  "BQBZU+": "Alle Systeme betriebsbereit",
+  "b9fOA1": "Eingeschränkte Leistung",
+  "80EXUh": "Ausfall",
+  "dudqv/": "Wartung",
+  "2syGZB": "Bericht gelöst",
</file context>
Fix with Cubic

@vercel
Copy link

vercel bot commented Mar 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
openstatus-dashboard Ready Ready Preview, Comment Mar 20, 2026 9:38pm
openstatus-status-page Ready Ready Preview, Comment Mar 20, 2026 9:38pm
openstatus-web Ready Ready Preview, Comment Mar 20, 2026 9:38pm

Request Review

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

3 issues found across 15 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/status-page/src/lib/resolve-pathname-prefix.ts">

<violation number="1" location="apps/status-page/src/lib/resolve-pathname-prefix.ts:40">
P3: The comment directly above (`// Pathname routing — slug always, locale only if non-default`) now contradicts the new behavior, which always includes the locale. Update it to reflect the change, e.g. `// Pathname routing — always {slug}/{locale}`.</violation>
</file>

<file name="apps/status-page/src/components/date-fns-provider.tsx">

<violation number="1" location="apps/status-page/src/components/date-fns-provider.tsx:16">
P2: `setDefaultOptions` is a global side effect called during render, violating React's expectation that render is pure. Wrap it in `useEffect` so it runs after commit instead of during the render phase.</violation>
</file>

<file name="apps/status-page/src/lib/formatter.ts">

<violation number="1" location="apps/status-page/src/lib/formatter.ts:95">
P2: The string literals `"Until"`, `"Since"`, and `"All time"` are still hardcoded in English, which is inconsistent with the i18n goal of this PR. These labels should be translated alongside the date formatting.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.


if (to) {
return `Until ${formatDateTime(to)}`;
return `Until ${formatDateTime(to, locale)}`;
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 20, 2026

Choose a reason for hiding this comment

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

P2: The string literals "Until", "Since", and "All time" are still hardcoded in English, which is inconsistent with the i18n goal of this PR. These labels should be translated alongside the date formatting.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/status-page/src/lib/formatter.ts, line 95:

<comment>The string literals `"Until"`, `"Since"`, and `"All time"` are still hardcoded in English, which is inconsistent with the i18n goal of this PR. These labels should be translated alongside the date formatting.</comment>

<file context>
@@ -41,58 +41,62 @@ export function formatNumber(
 
   if (to) {
-    return `Until ${formatDateTime(to)}`;
+    return `Until ${formatDateTime(to, locale)}`;
   }
 
</file context>
Fix with Cubic

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 44 out of 66 changed files in this pull request and generated 5 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 17 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/unsubscribe/[token]/page.tsx">

<violation number="1" location="apps/status-page/src/app/(status-page)/[domain]/[locale]/(public)/unsubscribe/[token]/page.tsx:53">
P2: The `font-semibold` styling on `maskedEmail` and `pageName` is lost in this i18n conversion. The original code wrapped both values in `<span className="font-semibold">` for visual emphasis. Use `t.rich()` (or the equivalent rich text API in your setup) to preserve the bold formatting on interpolated values.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@mxkaske
Copy link
Member

mxkaske commented Mar 20, 2026

@claude grill me

@claude
Copy link

claude bot commented Mar 20, 2026

Claude Code is working…

I'll analyze this and get back to you.

View job run

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.

3 participants