From 9295b42a46e6196ed54b7c780a3ecdf7df1dcba1 Mon Sep 17 00:00:00 2001 From: Baivab Sarkar Date: Mon, 21 Sep 2026 02:27:20 +0530 Subject: [PATCH] fix(preview): preserve typography when switching languages --- desktop-app/resources/styles.css | 30 +-------- styles.css | 30 +-------- tests/e2e/localization-typography.spec.js | 79 +++++++++++++++++++++++ wiki/Localization.md | 2 +- 4 files changed, 84 insertions(+), 57 deletions(-) create mode 100644 tests/e2e/localization-typography.spec.js diff --git a/desktop-app/resources/styles.css b/desktop-app/resources/styles.css index 9b382a6c..61838c3c 100644 --- a/desktop-app/resources/styles.css +++ b/desktop-app/resources/styles.css @@ -1824,6 +1824,7 @@ body.document-sidebar-collapsed .document-sidebar { padding: 20px; } +/* Keep document typography independent of the selected interface language. */ .markdown-body { padding: 20px; width: 100%; @@ -9123,7 +9124,7 @@ button.live-share-participant-overflow { } /* ========================================================================== - Multilingual & CJK Optimization styles added by Aegis SEO agency + Language menu ========================================================================== */ .lang-select-item { display: flex !important; @@ -9146,33 +9147,6 @@ button.live-share-participant-overflow { font-weight: 500; } -/* Adjust CJK text layout for maximum readability inside the preview pane */ -html[lang="zh"] .markdown-body, -html[lang="ja"] .markdown-body, -html[lang="ko"] .markdown-body { - line-height: 1.75 !important; - letter-spacing: 0.03em; - word-break: keep-all; - overflow-wrap: break-word; - text-align: justify; -} - -/* Specific heading spacing improvements for CJK characters */ -html[lang="zh"] .markdown-body h1, -html[lang="zh"] .markdown-body h2, -html[lang="zh"] .markdown-body h3, -html[lang="ja"] .markdown-body h1, -html[lang="ja"] .markdown-body h2, -html[lang="ja"] .markdown-body h3, -html[lang="ko"] .markdown-body h1, -html[lang="ko"] .markdown-body h2, -html[lang="ko"] .markdown-body h3 { - font-weight: 700; - letter-spacing: 0.02em; - margin-top: 1.4em; - margin-bottom: 0.6em; -} - /* Consistent, position-safe menu motion. Popper owns transform; the individual translate/scale properties compose with it without disturbing placement. */ @keyframes app-menu-fade { diff --git a/styles.css b/styles.css index 9b382a6c..61838c3c 100644 --- a/styles.css +++ b/styles.css @@ -1824,6 +1824,7 @@ body.document-sidebar-collapsed .document-sidebar { padding: 20px; } +/* Keep document typography independent of the selected interface language. */ .markdown-body { padding: 20px; width: 100%; @@ -9123,7 +9124,7 @@ button.live-share-participant-overflow { } /* ========================================================================== - Multilingual & CJK Optimization styles added by Aegis SEO agency + Language menu ========================================================================== */ .lang-select-item { display: flex !important; @@ -9146,33 +9147,6 @@ button.live-share-participant-overflow { font-weight: 500; } -/* Adjust CJK text layout for maximum readability inside the preview pane */ -html[lang="zh"] .markdown-body, -html[lang="ja"] .markdown-body, -html[lang="ko"] .markdown-body { - line-height: 1.75 !important; - letter-spacing: 0.03em; - word-break: keep-all; - overflow-wrap: break-word; - text-align: justify; -} - -/* Specific heading spacing improvements for CJK characters */ -html[lang="zh"] .markdown-body h1, -html[lang="zh"] .markdown-body h2, -html[lang="zh"] .markdown-body h3, -html[lang="ja"] .markdown-body h1, -html[lang="ja"] .markdown-body h2, -html[lang="ja"] .markdown-body h3, -html[lang="ko"] .markdown-body h1, -html[lang="ko"] .markdown-body h2, -html[lang="ko"] .markdown-body h3 { - font-weight: 700; - letter-spacing: 0.02em; - margin-top: 1.4em; - margin-bottom: 0.6em; -} - /* Consistent, position-safe menu motion. Popper owns transform; the individual translate/scale properties compose with it without disturbing placement. */ @keyframes app-menu-fade { diff --git a/tests/e2e/localization-typography.spec.js b/tests/e2e/localization-typography.spec.js new file mode 100644 index 00000000..e9f089a9 --- /dev/null +++ b/tests/e2e/localization-typography.spec.js @@ -0,0 +1,79 @@ +const { test, expect } = require('@playwright/test'); +const { openApp, setEditorContent, waitForAppReady } = require('../helpers/app'); + +const markdown = `--- +title: Welcome to Markdown Viewer +description: Keep document typography consistent across interface languages. +tags: [markdown, live-preview] +--- + +# Welcome to Markdown Viewer + +Normal text with **bold**, *italic*, and a [link](https://example.com). + +## Key Features + +- Split-screen Markdown preview with consistent spacing. +- 日本語の文章と한국어 문장 remain readable alongside English. + +### Details + +| Feature | Description | +| --- | --- | +| Preview | The same document in every interface language. | +`; + +async function previewTypography(page) { + return page.locator('#markdown-preview').evaluate(preview => { + const properties = [ + 'fontFamily', 'fontSize', 'fontWeight', 'lineHeight', 'letterSpacing', + 'wordBreak', 'overflowWrap', 'textAlign', 'marginTop', 'marginBottom' + ]; + return [preview, ...preview.querySelectorAll('h1, h2, h3, p, li, th, td')].map(element => { + const style = getComputedStyle(element); + return Object.fromEntries(properties.map(property => [property, style[property]])); + }); + }); +} + +async function selectLanguage(page, language) { + await page.locator('.lang-select-item[data-lang="' + language + '"]').first() + .evaluate(element => element.click()); + await expect(page).toHaveURL(language === 'en' ? '/' : '/?lang=' + language); + await expect(page.locator('html')).toHaveAttribute('lang', language); +} + +for (const surface of ['document', 'release notes']) { + test(`${surface} typography stays consistent when Japanese and Korean are switched in either order`, async ({ page }) => { + await page.setViewportSize({ width: 1440, height: 900 }); + await openApp(page); + + if (surface === 'release notes') { + await page.locator('#header-about-button').click(); + await page.getByRole('button', { name: 'Show Release Notes' }).click(); + await expect(page.locator('#markdown-preview .release-note-shell')).toBeVisible(); + } else { + await setEditorContent(page, markdown); + await expect(page.locator('#markdown-preview').getByRole('heading', { name: 'Details', exact: true })).toBeVisible(); + await expect(page.locator('#markdown-preview')).toContainText('日本語の文章と한국어 문장'); + } + + const baseline = await previewTypography(page); + const text = await page.locator('#markdown-preview').textContent(); + + for (const language of ['ja', 'ko', 'en', 'ko', 'ja', 'en']) { + await selectLanguage(page, language); + expect(await previewTypography(page), `Typography after switching to ${language}`).toEqual(baseline); + await expect(page.locator('#markdown-preview')).toHaveText(text); + + if (surface === 'document') { + await expect(page.locator('#markdown-editor')).toHaveValue(markdown); + await page.reload(); + await waitForAppReady(page); + await expect(page.locator('#markdown-preview').getByRole('heading', { name: 'Details', exact: true })).toBeVisible(); + expect(await previewTypography(page), `Typography after reloading ${language}`).toEqual(baseline); + await expect(page.locator('#markdown-editor')).toHaveValue(markdown); + } + } + }); +} diff --git a/wiki/Localization.md b/wiki/Localization.md index 9014241b..8afc4571 100644 --- a/wiki/Localization.md +++ b/wiki/Localization.md @@ -48,7 +48,7 @@ The desktop app chooses a language in this order: 4. Browser language from `navigator.language`. 5. English fallback. -When a user picks a language from the dropdown, the app saves `app-lang` and updates the URL query parameter. +When a user picks a language from the dropdown, the app saves `app-lang` and updates the URL query parameter. Document previews and release notes keep the same typography, spacing, and alignment across interface languages, including Japanese and Korean. ## Public Search Content