feat(legal): bilingual (RU + EN) legal pages with a language + theme switcher
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 21s
CI / ui (pull_request) Successful in 1m14s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m48s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 21s
CI / ui (pull_request) Successful in 1m14s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m48s
Add English versions of the privacy policy, EULA and offer (ui/legal/*_en.md) and render each legal page as one self-contained bilingual document: both language bodies plus a header language toggle and theme toggle (no back), a small inline ES5 script that switches language client-side (no reload, default Russian + persisted) and applies the theme (system default + persisted override) — mirroring the landing. The offer's English view transliterates the Russian product names spliced from the live catalog. renderLegalHtml now takes both language sources; renderOffer splices the price list into both; the renderer bakes and reads the _en sources and pre-renders the static pages at boot. Also wrap the /offer/ contour probe in the same retry+timeout as the legal probe (the offer page is now bilingual and larger). Docs + renderer/ui tests updated.
This commit is contained in:
+42
-32
@@ -1,52 +1,62 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { renderOfferHtml, renderLegalHtml } from './offer';
|
||||
|
||||
describe('renderOfferHtml', () => {
|
||||
it('wraps rendered markdown in a standalone Russian HTML document', () => {
|
||||
const html = renderOfferHtml('# Публичная оферта\n\nо заключении договора купли-продажи');
|
||||
expect(html).toContain('<!doctype html>');
|
||||
expect(html).toContain('lang="ru"');
|
||||
expect(html).toContain('<title>Публичная оферта — Эрудит</title>');
|
||||
// The markdown heading is rendered, not left as literal source.
|
||||
expect(html).toContain('<h1>Публичная оферта</h1>');
|
||||
expect(html).not.toContain('# Публичная оферта');
|
||||
// No in-page navigation: the standalone offer carries no "back" link.
|
||||
expect(html).not.toContain('class="back"');
|
||||
});
|
||||
|
||||
it('renders headings, bold clause numbers and lists', () => {
|
||||
const html = renderOfferHtml('## 2. Предмет\n\n**2.1.** Текст пункта.\n\n- первый\n- второй');
|
||||
expect(html).toContain('<h2>2. Предмет</h2>');
|
||||
expect(html).toContain('<strong>2.1.</strong>');
|
||||
expect(html).toContain('<li>первый</li>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('renderLegalHtml', () => {
|
||||
it('applies the given title and canonical URL to the shared chrome', () => {
|
||||
const html = renderLegalHtml('# Политика конфиденциальности\n\nтекст', {
|
||||
title: 'Политика конфиденциальности — Эрудит',
|
||||
it('renders both language bodies into one standalone document with a switcher', () => {
|
||||
const html = renderLegalHtml({
|
||||
ru: { md: '# Политика\n\nрусский текст', title: 'Политика — Эрудит' },
|
||||
en: { md: '# Policy\n\nenglish text', title: 'Policy — Erudit' },
|
||||
canonical: 'https://erudit-game.ru/privacy/',
|
||||
});
|
||||
expect(html).toContain('<!doctype html>');
|
||||
expect(html).toContain('<title>Политика конфиденциальности — Эрудит</title>');
|
||||
expect(html).toContain('<title>Политика — Эрудит</title>'); // Russian is the default
|
||||
expect(html).toContain('href="https://erudit-game.ru/privacy/"');
|
||||
expect(html).toContain('<h1>Политика конфиденциальности</h1>');
|
||||
// Both bodies are present; English is hidden until toggled.
|
||||
expect(html).toContain('<main data-lang="ru">');
|
||||
expect(html).toContain('<main data-lang="en" hidden>');
|
||||
expect(html).toContain('<h1>Политика</h1>');
|
||||
expect(html).toContain('<h1>Policy</h1>');
|
||||
// The language + theme switcher and its script.
|
||||
expect(html).toContain('id="legal-lang"');
|
||||
expect(html).toContain('id="legal-theme"');
|
||||
expect(html).toContain('erudit.legal.lang');
|
||||
// Titles carried on <html> so the toggle can update document.title.
|
||||
expect(html).toContain('data-title-ru="Политика — Эрудит"');
|
||||
expect(html).toContain('data-title-en="Policy — Erudit"');
|
||||
});
|
||||
|
||||
it('renderOfferHtml is the offer preset over it', () => {
|
||||
const html = renderOfferHtml('# Публичная оферта');
|
||||
expect(html).toContain('<title>Публичная оферта — Эрудит</title>');
|
||||
expect(html).toContain('href="https://erudit-game.ru/offer/"');
|
||||
it('renders markdown headings, bold clause numbers and lists in both languages', () => {
|
||||
const html = renderLegalHtml({
|
||||
ru: { md: '## 2. Предмет\n\n**2.1.** Текст.\n\n- первый\n- второй', title: 't' },
|
||||
en: { md: '## 2. Subject\n\n**2.1.** Text.', title: 't' },
|
||||
canonical: 'c',
|
||||
});
|
||||
expect(html).toContain('<h2>2. Предмет</h2>');
|
||||
expect(html).toContain('<strong>2.1.</strong>');
|
||||
expect(html).toContain('<li>первый</li>');
|
||||
expect(html).toContain('<h2>2. Subject</h2>');
|
||||
});
|
||||
|
||||
it('scopes the shrink-to-fit first-column table rule to the offer only', () => {
|
||||
// The offer opts into the nowrap product-name column via body.offer; other legal pages (the
|
||||
// privacy data table) must NOT get it, or their prose first column cannot wrap.
|
||||
expect(renderOfferHtml('# x')).toContain('<body class="offer">');
|
||||
const generic = renderLegalHtml('# x', { title: 't', canonical: 'c' });
|
||||
const generic = renderLegalHtml({ ru: { md: '# x', title: 't' }, en: { md: '# x', title: 't' }, canonical: 'c' });
|
||||
expect(generic).toContain('<body>');
|
||||
expect(generic).not.toContain('<body class=');
|
||||
expect(generic).toContain('.offer td:first-child');
|
||||
});
|
||||
});
|
||||
|
||||
describe('renderOfferHtml', () => {
|
||||
it('is the offer preset: both languages, body.offer, offer title + canonical, EN transliteration', () => {
|
||||
const html = renderOfferHtml('# Публичная оферта\n\nрусский', '# Public offer\n\nenglish');
|
||||
expect(html).toContain('<body class="offer">');
|
||||
expect(html).toContain('<title>Публичная оферта — Эрудит</title>');
|
||||
expect(html).toContain('data-title-en="Public offer — Erudit"');
|
||||
expect(html).toContain('href="https://erudit-game.ru/offer/"');
|
||||
expect(html).toContain('<h1>Публичная оферта</h1>');
|
||||
expect(html).toContain('<h1>Public offer</h1>');
|
||||
// The offer page transliterates the Russian product names left in the English (price-list) view.
|
||||
expect(html).toContain('translitEn');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user