Skip to content

fix(admin): use import.meta.glob for locale catalog resolution#499

Merged
ascorbic merged 4 commits intomainfrom
fix/admin-locale-resolution
Apr 12, 2026
Merged

fix(admin): use import.meta.glob for locale catalog resolution#499
ascorbic merged 4 commits intomainfrom
fix/admin-locale-resolution

Conversation

@ascorbic
Copy link
Copy Markdown
Collaborator

What does this PR do?

Fixes admin failing to load when emdash is installed from npm (non-monorepo). The dynamic import() in admin.astro used a template literal to load locale catalogs cross-package (@emdash-cms/admin/locales/${locale}/messages.mjs), which Vite's SSR module runner couldn't resolve.

The Vite alias entry intended to handle this used * in the find string, but Vite treats that as a literal character — so the alias was a no-op.

Moves locale loading into the admin package via a loadMessages() function that uses import.meta.glob to discover catalogs at build time with reliable relative paths.

Type of change

  • Bug fix

Checklist

AI-generated code disclosure

  • This PR includes AI-generated code

Screenshots / test output

Locale unit tests pass:

✓ chromium tests/lib/locales.test.ts (3 tests) 9ms

The dynamic import in admin.astro used a template literal to load locale
catalogs cross-package, which failed in non-monorepo installs because
Vite's SSR module runner couldn't resolve the path. The Vite alias entry
intended to fix this used `*` in the find string, which is treated as a
literal character, not a wildcard.

Moves locale loading into the admin package via `loadMessages()` using
`import.meta.glob`, so Vite resolves catalogs at build time with
reliable relative paths. Removes the no-op Vite alias.
Copilot AI review requested due to automatic review settings April 12, 2026 20:41
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 12, 2026

🦋 Changeset detected

Latest commit: 4af062a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
emdash Patch
@emdash-cms/admin Patch
@emdash-cms/cloudflare Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
create-emdash Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages bot commented Apr 12, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-playground 4af062a Apr 12 2026, 09:04 PM

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 12, 2026

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@499

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@499

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@499

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@499

emdash

npm i https://pkg.pr.new/emdash@499

create-emdash

npm i https://pkg.pr.new/create-emdash@499

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@499

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@499

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@499

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@499

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@499

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@499

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@499

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@499

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@499

commit: 4af062a

Copy link
Copy Markdown
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

Fixes admin SSR locale catalog resolution when emdash / @emdash-cms/admin are consumed from npm (non-monorepo) by moving locale catalog loading behind a stable API in the admin package.

Changes:

  • Replace cross-package dynamic import() of locale catalogs in admin.astro with loadMessages() from @emdash-cms/admin/locales.
  • Remove the ineffective Vite alias that attempted to match @emdash-cms/admin/locales/*.
  • Add loadMessages() implementation using import.meta.glob, plus a small test and a changeset.

Reviewed changes

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

Show a summary per file
File Description
packages/core/src/astro/routes/admin.astro Switches admin SSR route to call loadMessages() instead of dynamic importing catalogs via a template literal.
packages/core/src/astro/integration/vite-config.ts Removes the prior *-based locale alias that didn’t work in Vite.
packages/admin/src/locales/index.ts Introduces loadMessages() backed by import.meta.glob for build-time catalog discovery.
packages/admin/tests/lib/locales.test.ts Adds tests asserting catalogs load for supported locales and fallback behavior.
.changeset/rich-drinks-hug.md Publishes patch releases for emdash and @emdash-cms/admin documenting the fix.

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

Comment on lines 288 to 297
resolve: {
dedupe: ["@emdash-cms/admin", "react", "react-dom"],
// Array form so more-specific entries are checked first.
// The styles.css alias must come before the package alias, otherwise
// Vite's prefix matching on "@emdash-cms/admin" would resolve
// "@emdash-cms/admin/styles.css" through the source directory.
alias: [
{ find: "@emdash-cms/admin/styles.css", replacement: resolve(adminDistPath, "styles.css") },
{
find: "@emdash-cms/admin/locales/*",
replacement: resolve(adminDistPath, "locales", "*"),
},
{ find: "@emdash-cms/admin", replacement: useSource ? adminSourcePath : adminDistPath },
],
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

loadMessages() now relies on import.meta.glob("./**/messages.mjs") inside @emdash-cms/admin/locales. When core aliases @emdash-cms/admin to the admin source directory in dev (HMR mode), src/locales/*/messages.mjs typically doesn't exist (only messages.po), and the existing linguiMacroPlugin only rewrites explicit ./xx/messages.mjs imports (not import.meta.glob). This means the admin route can crash in monorepo dev unless lingui compile has been run.

Consider adding a more-specific Vite alias for @emdash-cms/admin/locales (and optionally /locales/) to always resolve to dist/locales (similar to the existing styles.css alias), or otherwise ensure the glob resolves against the compiled catalogs.

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +17
const LOCALE_LOADERS = import.meta.glob<{ messages: Record<string, unknown> }>("./**/messages.mjs");

export async function loadMessages(locale: string): Promise<Record<string, unknown>> {
const key = `./${locale}/messages.mjs`;
const loader = LOCALE_LOADERS[key] ?? LOCALE_LOADERS["./en/messages.mjs"]!;
const { messages } = await loader();
return messages;
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

loadMessages() hard-codes the fallback key to ./en/messages.mjs instead of using DEFAULT_LOCALE. If the default locale ever changes, this function will silently diverge from the single source of truth in config.ts.

Also, if catalogs haven’t been compiled yet, LOCALE_LOADERS["./en/messages.mjs"] will be undefined and the current code will fail with a generic "loader is not a function" error. Consider using DEFAULT_LOCALE for the fallback key and throwing a clear error when neither the requested locale nor the fallback catalog exists (e.g., instructing to run lingui compile).

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +11
import { expect, test } from "vitest";

import { loadMessages, SUPPORTED_LOCALES } from "../../src/locales/index.js";

for (const { code } of SUPPORTED_LOCALES) {
test(`loadMessages resolves catalog for supported locale "${code}"`, async () => {
const messages = await loadMessages(code);
expect(messages).toBeDefined();
expect(typeof messages).toBe("object");
expect(Object.keys(messages).length).toBeGreaterThan(0);
});
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

This test calls loadMessages() from src/locales/index.js, which depends on compiled messages.mjs catalogs existing on disk. Since the @emdash-cms/admin test script doesn’t run locale:compile (and messages.mjs files are gitignored), pnpm --filter @emdash-cms/admin test will fail on a clean checkout unless a build/compile step was run beforehand.

To keep tests self-contained, consider ensuring lingui compile runs before tests (e.g., via a pretest script) or having the test explicitly generate/fixture the catalogs it expects.

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +14
const LOCALE_LOADERS = import.meta.glob<{ messages: Record<string, unknown> }>("./**/messages.mjs");

export async function loadMessages(locale: string): Promise<Record<string, unknown>> {
const key = `./${locale}/messages.mjs`;
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

The messages payload coming from Lingui catalogs is typed as Record<string, unknown> here, but downstream (e.g., AdminAppProps.messages and core’s AdminWrapperProps.messages) uses @lingui/core’s Messages type. Using Messages for import.meta.glob’s module type and loadMessages()’s return type would improve type safety and keep the locale API consistent across packages.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Done in b49155a. The changes applied:

  • import.meta.glob now uses Messages from @lingui/core as the module type
  • loadMessages() return type changed from Promise<Record<string, unknown>> to Promise<Messages>
  • Fallback key uses DEFAULT_LOCALE instead of the hardcoded "./en/messages.mjs" string
  • Added a clear error when neither the requested locale nor the fallback catalog is found (e.g., if pnpm locale:compile hasn't been run)

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 12, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • pkg.pr.new
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/actions-REDACTED/cached/externals/node24/lib/node_modules/corepack/shims/../dist/pnpm.js install --frozen-lockfile (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@github-actions
Copy link
Copy Markdown
Contributor


Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution. You can sign the CLA by just posting a Pull Request Comment same as the below format.


I have read the CLA Document and I hereby sign the CLA


1 out of 2 committers have signed the CLA.
✅ (ascorbic)[https://github.com/ascorbic]
@copilot
You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@github-actions github-actions bot added size/M and removed size/S labels Apr 12, 2026
@ascorbic ascorbic merged commit 0b4e61b into main Apr 12, 2026
28 of 29 checks passed
@ascorbic ascorbic deleted the fix/admin-locale-resolution branch April 12, 2026 21:10
@emdashbot emdashbot bot mentioned this pull request Apr 12, 2026
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.

3 participants