chore: safety checks mixed-language installations

This commit is contained in:
2026-02-21 13:53:55 +01:00
parent f8e532fbf5
commit d651049659
2 changed files with 78 additions and 0 deletions

View File

@@ -3,6 +3,7 @@ import { mkdtemp, readFile, rm, readdir, stat } from 'node:fs/promises';
import path from 'node:path'; import path from 'node:path';
import { tmpdir } from 'node:os'; import { tmpdir } from 'node:os';
import type { PostData } from '../../src/main/engine/PostEngine'; import type { PostData } from '../../src/main/engine/PostEngine';
import { resolveUiLanguageFromSystemLocale } from '../../src/main/shared/i18n';
const generatedFileHashes = new Map<string, string>(); const generatedFileHashes = new Map<string, string>();
const getGeneratedFileHashMock = vi.fn(async (projectId: string, relativePath: string) => { const getGeneratedFileHashMock = vi.fn(async (projectId: string, relativePath: string) => {
@@ -365,6 +366,25 @@ describe('BlogGenerationEngine', () => {
expect(await fileExists(path.join(tempDir, 'html', '2025', '02', '20', 'index.html'))).toBe(true); expect(await fileExists(path.join(tempDir, 'html', '2025', '02', '20', 'index.html'))).toBe(true);
}); });
it('keeps static render language from project settings when ui language differs', async () => {
const uiLanguage = resolveUiLanguageFromSystemLocale('de-DE');
expect(uiLanguage).toBe('de');
const posts = [
makePost({ id: 'fr-1', slug: 'fr-1', title: 'FR 1', createdAt: new Date('2020-02-15T10:00:00Z') }),
makePost({ id: 'fr-2', slug: 'fr-2', title: 'FR 2', createdAt: new Date('2020-02-14T10:00:00Z') }),
];
await generate(posts, { language: 'fr', maxPostsPerPage: 50 });
const monthArchivePath = path.join(tempDir, 'html', '2020', '02', 'index.html');
const monthHtml = await readFile(monthArchivePath, 'utf-8');
expect(monthHtml).toContain('<html lang="fr">');
expect(monthHtml).toContain('<h1 class="archive-heading">Archives février 2020</h1>');
expect(monthHtml).not.toContain('<h1 class="archive-heading">Archiv Februar 2020</h1>');
});
it('excludes draft-only posts from generated pages', async () => { it('excludes draft-only posts from generated pages', async () => {
const posts = [ const posts = [
makePost({ id: '1', slug: 'published', title: 'Published', status: 'published' }), makePost({ id: '1', slug: 'published', title: 'Published', status: 'published' }),

View File

@@ -4,6 +4,7 @@ import path from 'node:path';
import { tmpdir } from 'node:os'; import { tmpdir } from 'node:os';
import type { PostData, PostFilter } from '../../src/main/engine/PostEngine'; import type { PostData, PostFilter } from '../../src/main/engine/PostEngine';
import { PreviewServer } from '../../src/main/engine/PreviewServer'; import { PreviewServer } from '../../src/main/engine/PreviewServer';
import { resolveUiLanguageFromSystemLocale } from '../../src/main/shared/i18n';
type PostEngineLike = { type PostEngineLike = {
getPostsFiltered: (filter: PostFilter) => Promise<PostData[]>; getPostsFiltered: (filter: PostFilter) => Promise<PostData[]>;
@@ -607,6 +608,63 @@ describe('PreviewServer', () => {
expect(monthPageHtml).toContain('<h1 class="archive-heading">Archive February 2020</h1>'); expect(monthPageHtml).toContain('<h1 class="archive-heading">Archive February 2020</h1>');
}); });
it('uses project mainLanguage for translated archive heading text', async () => {
const posts = [
makePost({ id: 'fr-1', slug: 'fr-1', title: 'FR1', content: 'Body 1', createdAt: new Date('2020-02-05T10:00:00.000Z') }),
makePost({ id: 'fr-2', slug: 'fr-2', title: 'FR2', content: 'Body 2', createdAt: new Date('2020-02-04T10:00:00.000Z') }),
];
server = new PreviewServer({
postEngine: makeEngine(posts),
settingsEngine: {
setProjectContext: vi.fn(),
async getProjectMetadata() {
return {
mainLanguage: 'fr',
maxPostsPerPage: 50,
};
},
},
getActiveProjectContext: async () => ({ projectId: 'default' }),
});
await server.start(0);
const monthPageHtml = await (await fetch(`${server.getBaseUrl()}/2020/2/`)).text();
expect(monthPageHtml).toContain('<h1 class="archive-heading">Archives février 2020</h1>');
});
it('keeps preview render language from project settings when ui language differs', async () => {
const uiLanguage = resolveUiLanguageFromSystemLocale('de-DE');
expect(uiLanguage).toBe('de');
const posts = [
makePost({ id: 'mixed-1', slug: 'mixed-1', title: 'Mixed 1', content: 'Body 1', createdAt: new Date('2020-02-05T10:00:00.000Z') }),
makePost({ id: 'mixed-2', slug: 'mixed-2', title: 'Mixed 2', content: 'Body 2', createdAt: new Date('2020-02-04T10:00:00.000Z') }),
];
server = new PreviewServer({
postEngine: makeEngine(posts),
settingsEngine: {
setProjectContext: vi.fn(),
async getProjectMetadata() {
return {
mainLanguage: 'fr',
maxPostsPerPage: 50,
};
},
},
getActiveProjectContext: async () => ({ projectId: 'default' }),
});
await server.start(0);
const monthPageHtml = await (await fetch(`${server.getBaseUrl()}/2020/2/`)).text();
expect(monthPageHtml).toContain('<html lang="fr">');
expect(monthPageHtml).toContain('<h1 class="archive-heading">Archives février 2020</h1>');
expect(monthPageHtml).not.toContain('<h1 class="archive-heading">Archiv Februar 2020</h1>');
});
it('renders tag heading on first page and adds date range on later pages', async () => { it('renders tag heading on first page and adds date range on later pages', async () => {
const posts = [ const posts = [
makePost({ id: 't-1', slug: 't-1', title: 'T1', content: 'Body 1', tags: ['dev'], createdAt: new Date('2020-02-05T10:00:00.000Z') }), makePost({ id: 't-1', slug: 't-1', title: 'T1', content: 'Body 1', tags: ['dev'], createdAt: new Date('2020-02-05T10:00:00.000Z') }),