Implementierung von SEO-Inhalten und Anpassung der Benutzeroberfläche für den Single Chat
All checks were successful
Deploy SingleChat / deploy (push) Successful in 41s

This commit is contained in:
Torsten Schulz (local)
2026-08-20 16:16:26 +02:00
parent 83d4d0be38
commit 1f1c788204
5 changed files with 53 additions and 39 deletions

View File

@@ -2,14 +2,12 @@
<div class="landing-login"> <div class="landing-login">
<section class="landing-login-intro"> <section class="landing-login-intro">
<p class="landing-login-eyebrow">YpChat</p> <p class="landing-login-eyebrow">YpChat</p>
<h2>Singles kennenlernen, privat chatten</h2> <h2>{{ seoHome.heading }}</h2>
<p class="landing-login-copy"> <p class="landing-login-copy">
Starte kostenlos mit einem Nicknamen. Alter, Geschlecht und Land genügen, damit du passende Kontakte finden und direkt schreiben kannst. {{ seoHome.intro }}
</p> </p>
<div class="landing-login-features"> <div class="landing-login-features">
<span>Weltweiter Chat</span> <span v-for="topic in seoHome.topics" :key="topic.title">{{ topic.title }}</span>
<span>Bildaustausch</span>
<span>Kompakte Bedienung</span>
</div> </div>
<nav class="landing-login-topic-links" aria-label="YpChat Themen"> <nav class="landing-login-topic-links" aria-label="YpChat Themen">
<router-link to="/kostenloser-single-chat">Kostenloser Single Chat</router-link> <router-link to="/kostenloser-single-chat">Kostenloser Single Chat</router-link>
@@ -65,26 +63,18 @@
</section> </section>
<section class="landing-login-guide" aria-label="Informationen zu YpChat"> <section class="landing-login-guide" aria-label="Informationen zu YpChat">
<h2>So funktioniert der Single Chat</h2> <h2>{{ seoHome.guideHeading }}</h2>
<div class="landing-login-guide-grid"> <div class="landing-login-guide-grid">
<article> <article v-for="topic in seoHome.topics" :key="topic.title">
<h3>Kurz Profil anlegen</h3> <h3>{{ topic.title }}</h3>
<p>Wähle einen Nicknamen und gib die nötigen Basisangaben an. Eine lange Registrierung ist nicht nötig.</p> <p>{{ topic.text }}</p>
</article>
<article>
<h3>Neue Kontakte finden</h3>
<p>Suche nach Singles und beginne private Gespräche. Bilder kannst du direkt im Chat austauschen.</p>
</article>
<article>
<h3>Sicher chatten</h3>
<p>Nutze einen Nicknamen, teile keine sensiblen Daten und blockiere oder melde Kontakte bei Bedarf.</p>
</article> </article>
</div> </div>
<p class="landing-login-guide-links"> <p class="landing-login-guide-links">
<router-link to="/single-chat-ohne-anmeldung">Chat ohne Anmeldung</router-link> <router-link to="/single-chat-ohne-anmeldung">{{ seoHome.links[0] }}</router-link>
<router-link to="/single-treff-chat">Singles kennenlernen</router-link> <router-link to="/single-treff-chat">{{ seoHome.links[1] }}</router-link>
<router-link to="/ratgeber/erste-nachricht">Tipps für die erste Nachricht</router-link> <router-link to="/ratgeber/erste-nachricht">{{ seoHome.links[2] }}</router-link>
<router-link to="/sicherheit">Sicher chatten</router-link> <router-link to="/sicherheit">{{ seoHome.links[3] }}</router-link>
</p> </p>
</section> </section>
</div> </div>
@@ -97,6 +87,7 @@ import { useChatStore } from '../stores/chat';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import countryTranslations from '../i18n/countries.json'; import countryTranslations from '../i18n/countries.json';
import { readProfileCookie, writeProfileCookie } from '../utils/profileCookie'; import { readProfileCookie, writeProfileCookie } from '../utils/profileCookie';
import { SEO_HOME_CONTENT } from '../content/seoHome';
const { locale } = useI18n(); const { locale } = useI18n();
const chatStore = useChatStore(); const chatStore = useChatStore();
@@ -105,6 +96,7 @@ const gender = ref('');
const age = ref(18); const age = ref(18);
const country = ref(''); const country = ref('');
const countriesRaw = ref({}); const countriesRaw = ref({});
const seoHome = computed(() => SEO_HOME_CONTENT[locale.value] || SEO_HOME_CONTENT.de);
// Übersetzte Länderliste (sortiert) // Übersetzte Länderliste (sortiert)
const countries = computed(() => { const countries = computed(() => {

View File

@@ -0,0 +1,12 @@
export const SEO_HOME_CONTENT = {
de: { heading: 'Kostenloser Single Chat ohne Anmeldung', intro: 'Bei YPChat kannst du kostenlos neue Singles kennenlernen, privat schreiben und direkt mit einem Nicknamen starten. Für den Einstieg wählst du Nickname, Alter, Geschlecht und Land – eine lange Registrierung ist nicht nötig.', guideHeading: 'So funktioniert der Single Chat', topics: [{ title: 'Singles kennenlernen', text: 'Suche nach passenden Kontakten und beginne Gespräche in deinem Tempo.' }, { title: 'Privat chatten', text: 'Private Unterhaltungen, Bilder sowie Blockier- und Meldefunktionen geben dir Kontrolle über deine Kontakte.' }, { title: 'Schnell starten', text: 'Lege ein kurzes Profil an und öffne den Chat direkt im Browser.' }], links: ['Chat ohne Anmeldung', 'Singles kennenlernen', 'Tipps für die erste Nachricht', 'Sicher chatten'] },
en: { heading: 'Free Single Chat Without a Long Sign-up', intro: 'Meet new singles, chat privately and get started with a nickname on YPChat. Choose a nickname, age, gender and country to begin – no lengthy registration is needed.', guideHeading: 'How single chat works', topics: [{ title: 'Meet singles', text: 'Find suitable contacts and start conversations at your own pace.' }, { title: 'Chat privately', text: 'Private conversations, image sharing, blocking and reporting tools keep you in control.' }, { title: 'Start quickly', text: 'Create a short profile and open the chat directly in your browser.' }], links: ['Chat without a long sign-up', 'Meet new singles', 'First message tips', 'Chat safely'] },
fr: { heading: 'Chat célibataire gratuit sans longue inscription', intro: 'Sur YPChat, rencontrez de nouveaux célibataires, discutez en privé et commencez avec un pseudonyme. Choisissez un pseudo, votre âge, votre genre et votre pays pour démarrer.', guideHeading: 'Comment fonctionne le chat célibataire', topics: [{ title: 'Rencontrer des célibataires', text: 'Trouvez des contacts qui vous correspondent et discutez à votre rythme.' }, { title: 'Discuter en privé', text: 'Conversations privées, partage d’images, blocage et signalement vous donnent le contrôle.' }, { title: 'Commencer rapidement', text: 'Créez un profil court et ouvrez le chat dans votre navigateur.' }], links: ['Chat sans longue inscription', 'Rencontrer des célibataires', 'Conseils pour le premier message', 'Discuter en sécurité'] },
es: { heading: 'Chat para solteros gratis sin registro largo', intro: 'En YPChat puedes conocer nuevos solteros, chatear en privado y empezar con un apodo. Elige apodo, edad, género y país para comenzar; no necesitas un registro largo.', guideHeading: 'Cómo funciona el chat para solteros', topics: [{ title: 'Conocer solteros', text: 'Encuentra contactos adecuados e inicia conversaciones a tu ritmo.' }, { title: 'Chatear en privado', text: 'Los chats privados, las imágenes y las opciones de bloqueo y reporte te dan el control.' }, { title: 'Empezar rápido', text: 'Crea un perfil breve y abre el chat directamente en tu navegador.' }], links: ['Chat sin registro largo', 'Conocer solteros', 'Consejos para el primer mensaje', 'Chatear con seguridad'] },
it: { heading: 'Chat single gratis senza lunga registrazione', intro: 'Su YPChat puoi conoscere nuovi single, chattare in privato e iniziare con un nickname. Scegli nickname, età, genere e paese per iniziare; non serve una lunga registrazione.', guideHeading: 'Come funziona la chat single', topics: [{ title: 'Conosci single', text: 'Trova contatti adatti e avvia conversazioni con i tuoi tempi.' }, { title: 'Chat privata', text: 'Conversazioni private, immagini, blocco e segnalazione ti danno il controllo.' }, { title: 'Inizia subito', text: 'Crea un breve profilo e apri la chat direttamente nel browser.' }], links: ['Chat senza lunga registrazione', 'Conosci nuovi single', 'Consigli per il primo messaggio', 'Chat sicura'] },
ja: { heading: '登録不要ですぐ使える無料シングルチャット', intro: 'YPChatでは、ニックネームで始めて新しいシングルと出会い、プライベートにチャットできます。開始にはニックネーム、年齢、性別、国を選ぶだけです。', guideHeading: 'シングルチャットの使い方', topics: [{ title: '新しい人と出会う', text: '自分に合う相手を探し、自分のペースで会話を始められます。' }, { title: 'プライベートにチャット', text: '個別チャット、画像共有、ブロックと通報の機能で会話を管理できます。' }, { title: 'すぐに始める', text: '短いプロフィールを作成し、ブラウザで直接チャットを開けます。' }], links: ['簡単にチャットを始める', '新しいシングルと出会う', '最初のメッセージのヒント', '安全にチャットする'] },
zh: { heading: '免费单身聊天,无需繁琐注册', intro: '在 YPChat,你可以用昵称开始,认识新的单身人士并进行私密聊天。选择昵称、年龄、性别和国家即可开始,无需繁琐注册。', guideHeading: '单身聊天如何使用', topics: [{ title: '认识新朋友', text: '寻找合适的联系人,按照自己的节奏开始对话。' }, { title: '私密聊天', text: '私聊、图片分享、屏蔽和举报功能让你掌控自己的交流。' }, { title: '快速开始', text: '创建简短资料后,直接在浏览器中打开聊天。' }], links: ['无需繁琐注册的聊天', '认识单身人士', '第一条消息建议', '安全聊天'] },
th: { heading: 'แชทคนโสดฟรี ไม่ต้องสมัครนาน', intro: 'ที่ YPChat คุณพบคนโสดใหม่ ๆ แชทแบบส่วนตัว และเริ่มต้นด้วยชื่อเล่นได้ เพียงเลือกชื่อเล่น อายุ เพศ และประเทศก็เริ่มได้เลย.', guideHeading: 'แชทคนโสดทำงานอย่างไร', topics: [{ title: 'พบคนโสดใหม่', text: 'ค้นหาคนที่เหมาะสมและเริ่มสนทนาตามจังหวะของคุณ.' }, { title: 'แชทส่วนตัว', text: 'แชทส่วนตัว การแชร์รูปภาพ การบล็อกและการรายงานช่วยให้คุณควบคุมการติดต่อได้.' }, { title: 'เริ่มได้รวดเร็ว', text: 'สร้างโปรไฟล์สั้น ๆ และเปิดแชทในเบราว์เซอร์ได้ทันที.' }], links: ['แชทโดยไม่ต้องสมัครนาน', 'พบคนโสดใหม่', 'เคล็ดลับข้อความแรก', 'แชทอย่างปลอดภัย'] },
tl: { heading: 'Libreng single chat na walang mahabang pagpaparehistro', intro: 'Sa YPChat, makakilala ka ng mga bagong single, makipag-chat nang pribado at magsimula gamit ang palayaw. Pumili ng palayaw, edad, kasarian at bansa para makapagsimula.', guideHeading: 'Paano gumagana ang single chat', topics: [{ title: 'Makakilala ng mga single', text: 'Maghanap ng angkop na kausap at magsimula ng pag-uusap sa sarili mong bilis.' }, { title: 'Pribadong chat', text: 'Ang pribadong pag-uusap, pagbabahagi ng larawan, pag-block at pag-report ay nagbibigay sa iyo ng kontrol.' }, { title: 'Mabilis magsimula', text: 'Gumawa ng maikling profile at buksan ang chat mismo sa browser.' }], links: ['Chat na walang mahabang registration', 'Makakilala ng mga single', 'Mga tip sa unang mensahe', 'Ligtas na pag-chat'] },
ceb: { heading: 'Libre nga single chat, walay taas nga rehistrasyon', intro: 'Sa YPChat, makaila ka og bag-ong single, makig-chat og pribado ug magsugod gamit ang palayaw. Pilia ang palayaw, edad, gender ug nasod aron makasugod.', guideHeading: 'Giunsa pagtrabaho ang single chat', topics: [{ title: 'Makaila og mga single', text: 'Pangitaa ang angay nga kaistorya ug sugdi ang panag-istorya sa imong kaugalingong oras.' }, { title: 'Pribadong chat', text: 'Pribadong panag-istorya, pagpaambit og hulagway, pag-block ug pag-report naghatag nimo og kontrol.' }, { title: 'Dali nga pagsugod', text: 'Paghimo og mubo nga profile ug ablihi ang chat direkta sa browser.' }], links: ['Chat nga walay taas nga rehistrasyon', 'Makaila og mga single', 'Tambag sa unang mensahe', 'Luwas nga pag-chat'] }
};

View File

@@ -13,10 +13,11 @@ import GuideProfileView from '../views/GuideProfileView.vue';
import GuideSafetyView from '../views/GuideSafetyView.vue'; import GuideSafetyView from '../views/GuideSafetyView.vue';
import GuideRedFlagsView from '../views/GuideRedFlagsView.vue'; import GuideRedFlagsView from '../views/GuideRedFlagsView.vue';
import SeoLandingView from '../views/SeoLandingView.vue'; import SeoLandingView from '../views/SeoLandingView.vue';
import i18n from '../i18n';
const SITE_URL = 'https://www.ypchat.net'; const SITE_URL = 'https://www.ypchat.net';
const DEFAULT_IMAGE = `${SITE_URL}/static/favicon.png`; const DEFAULT_IMAGE = `${SITE_URL}/static/favicon.png`;
const SUPPORTED_LOCALES = ['de', 'en', 'fr', 'es', 'it', 'ja', 'zh', 'th', 'tl']; const SUPPORTED_LOCALES = ['de', 'en', 'fr', 'es', 'it', 'ja', 'zh', 'th', 'tl', 'ceb'];
const LOCALIZED_HOME_META = { const LOCALIZED_HOME_META = {
de: { de: {
title: 'SingleChat - Kostenloser Single Chat ohne Anmeldung', title: 'SingleChat - Kostenloser Single Chat ohne Anmeldung',
@@ -62,6 +63,11 @@ const LOCALIZED_HOME_META = {
title: 'SingleChat: Libreng private at anonymous na single chat', title: 'SingleChat: Libreng private at anonymous na single chat',
description: 'Libreng single chat para sa private at anonymous na usapan. Kumilala ng bagong tao at magbahagi ng larawan nang ligtas.', description: 'Libreng single chat para sa private at anonymous na usapan. Kumilala ng bagong tao at magbahagi ng larawan nang ligtas.',
keywords: 'single chat, libreng chat, private chat, anonymous chat, online chat' keywords: 'single chat, libreng chat, private chat, anonymous chat, online chat'
},
ceb: {
title: 'SingleChat: Libre, Pribado ug Anonimong Single Chat',
description: 'Libre nga single chat para sa pribado ug anonimong mga panaghisgot. Makaila ug magbahin og mga litrato nga luwas online.',
keywords: 'single chat, libre nga chat, pribadong chat, anonimong chat, online chat'
} }
}; };
@@ -565,6 +571,7 @@ router.beforeEach((to, from, next) => {
document.title = title; document.title = title;
document.documentElement.setAttribute('lang', localeFromPath); document.documentElement.setAttribute('lang', localeFromPath);
i18n.global.locale.value = localeFromPath;
updateMetaTag('description', description); updateMetaTag('description', description);
updateMetaTag('keywords', keywords); updateMetaTag('keywords', keywords);

View File

@@ -159,7 +159,7 @@
<span class="app-brand-mark">Y</span> <span class="app-brand-mark">Y</span>
<div class="app-brand-copy"> <div class="app-brand-copy">
<span class="app-brand-eyebrow">YpChat</span> <span class="app-brand-eyebrow">YpChat</span>
<h1>Kostenloser Single Chat</h1> <h1>{{ publicHomeHeading }}</h1>
</div> </div>
</div> </div>
<HeaderAdBanner /> <HeaderAdBanner />
@@ -178,6 +178,7 @@
<script setup> <script setup>
import { onMounted, computed } from 'vue'; import { onMounted, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useChatStore } from '../stores/chat'; import { useChatStore } from '../stores/chat';
import MenuBar from '../components/MenuBar.vue'; import MenuBar from '../components/MenuBar.vue';
import UserList from '../components/UserList.vue'; import UserList from '../components/UserList.vue';
@@ -191,8 +192,15 @@ import ImprintContainer from '../components/ImprintContainer.vue';
import HeaderAdBanner from '../components/HeaderAdBanner.vue'; import HeaderAdBanner from '../components/HeaderAdBanner.vue';
import VideoDock from '../components/VideoDock.vue'; import VideoDock from '../components/VideoDock.vue';
import FloatingVideoWindow from '../components/FloatingVideoWindow.vue'; import FloatingVideoWindow from '../components/FloatingVideoWindow.vue';
import { SEO_HOME_CONTENT } from '../content/seoHome';
const chatStore = useChatStore(); const chatStore = useChatStore();
const route = useRoute();
const publicHomeHeading = computed(() => {
const locale = String(route.path || '/').slice(1) || 'de';
return (SEO_HOME_CONTENT[locale] || SEO_HOME_CONTENT.de).heading;
});
const userInitials = computed(() => { const userInitials = computed(() => {
return (chatStore.userName || 'YP') return (chatStore.userName || 'YP')

View File

@@ -1,6 +1,7 @@
import { readFileSync, existsSync } from 'fs'; import { readFileSync, existsSync } from 'fs';
import { join, resolve } from 'path'; import { join, resolve } from 'path';
import { loadFeedback } from './feedback-store.js'; import { loadFeedback } from './feedback-store.js';
import { SEO_HOME_CONTENT } from '../client/src/content/seoHome.js';
const SITE_URL = 'https://www.ypchat.net'; const SITE_URL = 'https://www.ypchat.net';
const DEFAULT_IMAGE = `${SITE_URL}/static/favicon.png`; const DEFAULT_IMAGE = `${SITE_URL}/static/favicon.png`;
@@ -498,18 +499,15 @@ function buildLocalizedLandingContent(route, __dirname) {
</section>`; </section>`;
} }
function buildHomeSeoContent() { function buildHomeSeoContent(localeCode = 'de') {
return `<section lang="de" style="max-width:960px;margin:24px auto;padding:0 16px;font:400 16px/1.6 sans-serif;color:#344038;"> const content = SEO_HOME_CONTENT[localeCode] || SEO_HOME_CONTENT.de;
const topics = content.topics.map((topic) => `<article style="border:1px solid #d7dfd9;border-radius:12px;padding:14px;background:#fff;"><h2 style="font:600 20px/1.25 sans-serif;color:#18201b;margin:0 0 8px;">${escapeHtml(topic.title)}</h2><p style="margin:0;">${escapeHtml(topic.text)}</p></article>`).join('');
return `<section lang="${escapeHtml(localeCode)}" style="max-width:960px;margin:24px auto;padding:0 16px;font:400 16px/1.6 sans-serif;color:#344038;">
<p style="font:700 12px/1.2 sans-serif;color:#637067;text-transform:uppercase;margin:0 0 6px;">YPChat</p> <p style="font:700 12px/1.2 sans-serif;color:#637067;text-transform:uppercase;margin:0 0 6px;">YPChat</p>
<h1 style="font:700 34px/1.15 sans-serif;color:#18201b;margin:0 0 12px;">Kostenloser Single Chat ohne Anmeldung</h1> <h1 style="font:700 34px/1.15 sans-serif;color:#18201b;margin:0 0 12px;">${escapeHtml(content.heading)}</h1>
<p style="margin:0 0 18px;max-width:760px;">Bei YPChat kannst du kostenlos neue Singles kennenlernen, privat schreiben und direkt mit einem Nicknamen starten. Für den Einstieg wählst du Nickname, Alter, Geschlecht und Land – eine lange Registrierung ist nicht nötig.</p> <p style="margin:0 0 18px;max-width:760px;">${escapeHtml(content.intro)}</p>
<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px;"> <div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px;">${topics}</div>
<article style="border:1px solid #d7dfd9;border-radius:12px;padding:14px;background:#fff;"><h2 style="font:600 20px/1.25 sans-serif;color:#18201b;margin:0 0 8px;">Singles kennenlernen</h2><p style="margin:0;">Suche nach passenden Kontakten und beginne Gespräche in deinem Tempo.</p></article>
<article style="border:1px solid #d7dfd9;border-radius:12px;padding:14px;background:#fff;"><h2 style="font:600 20px/1.25 sans-serif;color:#18201b;margin:0 0 8px;">Privat und respektvoll chatten</h2><p style="margin:0;">Private Unterhaltungen, Bilder im Chat sowie Blockier- und Meldefunktionen geben dir Kontrolle über deine Kontakte.</p></article>
<article style="border:1px solid #d7dfd9;border-radius:12px;padding:14px;background:#fff;"><h2 style="font:600 20px/1.25 sans-serif;color:#18201b;margin:0 0 8px;">Ohne lange Anmeldung starten</h2><p style="margin:0;">Lege ein kurzes Profil an und öffne den Chat direkt im Browser.</p></article>
</div>
<section style="margin-top:24px;"><h2 style="font:600 24px/1.25 sans-serif;color:#18201b;margin:0 0 8px;">Häufige Fragen zum kostenlosen Single Chat</h2><h3 style="font:600 18px/1.3 sans-serif;color:#18201b;margin:16px 0 4px;">Ist der Einstieg kostenlos?</h3><p style="margin:0;">Ja. Du kannst dein Profil starten und den Chat kostenlos nutzen.</p><h3 style="font:600 18px/1.3 sans-serif;color:#18201b;margin:16px 0 4px;">Was brauche ich für den Start?</h3><p style="margin:0;">Ein Nickname sowie Alter, Geschlecht und Land genügen für den Einstieg.</p></section>
<nav aria-label="Weitere Themen" style="margin-top:22px;"><strong style="color:#18201b;">Mehr zu YPChat:</strong> <a href="/single-chat-ohne-anmeldung">Chat ohne Anmeldung</a> · <a href="/single-treff-chat">Singles kennenlernen im Single Treff Chat</a> · <a href="/ratgeber/erste-nachricht">Tipps für die erste Nachricht</a> · <a href="/sicherheit">Sicher und anonym chatten</a></nav>
</section>`; </section>`;
} }
@@ -567,14 +565,11 @@ function generateHTML(route, meta, __dirname) {
html = upsertHreflangLinks(html, route); html = upsertHreflangLinks(html, route);
if (route === '/') { if (route === '/') {
html = html.replace('<div id="app"></div>', `<div id="app">${buildHomeSeoContent()}</div>`); html = html.replace('<div id="app"></div>', `<div id="app">${buildHomeSeoContent('de')}</div>`);
} }
if (SEO_LOCALES.some((locale) => `/${locale.code}` === route)) { if (SEO_LOCALES.some((locale) => `/${locale.code}` === route)) {
const localizedLanding = buildLocalizedLandingContent(route, __dirname); html = html.replace('<div id="app"></div>', `<div id="app">${buildHomeSeoContent(route.slice(1))}</div>`);
if (localizedLanding) {
html = html.replace('<div id="app"></div>', `<div id="app">${localizedLanding}</div>`);
}
} }
const seoLanding = buildSeoLandingContent(route); const seoLanding = buildSeoLandingContent(route);