From 43a5e595d734cab3b8db887fac962afe582abbfd Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Tue, 7 Apr 2026 15:37:49 +0200 Subject: [PATCH] Add multilingual SEO support in routes-seo.js - Introduced a new SEO_LOCALES array to support multiple languages for SEO content. - Implemented a function to build multilingual SEO content based on available locale files. - Enhanced the generateHTML function to include multilingual sections for the home route, improving accessibility for diverse audiences. These changes enhance the site's SEO capabilities by providing localized content for better search engine indexing and user engagement. --- server/routes-seo.js | 57 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) 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))