Import source: app/scripts/generate-en-page.mjs
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
@@ -0,0 +1,123 @@
|
|||||||
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
||||||
|
import { resolve } from 'node:path';
|
||||||
|
|
||||||
|
const SITE_URL = (process.env.TEKNAV_SITE_URL || process.env.VITE_SITE_URL || 'https://www.teknav.ir').replace(/\/$/, '');
|
||||||
|
const distRoot = resolve('dist');
|
||||||
|
const sourcePath = resolve(distRoot, 'index.html');
|
||||||
|
const targetDir = resolve(distRoot, 'en');
|
||||||
|
const targetPath = resolve(targetDir, 'index.html');
|
||||||
|
|
||||||
|
function esc(value) {
|
||||||
|
return String(value ?? '')
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
function json(value) {
|
||||||
|
return JSON.stringify(value).replace(/</g, '\\u003c');
|
||||||
|
}
|
||||||
|
|
||||||
|
const canonical = `${SITE_URL}/en/`;
|
||||||
|
const title = 'Teknav English | Persian Technology Analysis on AI, Data, Security and Software';
|
||||||
|
const description = 'Teknav English homepage: a single LTR English gateway to Persian technology analysis on AI, data science, cybersecurity, software, hardware, startups, writers, and the newsletter archive.';
|
||||||
|
const keywords = [
|
||||||
|
'Teknav English',
|
||||||
|
'Teknav',
|
||||||
|
'Persian technology media',
|
||||||
|
'Iran technology analysis',
|
||||||
|
'Persian AI articles',
|
||||||
|
'Persian data science',
|
||||||
|
'Persian cybersecurity',
|
||||||
|
'AI analysis Iran',
|
||||||
|
'technology writers Iran',
|
||||||
|
'Persian tech newsletter',
|
||||||
|
'RAG benchmark Persian',
|
||||||
|
'data-centric AI Persian',
|
||||||
|
'software engineering analysis',
|
||||||
|
'hardware analysis',
|
||||||
|
'startup analysis Iran',
|
||||||
|
].join(', ');
|
||||||
|
const image = `${SITE_URL}/images/og/tekrag-persian-data-centric-rag-benchmark.jpg`;
|
||||||
|
|
||||||
|
const graph = [
|
||||||
|
{
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': ['Organization', 'NewsMediaOrganization'],
|
||||||
|
'@id': `${SITE_URL}/#organization-en`,
|
||||||
|
name: 'Teknav',
|
||||||
|
alternateName: ['Teknav.ir', 'Teknav English'],
|
||||||
|
url: SITE_URL,
|
||||||
|
logo: { '@type': 'ImageObject', url: `${SITE_URL}/favicon.png`, width: 512, height: 512 },
|
||||||
|
description: 'Teknav is a Persian-first technology publication covering artificial intelligence, data science, cybersecurity, software engineering, hardware, startups, and future technology.',
|
||||||
|
sameAs: ['https://x.com/teknavir', 'https://linkedin.com/company/teknav'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'WebSite',
|
||||||
|
'@id': `${SITE_URL}/en/#website`,
|
||||||
|
url: canonical,
|
||||||
|
name: 'Teknav English',
|
||||||
|
inLanguage: 'en-US',
|
||||||
|
publisher: { '@id': `${SITE_URL}/#organization-en` },
|
||||||
|
description,
|
||||||
|
potentialAction: {
|
||||||
|
'@type': 'SearchAction',
|
||||||
|
target: `${SITE_URL}/search?q={search_term_string}`,
|
||||||
|
'query-input': 'required name=search_term_string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'WebPage',
|
||||||
|
'@id': `${SITE_URL}/en/#webpage`,
|
||||||
|
name: 'Teknav English',
|
||||||
|
url: canonical,
|
||||||
|
inLanguage: 'en-US',
|
||||||
|
isPartOf: { '@id': `${SITE_URL}/en/#website` },
|
||||||
|
primaryImageOfPage: { '@type': 'ImageObject', url: image },
|
||||||
|
about: [
|
||||||
|
{ '@type': 'Thing', name: 'Artificial Intelligence' },
|
||||||
|
{ '@type': 'Thing', name: 'Data Science' },
|
||||||
|
{ '@type': 'Thing', name: 'Cybersecurity' },
|
||||||
|
{ '@type': 'Thing', name: 'Software Engineering' },
|
||||||
|
{ '@type': 'Thing', name: 'Persian technology analysis' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'BreadcrumbList',
|
||||||
|
itemListElement: [
|
||||||
|
{ '@type': 'ListItem', position: 1, name: 'Teknav', item: SITE_URL },
|
||||||
|
{ '@type': 'ListItem', position: 2, name: 'English', item: canonical },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let html = readFileSync(sourcePath, 'utf8');
|
||||||
|
html = html.replace(/<html([^>]*)>/, '<html lang="en" dir="ltr">');
|
||||||
|
html = html.replace(/<title>.*?<\/title>/, `<title>${esc(title)}</title>`);
|
||||||
|
html = html.replace(/<meta name="description" content="[^"]*" \/>/, `<meta name="description" content="${esc(description)}" />`);
|
||||||
|
html = html.replace(/<meta name="keywords" content="[^"]*" \/>/, `<meta name="keywords" content="${esc(keywords)}" />`);
|
||||||
|
html = html.replace(/<meta name="author" content="[^"]*" \/>/, '<meta name="author" content="Teknav" />');
|
||||||
|
html = html.replace(/<meta name="language" content="[^"]*" \/>/, '<meta name="language" content="en-US" />');
|
||||||
|
html = html.replace(/<meta property="og:locale" content="[^"]*" \/>/, '<meta property="og:locale" content="en_US" />');
|
||||||
|
html = html.replace(/<meta property="og:site_name" content="[^"]*" \/>/, '<meta property="og:site_name" content="Teknav" />');
|
||||||
|
html = html.replace(/<meta property="og:type" content="[^"]*" \/>/, '<meta property="og:type" content="website" />');
|
||||||
|
html = html.replace(/<meta property="og:title" content="[^"]*" \/>/, `<meta property="og:title" content="${esc(title)}" />`);
|
||||||
|
html = html.replace(/<meta property="og:description" content="[^"]*" \/>/, `<meta property="og:description" content="${esc(description)}" />`);
|
||||||
|
html = html.replace(/<meta property="og:url" content="[^"]*" \/>/, `<meta property="og:url" content="${esc(canonical)}" />`);
|
||||||
|
html = html.replace(/<meta property="og:image" content="[^"]*" \/>/, `<meta property="og:image" content="${esc(image)}" />`);
|
||||||
|
html = html.replace(/<meta name="twitter:title" content="[^"]*" \/>/, `<meta name="twitter:title" content="${esc(title)}" />`);
|
||||||
|
html = html.replace(/<meta name="twitter:description" content="[^"]*" \/>/, `<meta name="twitter:description" content="${esc(description)}" />`);
|
||||||
|
html = html.replace(/<meta name="twitter:image" content="[^"]*" \/>/, `<meta name="twitter:image" content="${esc(image)}" />`);
|
||||||
|
html = html.replace(/<link rel="canonical" href="[^"]*" \/>/, `<link rel="canonical" href="${esc(canonical)}" />`);
|
||||||
|
html = html.replace(/<link rel="alternate" hreflang="[^"]+" href="[^"]+" \/>/, `<link rel="alternate" hreflang="en" href="${esc(canonical)}" />\n <link rel="alternate" hreflang="fa" href="${esc(SITE_URL)}/" />\n <link rel="alternate" hreflang="x-default" href="${esc(canonical)}" />`);
|
||||||
|
html = html.replace(/<link rel="alternate" type="application\/rss\+xml" title="[^"]*" href="[^"]*" \/>/, `<link rel="alternate" type="application/rss+xml" title="Teknav latest articles" href="${esc(SITE_URL)}/feed.xml" />`);
|
||||||
|
html = html.replace(/<script type="application\/ld\+json">.*?<\/script>/s, `<script type="application/ld+json">${json({ '@context': 'https://schema.org', '@graph': graph })}</script>`);
|
||||||
|
html = html.replace(/<div style="font-size:36px;font-weight:900;color:#0F6B73;margin-bottom:8px">.*?<\/div>/, '<div style="font-size:36px;font-weight:900;color:#0F6B73;margin-bottom:8px">Teknav</div>');
|
||||||
|
|
||||||
|
mkdirSync(targetDir, { recursive: true });
|
||||||
|
writeFileSync(targetPath, html, 'utf8');
|
||||||
|
console.log('[en-page] generated dist/en/index.html');
|
||||||
Reference in New Issue
Block a user