Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4307,7 +4307,7 @@
"title": "VendureDashboardPlugin",
"slug": "vendure-dashboard-plugin",
"file": "docs/reference/dashboard/vite-plugin/vendure-dashboard-plugin.mdx",
"lastModified": "2026-07-29T16:21:34+02:00"
"lastModified": "2026-07-30T10:08:40+02:00"
}
],
"lastModified": "2026-01-28T14:49:21+01:00"
Expand Down Expand Up @@ -5251,4 +5251,4 @@
"branch": "master",
"docsPath": "docs"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { i18n } from '@lingui/core';
import { act } from 'react';
import { createRoot } from 'react-dom/client';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

import { defaultLocale } from '../../providers/i18n-provider.js';
import { useDashboardExtensions } from './use-dashboard-extensions.js';

const runDashboardExtensions = vi.hoisted(() => vi.fn());

(globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true;

vi.mock('virtual:dashboard-extensions', () => ({
runDashboardExtensions,
}));

vi.mock('./define-dashboard-extension.js', () => ({
onExtensionSourceChange: vi.fn(),
}));

describe('useDashboardExtensions', () => {
let container: HTMLDivElement;
let root: ReturnType<typeof createRoot>;

beforeEach(() => {
container = document.createElement('div');
document.body.appendChild(container);
root = createRoot(container);
});

afterEach(async () => {
await act(async () => {
root.unmount();
});
container.remove();
vi.clearAllMocks();
});

it('can evaluate translations before the full locale catalog has loaded', async () => {
let extensionError: unknown;

runDashboardExtensions.mockImplementation(async () => {
try {
const extensionMessageId = ['Extension', 'label'].join(' ');
i18n._(extensionMessageId);
} catch (error) {
extensionError = error;
}
});

function DashboardBootstrap() {
useDashboardExtensions();
return null;
}

await act(async () => {
root.render(<DashboardBootstrap />);
});

expect(runDashboardExtensions).toHaveBeenCalledOnce();
expect(i18n.locale).toBe(defaultLocale);
expect(extensionError).toBeUndefined();
});
});
7 changes: 7 additions & 0 deletions packages/dashboard/src/lib/providers/i18n-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import React from 'react';

export const defaultLocale = 'en';

// Dashboard extensions are evaluated asynchronously during app bootstrap and
// may translate source-locale strings at module scope. Activate an empty source
// catalog synchronously so those translations are safe while the compiled
// dashboard and plugin catalogs load in parallel.
i18n.load(defaultLocale, {});
i18n.activate(defaultLocale);

/**
* We do a dynamic import of just the catalog that we need
* @param locale any locale string
Expand Down
Loading