Skip to content

feat: add translation status page#1485

Draft
userquin wants to merge 14 commits intonpmx-dev:mainfrom
userquin:fix-lunaria-html-report
Draft

feat: add translation status page#1485
userquin wants to merge 14 commits intonpmx-dev:mainfrom
userquin:fix-lunaria-html-report

Conversation

@userquin
Copy link
Member

@userquin userquin commented Feb 13, 2026

This PR adds a new page to replace https://i18n.npmx.dev/ and the lunaria/components.ts module that runs with build:lunaria.

This PR includes:

  • similar logic to lunaria/components.ts module but at npmx.dev
  • updates logic at useI18nStatus to replace array.find with map.get
  • adds links at app footer, mobile menu and settings (at the end of the lang section)
  • adds 2 new scripts to run and start lunaria dev server (lunaria/components.ts module generates an html): run:lunaria and start:lunaria=> both scripts and lunaria/components.ts module can be removed later.
  • includes Spanish translations

I have no idea where is the logic to extract outdated logic, maybe we move the logic when we add i18n:check* scripts.

DON'T MERGE YET: I need to fix hydration missmatch errors.

Context:

  • entries per locale are translated using the target locale, using dir="rtl" when required (we can use dir="auto" but then rtl-flip won't work, check RTL Support at CONTRIBUTING.md).
  • entries per file will use current locale to display the data
  • using $n(<file|entry>.percentComplete / 100, 'percentage', <file|entry>.lang) to allow Intl add the percentage symbol (some locales using space between the percertange and the % symbol: percentage is defined at numberFormats (config/i18n.ts)

@vercel
Copy link

vercel bot commented Feb 13, 2026

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

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Feb 14, 2026 0:27am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Feb 14, 2026 0:27am
npmx-lunaria Ignored Ignored Feb 14, 2026 0:27am

Request Review

@github-actions
Copy link

github-actions bot commented Feb 13, 2026

Lunaria Status Overview

🌕 This pull request will trigger status changes.

Learn more

By default, every PR changing files present in the Lunaria configuration's files property will be considered and trigger status changes accordingly.

You can change this by adding one of the keywords present in the ignoreKeywords property in your Lunaria configuration file in the PR's title (ignoring all files) or by including a tracker directive in the merged commit's description.

Tracked Files

File Note
lunaria/files/en-GB.json Localization changed, will be marked as complete. 🔄️
lunaria/files/en-US.json Source changed, localizations will be marked as outdated.
lunaria/files/es-419.json Localization changed, will be marked as complete. 🔄️
lunaria/files/es-ES.json Localization changed, will be marked as complete. 🔄️
Warnings reference
Icon Description
🔄️ The source for this localization has been updated since the creation of this pull request, make sure all changes in the source have been applied.

@codecov
Copy link

codecov bot commented Feb 13, 2026

Codecov Report

❌ Patch coverage is 14.28571% with 6 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
app/composables/useI18nStatus.ts 0.00% 4 Missing and 1 partial ⚠️
app/pages/settings.vue 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 13, 2026

📝 Walkthrough

Walkthrough

Adds a translation status feature: a new page at /translation-status (app/pages/translation-status.vue) showing translation progress by locale and by file; adds navigation links in AppFooter, AppHeader (mobile), and Settings; introduces translation_status strings across i18n locale files and schema; updates useI18nStatus to expose a localesMap and change lookup; extends shared I18nStatus.sourceLocale with totalKeys; adds a prerender routeRule for /translation-status; updates canonical-redirects allowlist; adds two npm scripts for serving Lunaria.

Possibly related PRs

Suggested reviewers

  • danielroe
  • shuuji3
  • mrcego
🚥 Pre-merge checks | ✅ 1 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (24 files):

⚔️ app/components/AppFooter.vue (content)
⚔️ app/components/AppHeader.vue (content)
⚔️ app/components/Package/TrendsChart.vue (content)
⚔️ app/components/Package/WeeklyDownloadStats.vue (content)
⚔️ app/composables/useCharts.ts (content)
⚔️ app/composables/useI18nStatus.ts (content)
⚔️ app/pages/compare.vue (content)
⚔️ app/pages/package/[[org]]/[name].vue (content)
⚔️ app/pages/settings.vue (content)
⚔️ i18n/locales/en-GB.json (content)
⚔️ i18n/locales/en.json (content)
⚔️ i18n/locales/es-419.json (content)
⚔️ i18n/locales/es.json (content)
⚔️ i18n/schema.json (content)
⚔️ lunaria/files/en-GB.json (content)
⚔️ lunaria/files/en-US.json (content)
⚔️ lunaria/files/es-419.json (content)
⚔️ lunaria/files/es-ES.json (content)
⚔️ lunaria/lunaria.ts (content)
⚔️ modules/runtime/server/cache.ts (content)
⚔️ nuxt.config.ts (content)
⚔️ package.json (content)
⚔️ server/middleware/canonical-redirects.global.ts (content)
⚔️ shared/types/i18n-status.ts (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description clearly relates to the changeset, detailing the addition of a translation status page, updates to useI18nStatus, new navigation links, and new npm scripts for the Lunaria dev server.

✏️ 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
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch fix-lunaria-html-report
  • Post resolved changes as copyable diffs in a comment

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Comment on lines +91 to +99
<button
type="button"
class="cursor-pointer inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70 shrink-0"
@click="router.back()"
v-if="canGoBack"
>
<span class="i-lucide:arrow-left icon-rtl w-4 h-4" aria-hidden="true" />
<span class="sr-only sm:not-sr-only">{{ $t('nav.back') }}</span>
</button>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Avoid per-button focus-visible utilities; rely on the global rule.

focus-visible:outline-accent/70 is applied on button elements here, but the project’s global CSS already defines button focus-visible styling; please remove the per-element utility class to keep the behaviour consistent.

Proposed fix
-            class="cursor-pointer inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70 shrink-0"
+            class="cursor-pointer inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-colors duration-200 rounded shrink-0"
-                    class="text-xs text-accent hover:underline rounded focus-visible:outline-accent/70"
+                    class="text-xs text-accent hover:underline rounded"

Based on learnings: “In the npmx.dev project, ensure that focus-visible styling for button and select elements is implemented globally in app/assets/main.css … Do not apply per-element inline utility classes like focus-visible:outline-accent/70 on these elements in Vue templates or components.”

Also applies to: 259-269

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Comment on lines +255 to +258
<div class="flex items-center justify-between mb-2">
<p class="text-sm font-medium">
{{ $t('translation_status.missing_keys', {}, { locale: localeEntry.lang }) }}
</p>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n app/pages/translation-status.vue | sed -n '240,270p'

Repository: npmx-dev/npmx.dev

Length of output: 1618


🏁 Script executed:

rg "localeEntry" app/pages/translation-status.vue -A 3 -B 3

Repository: npmx-dev/npmx.dev

Length of output: 5562


🏁 Script executed:

fd -e json -e ts -e js -path "*locales*" | head -20

Repository: npmx-dev/npmx.dev

Length of output: 229


🏁 Script executed:

rg "missing_keys" --type json

Repository: npmx-dev/npmx.dev

Length of output: 6195


🏁 Script executed:

rg '\$t\([^,]+,\s*\{\s*count:' --type vue --type ts

Repository: npmx-dev/npmx.dev

Length of output: 88


🏁 Script executed:

wc -l app/pages/translation-status.vue

Repository: npmx-dev/npmx.dev

Length of output: 97


🏁 Script executed:

cat package.json | grep -A 5 -B 5 "@nuxtjs/i18n"

Repository: npmx-dev/npmx.dev

Length of output: 422


🏁 Script executed:

rg '\$t\([^,]+,\s*{[^}]*count' app/ -A 1 -B 1

Repository: npmx-dev/npmx.dev

Length of output: 183


🌐 Web query:

nuxtjs/i18n v10 pluralization count parameter $t function

💡 Result:

In @nuxtjs/i18n v10, pluralization is done via $t / t (because $tc / tc is removed after the Vue I18n upgrade). Use the count as the 2nd argument to $t. [1]

messages

// en.json (or messages object)
{
  "apple": "no apples | one apple | {count} apples"
}

template / code

{{ $t('apple', count) }}                 <!-- plural selection; {count} is implicit -->
{{ $t('apple', count, { count }) }}      <!-- if you want to pass it explicitly -->

So, the “pluralization count parameter” is the 2nd parameter to $t('key', count, ...). [2]

Sources: Nuxt i18n v10 migration (Vue I18n upgrade, $tc removed) [1], Vue I18n pluralization examples showing $t(key, plural) and optional {count} options [2].


🏁 Script executed:

cat i18n/schema.json | grep -A 10 "missing_keys"

Repository: npmx-dev/npmx.dev

Length of output: 566


🏁 Script executed:

rg "type FileEntryStatus" app/ -A 15

Repository: npmx-dev/npmx.dev

Length of output: 43


🏁 Script executed:

sed -n '1,100p' app/pages/translation-status.vue | tail -50

Repository: npmx-dev/npmx.dev

Length of output: 1681


🏁 Script executed:

rg '\$t\([^,]+,\s*[^{][^,]*,\s*\{' app/ --type ts --type vue -B 1 -A 1 | head -40

Repository: npmx-dev/npmx.dev

Length of output: 88


🏁 Script executed:

sed -n '1,150p' app/pages/translation-status.vue | grep -A 30 "type FileEntryStatus"

Repository: npmx-dev/npmx.dev

Length of output: 43


🌐 Web query:

vue-i18n v10 $t function signature pluralization second parameter

💡 Result:

In vue-i18n v10, $t / t are overloaded. For pluralization, the 2nd parameter can be a number:

  • Plural only: t(key, plural)

    • Example: $t('car', 1), $t('car', 2) (2nd arg is the plural choice number). [1][2]
  • Plural + options (recommended/clear): t(key, plural, options) where options can include named, list, etc.

    • Example: $t('apple', 10, { named: { count: 10 } }). [1][2][5]
  • Plural + named (alternate overload also supported in v10): t(key, named, plural)

    • Example: $t('apple', { count: 10 }, 10). [3][4]

Also, v10 legacy mode uses the same overload signatures as composition mode, so don’t use the old “locale as 2nd argument” signatures anymore. [4]


🏁 Script executed:

rg '\$t\(['\''"][^'\''"]+'\'',\s*[a-zA-Z0-9]+\s*[,\)]' app/ -A 1 -B 1 | head -30

Repository: npmx-dev/npmx.dev

Length of output: 43


🏁 Script executed:

sed -n '255,275p' app/pages/translation-status.vue

Repository: npmx-dev/npmx.dev

Length of output: 1048


Pass the missing count so plural forms resolve correctly.

The key has plural variants but the count is not provided, preventing correct variant selection. localeEntry.missing is available and should be passed to the $t function.

🛠️ Suggested fix
-                    {{ $t('translation_status.missing_keys', {}, { locale: localeEntry.lang }) }}
+                    {{
+                      $t(
+                        'translation_status.missing_keys',
+                        { count: localeEntry.missing },
+                        { locale: localeEntry.lang },
+                      )
+                    }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div class="flex items-center justify-between mb-2">
<p class="text-sm font-medium">
{{ $t('translation_status.missing_keys', {}, { locale: localeEntry.lang }) }}
</p>
<div class="flex items-center justify-between mb-2">
<p class="text-sm font-medium">
{{
$t(
'translation_status.missing_keys',
{ count: localeEntry.missing },
{ locale: localeEntry.lang },
)
}}
</p>

Comment on lines +1148 to +1155
"missing_keys": "There is no missing translations | Missing translation | Missing translations",
"progress_label": "Progress status for {locale}",
"table": {
"file": "File",
"status": "Status",
"error": "Error while loading file list.",
"loading": "{spinner} Loading translation files...",
"empty": "No files found",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Tighten the loading/missing copy to avoid grammar issues and placeholder leakage.

translation_status.missing_keys reads ungrammatically, and translation_status.table.loading includes a {spinner} placeholder that isn’t populated in the UI.

📝 Suggested copy tweaks
-    "missing_keys": "There is no missing translations | Missing translation | Missing translations",
+    "missing_keys": "No missing translations | Missing translation | Missing translations",
-    "loading": "{spinner} Loading translation files...",
+    "loading": "Loading translation files...",
📝 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
"missing_keys": "There is no missing translations | Missing translation | Missing translations",
"progress_label": "Progress status for {locale}",
"table": {
"file": "File",
"status": "Status",
"error": "Error while loading file list.",
"loading": "{spinner} Loading translation files...",
"empty": "No files found",
"missing_keys": "No missing translations | Missing translation | Missing translations",
"progress_label": "Progress status for {locale}",
"table": {
"file": "File",
"status": "Status",
"error": "Error while loading file list.",
"loading": "Loading translation files...",
"empty": "No files found",

Comment on lines +1138 to +1147
"p1_count": "0 messages | 1 message |{count} messages",
"p2": "Before starting, please read our {guide} to learn about our translation process and how you can get involved.",
"guide": "localization (i18n) guide",
"by_locale": "Translation progress by locale",
"by_file": "Translation progress by file",
"locale_summary": "{name} ({id})",
"complete_text": "This translation is complete, amazing job!",
"done_text": "done",
"missing_text": "missing",
"missing_keys": "There is no missing translations | Missing translation | Missing translations",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix plural copy and spacing in translation counts.

There’s a missing space before {count} and the first plural form reads awkwardly.

📝 Suggested fix
-    "p1_count": "0 messages | 1 message |{count} messages",
+    "p1_count": "0 messages | 1 message | {count} messages",
-    "missing_keys": "There is no missing translations | Missing translation | Missing translations",
+    "missing_keys": "There are no missing translations | Missing translation | Missing translations",
📝 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
"p1_count": "0 messages | 1 message |{count} messages",
"p2": "Before starting, please read our {guide} to learn about our translation process and how you can get involved.",
"guide": "localization (i18n) guide",
"by_locale": "Translation progress by locale",
"by_file": "Translation progress by file",
"locale_summary": "{name} ({id})",
"complete_text": "This translation is complete, amazing job!",
"done_text": "done",
"missing_text": "missing",
"missing_keys": "There is no missing translations | Missing translation | Missing translations",
"p1_count": "0 messages | 1 message | {count} messages",
"p2": "Before starting, please read our {guide} to learn about our translation process and how you can get involved.",
"guide": "localization (i18n) guide",
"by_locale": "Translation progress by locale",
"by_file": "Translation progress by file",
"locale_summary": "{name} ({id})",
"complete_text": "This translation is complete, amazing job!",
"done_text": "done",
"missing_text": "missing",
"missing_keys": "There are no missing translations | Missing translation | Missing translations",

@ghostdevv ghostdevv marked this pull request as draft February 14, 2026 01:57
@ghostdevv
Copy link
Contributor

will mark as draft while you're working on it 🙏

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants