diff --git a/server/routes-seo.js b/server/routes-seo.js index 9d5cb09..ff5a2f4 100644 --- a/server/routes-seo.js +++ b/server/routes-seo.js @@ -4,6 +4,17 @@ import { loadFeedback } from './feedback-store.js'; const SITE_URL = 'https://www.ypchat.net'; const DEFAULT_IMAGE = `${SITE_URL}/static/favicon.png`; +const SEO_LOCALES = [ + { code: 'de', label: 'Deutsch' }, + { code: 'en', label: 'English' }, + { code: 'fr', label: 'Francais' }, + { code: 'es', label: 'Espanol' }, + { code: 'it', label: 'Italiano' }, + { code: 'ja', label: 'Japanese' }, + { code: 'zh', label: 'Chinese' }, + { code: 'th', label: 'Thai' }, + { code: 'tl', label: 'Tagalog' } +]; const seoData = { '/': { @@ -212,6 +223,45 @@ function upsertJsonLd(html, schema) { return html.replace('', ` ${tag}\n`); } +function sanitizeLocalizedHtml(input = '') { + return String(input) + .replace(/[\s\S]*?<\/script>/gi, '') + .trim(); +} + +function buildMultilingualSeoContent(__dirname) { + const localesDir = join(__dirname, '../client/src/i18n/locales'); + const blocks = []; + + for (const locale of SEO_LOCALES) { + const filePath = join(localesDir, `${locale.code}.json`); + if (!existsSync(filePath)) continue; + + try { + const parsed = JSON.parse(readFileSync(filePath, 'utf-8')); + const welcome = sanitizeLocalizedHtml(parsed.welcome || ''); + const intro = sanitizeLocalizedHtml(parsed.introduction || ''); + if (!welcome && !intro) continue; + + blocks.push(`
+

${escapeHtml(locale.label)}

+ ${welcome} + ${intro} +
`); + } catch (error) { + console.warn(`[SEO] Locale konnte nicht gelesen werden (${locale.code}): ${error.message}`); + } + } + + if (blocks.length === 0) return ''; + + return `
+

Mehrsprachige Inhalte

+

Diese Texte sind serverseitig eingebettet, damit Suchmaschinen die Inhalte in allen verfügbaren Sprachen direkt erfassen können.

+ ${blocks.join('\n')} +
`; +} + function generateHTML(route, meta, __dirname) { const distIndexPath = join(__dirname, '../docroot/dist/index.html'); @@ -244,6 +294,13 @@ function generateHTML(route, meta, __dirname) { html = upsertLinkTag(html, 'canonical', meta.ogUrl); html = upsertJsonLd(html, meta.schema); + if (route === '/') { + const multilingual = buildMultilingualSeoContent(__dirname); + if (multilingual) { + html = html.replace('
', `
${multilingual}
`); + } + } + if (route === '/feedback') { const feedbackItems = loadFeedback(__dirname) .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))