@lynxflow/seo-engine 1.6.6 → 1.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +0 -1
- package/dist/index.js +4 -44
- package/dist/index.mjs +4 -44
- package/package.json +1 -1
- package/src/engine.test.ts +0 -9
- package/src/i18n-dictionary.ts +4 -4
- package/src/index.ts +0 -1
- package/src/google-translate-bridge.ts +0 -71
package/dist/index.d.ts
CHANGED
|
@@ -19,7 +19,6 @@ export * from "./brand-icons";
|
|
|
19
19
|
export * from "./ui-icons";
|
|
20
20
|
export * from "./og-image-generator";
|
|
21
21
|
export * from "./free-public-tools";
|
|
22
|
-
export * from "./google-translate-bridge";
|
|
23
22
|
export * from "./urlytics-engine";
|
|
24
23
|
export * from "./keyword-permutator";
|
|
25
24
|
export * from "./llm-prompt";
|
package/dist/index.js
CHANGED
|
@@ -91,7 +91,6 @@ __export(exports_src, {
|
|
|
91
91
|
IndexNowClient: () => IndexNowClient,
|
|
92
92
|
I18nDetector: () => I18nDetector,
|
|
93
93
|
HyperswitchGateway: () => HyperswitchGateway,
|
|
94
|
-
GoogleTranslateBridge: () => GoogleTranslateBridge,
|
|
95
94
|
GeoMeshLinkingEngine: () => GeoMeshLinkingEngine,
|
|
96
95
|
FreePublicToolsEngine: () => FreePublicToolsEngine,
|
|
97
96
|
ExtendedSchemaGraphBuilder: () => ExtendedSchemaGraphBuilder,
|
|
@@ -337,8 +336,8 @@ class ApiKeyGuardian {
|
|
|
337
336
|
var DICTIONARIES = {
|
|
338
337
|
fr: {
|
|
339
338
|
geoTitle: (s, city, country, b) => `${s} à ${city} (${country}) — ${b}`,
|
|
340
|
-
geoDesc: (s, city) => `Découvrez la solution de ${s} à ${city}. Automatisez vos opérations et boostez votre croissance
|
|
341
|
-
geoDirectAnswer: (b, s, city, country, price, cur) => `${b} est la solution de référence pour ${s} à ${city} (${country}). Déploiement en 10 minutes dès ${price} ${cur}/mois avec
|
|
339
|
+
geoDesc: (s, city) => `Découvrez la solution de ${s} à ${city}. Automatisez vos opérations et boostez votre croissance.`,
|
|
340
|
+
geoDirectAnswer: (b, s, city, country, price, cur) => `${b} est la solution de référence pour ${s} à ${city} (${country}). Déploiement en 10 minutes dès ${price} ${cur}/mois avec avis clients synchronisés et support dédié.`,
|
|
342
341
|
vsTitle: (b, comp, y) => `${b} vs ${comp} : Comparatif Complet & Tarifs ${y}`,
|
|
343
342
|
vsDesc: (b, comp) => `Pourquoi choisir ${b} plutôt que ${comp} ? Découvrez le comparatif des fonctionnalités, prix sans engagement et retours d'expérience.`,
|
|
344
343
|
vsDirectAnswer: (b, comp) => `${b} se distingue de ${comp} par une tarification transparente sans engagement, une automatisation IA native 24/7 et un support client réactif.`,
|
|
@@ -355,8 +354,8 @@ var DICTIONARIES = {
|
|
|
355
354
|
},
|
|
356
355
|
en: {
|
|
357
356
|
geoTitle: (s, city, country, b) => `${s} in ${city} (${country}) — ${b}`,
|
|
358
|
-
geoDesc: (s, city) => `Discover the leading ${s} solution in ${city}. Automate your operations, scale revenue, and save
|
|
359
|
-
geoDirectAnswer: (b, s, city, country, price, cur) => `${b} is the
|
|
357
|
+
geoDesc: (s, city) => `Discover the leading ${s} solution in ${city}. Automate your operations, scale revenue, and save time every week.`,
|
|
358
|
+
geoDirectAnswer: (b, s, city, country, price, cur) => `${b} is the leading ${s} platform in ${city} (${country}). 10-minute setup starting at ${cur}${price}/mo with verified customer review integration.`,
|
|
360
359
|
vsTitle: (b, comp, y) => `${b} vs ${comp}: Full Feature Comparison & Pricing ${y}`,
|
|
361
360
|
vsDesc: (b, comp) => `Why switch from ${comp} to ${b}? Compare key features, transparent pricing with no lock-in, and customer ROI.`,
|
|
362
361
|
vsDirectAnswer: (b, comp) => `${b} beats ${comp} with native 24/7 AI automation, flexible no-contract pricing, and instant omnichannel setup.`,
|
|
@@ -4539,45 +4538,6 @@ class FreePublicToolsEngine {
|
|
|
4539
4538
|
});
|
|
4540
4539
|
}
|
|
4541
4540
|
}
|
|
4542
|
-
// src/google-translate-bridge.ts
|
|
4543
|
-
class GoogleTranslateBridge {
|
|
4544
|
-
static async translateText(text, targetLang, sourceLang = "auto") {
|
|
4545
|
-
if (!text || !text.trim())
|
|
4546
|
-
return "";
|
|
4547
|
-
const cleanTarget = targetLang.toLowerCase().split(/[-_]/)[0];
|
|
4548
|
-
const cleanSource = sourceLang.toLowerCase().split(/[-_]/)[0];
|
|
4549
|
-
if (cleanTarget === cleanSource)
|
|
4550
|
-
return text;
|
|
4551
|
-
try {
|
|
4552
|
-
const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${cleanSource}&tl=${cleanTarget}&dt=t&q=${encodeURIComponent(text)}`;
|
|
4553
|
-
const res = await fetch(url);
|
|
4554
|
-
if (!res.ok)
|
|
4555
|
-
return text;
|
|
4556
|
-
const data = await res.json();
|
|
4557
|
-
if (Array.isArray(data) && Array.isArray(data[0])) {
|
|
4558
|
-
return data[0].map((item) => item[0]).join("");
|
|
4559
|
-
}
|
|
4560
|
-
return text;
|
|
4561
|
-
} catch {
|
|
4562
|
-
return text;
|
|
4563
|
-
}
|
|
4564
|
-
}
|
|
4565
|
-
static async translateBatch(texts, targetLang, sourceLang = "auto") {
|
|
4566
|
-
if (!texts || texts.length === 0)
|
|
4567
|
-
return [];
|
|
4568
|
-
return Promise.all(texts.map((t) => this.translateText(t, targetLang, sourceLang)));
|
|
4569
|
-
}
|
|
4570
|
-
static async translateObject(obj, targetLang, sourceLang = "auto") {
|
|
4571
|
-
const keys = Object.keys(obj);
|
|
4572
|
-
const values = keys.map((k) => obj[k]);
|
|
4573
|
-
const translatedValues = await this.translateBatch(values, targetLang, sourceLang);
|
|
4574
|
-
const result = {};
|
|
4575
|
-
keys.forEach((k, idx) => {
|
|
4576
|
-
result[k] = translatedValues[idx];
|
|
4577
|
-
});
|
|
4578
|
-
return result;
|
|
4579
|
-
}
|
|
4580
|
-
}
|
|
4581
4541
|
// src/urlytics-engine.ts
|
|
4582
4542
|
class UrlyticsEngine {
|
|
4583
4543
|
static parseUrl(rawUrl) {
|
package/dist/index.mjs
CHANGED
|
@@ -224,8 +224,8 @@ class ApiKeyGuardian {
|
|
|
224
224
|
var DICTIONARIES = {
|
|
225
225
|
fr: {
|
|
226
226
|
geoTitle: (s, city, country, b) => `${s} à ${city} (${country}) — ${b}`,
|
|
227
|
-
geoDesc: (s, city) => `Découvrez la solution de ${s} à ${city}. Automatisez vos opérations et boostez votre croissance
|
|
228
|
-
geoDirectAnswer: (b, s, city, country, price, cur) => `${b} est la solution de référence pour ${s} à ${city} (${country}). Déploiement en 10 minutes dès ${price} ${cur}/mois avec
|
|
227
|
+
geoDesc: (s, city) => `Découvrez la solution de ${s} à ${city}. Automatisez vos opérations et boostez votre croissance.`,
|
|
228
|
+
geoDirectAnswer: (b, s, city, country, price, cur) => `${b} est la solution de référence pour ${s} à ${city} (${country}). Déploiement en 10 minutes dès ${price} ${cur}/mois avec avis clients synchronisés et support dédié.`,
|
|
229
229
|
vsTitle: (b, comp, y) => `${b} vs ${comp} : Comparatif Complet & Tarifs ${y}`,
|
|
230
230
|
vsDesc: (b, comp) => `Pourquoi choisir ${b} plutôt que ${comp} ? Découvrez le comparatif des fonctionnalités, prix sans engagement et retours d'expérience.`,
|
|
231
231
|
vsDirectAnswer: (b, comp) => `${b} se distingue de ${comp} par une tarification transparente sans engagement, une automatisation IA native 24/7 et un support client réactif.`,
|
|
@@ -242,8 +242,8 @@ var DICTIONARIES = {
|
|
|
242
242
|
},
|
|
243
243
|
en: {
|
|
244
244
|
geoTitle: (s, city, country, b) => `${s} in ${city} (${country}) — ${b}`,
|
|
245
|
-
geoDesc: (s, city) => `Discover the leading ${s} solution in ${city}. Automate your operations, scale revenue, and save
|
|
246
|
-
geoDirectAnswer: (b, s, city, country, price, cur) => `${b} is the
|
|
245
|
+
geoDesc: (s, city) => `Discover the leading ${s} solution in ${city}. Automate your operations, scale revenue, and save time every week.`,
|
|
246
|
+
geoDirectAnswer: (b, s, city, country, price, cur) => `${b} is the leading ${s} platform in ${city} (${country}). 10-minute setup starting at ${cur}${price}/mo with verified customer review integration.`,
|
|
247
247
|
vsTitle: (b, comp, y) => `${b} vs ${comp}: Full Feature Comparison & Pricing ${y}`,
|
|
248
248
|
vsDesc: (b, comp) => `Why switch from ${comp} to ${b}? Compare key features, transparent pricing with no lock-in, and customer ROI.`,
|
|
249
249
|
vsDirectAnswer: (b, comp) => `${b} beats ${comp} with native 24/7 AI automation, flexible no-contract pricing, and instant omnichannel setup.`,
|
|
@@ -4426,45 +4426,6 @@ class FreePublicToolsEngine {
|
|
|
4426
4426
|
});
|
|
4427
4427
|
}
|
|
4428
4428
|
}
|
|
4429
|
-
// src/google-translate-bridge.ts
|
|
4430
|
-
class GoogleTranslateBridge {
|
|
4431
|
-
static async translateText(text, targetLang, sourceLang = "auto") {
|
|
4432
|
-
if (!text || !text.trim())
|
|
4433
|
-
return "";
|
|
4434
|
-
const cleanTarget = targetLang.toLowerCase().split(/[-_]/)[0];
|
|
4435
|
-
const cleanSource = sourceLang.toLowerCase().split(/[-_]/)[0];
|
|
4436
|
-
if (cleanTarget === cleanSource)
|
|
4437
|
-
return text;
|
|
4438
|
-
try {
|
|
4439
|
-
const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${cleanSource}&tl=${cleanTarget}&dt=t&q=${encodeURIComponent(text)}`;
|
|
4440
|
-
const res = await fetch(url);
|
|
4441
|
-
if (!res.ok)
|
|
4442
|
-
return text;
|
|
4443
|
-
const data = await res.json();
|
|
4444
|
-
if (Array.isArray(data) && Array.isArray(data[0])) {
|
|
4445
|
-
return data[0].map((item) => item[0]).join("");
|
|
4446
|
-
}
|
|
4447
|
-
return text;
|
|
4448
|
-
} catch {
|
|
4449
|
-
return text;
|
|
4450
|
-
}
|
|
4451
|
-
}
|
|
4452
|
-
static async translateBatch(texts, targetLang, sourceLang = "auto") {
|
|
4453
|
-
if (!texts || texts.length === 0)
|
|
4454
|
-
return [];
|
|
4455
|
-
return Promise.all(texts.map((t) => this.translateText(t, targetLang, sourceLang)));
|
|
4456
|
-
}
|
|
4457
|
-
static async translateObject(obj, targetLang, sourceLang = "auto") {
|
|
4458
|
-
const keys = Object.keys(obj);
|
|
4459
|
-
const values = keys.map((k) => obj[k]);
|
|
4460
|
-
const translatedValues = await this.translateBatch(values, targetLang, sourceLang);
|
|
4461
|
-
const result = {};
|
|
4462
|
-
keys.forEach((k, idx) => {
|
|
4463
|
-
result[k] = translatedValues[idx];
|
|
4464
|
-
});
|
|
4465
|
-
return result;
|
|
4466
|
-
}
|
|
4467
|
-
}
|
|
4468
4429
|
// src/urlytics-engine.ts
|
|
4469
4430
|
class UrlyticsEngine {
|
|
4470
4431
|
static parseUrl(rawUrl) {
|
|
@@ -7102,7 +7063,6 @@ export {
|
|
|
7102
7063
|
IndexNowClient,
|
|
7103
7064
|
I18nDetector,
|
|
7104
7065
|
HyperswitchGateway,
|
|
7105
|
-
GoogleTranslateBridge,
|
|
7106
7066
|
GeoMeshLinkingEngine,
|
|
7107
7067
|
FreePublicToolsEngine,
|
|
7108
7068
|
ExtendedSchemaGraphBuilder,
|
package/package.json
CHANGED
package/src/engine.test.ts
CHANGED
|
@@ -11,7 +11,6 @@ import { I18nDetector } from "./i18n-detector";
|
|
|
11
11
|
import { renderUiIconSvg, resolveFeatureIcon } from "./ui-icons";
|
|
12
12
|
import { OgImageGenerator } from "./og-image-generator";
|
|
13
13
|
import { FreePublicToolsEngine } from "./free-public-tools";
|
|
14
|
-
import { GoogleTranslateBridge } from "./google-translate-bridge";
|
|
15
14
|
|
|
16
15
|
describe("Multilingual SEO Slug Engine (10+ Languages)", () => {
|
|
17
16
|
it("English: Strips stop words and years", () => {
|
|
@@ -338,12 +337,4 @@ describe("Audited Reference Engines (Advertools, Santifer, Seonaut)", () => {
|
|
|
338
337
|
const schema = FreePublicToolsEngine.generateSampleSchema("softwareApp", "Acme", "https://acme.com");
|
|
339
338
|
expect(schema["@type"]).toBe("SoftwareApplication");
|
|
340
339
|
});
|
|
341
|
-
|
|
342
|
-
it("GoogleTranslateBridge: Translates texts and handles batch translation", async () => {
|
|
343
|
-
const identical = await GoogleTranslateBridge.translateText("Bonjour", "fr", "fr");
|
|
344
|
-
expect(identical).toBe("Bonjour");
|
|
345
|
-
|
|
346
|
-
const batch = await GoogleTranslateBridge.translateBatch(["Hello", "World"], "en", "en");
|
|
347
|
-
expect(batch).toEqual(["Hello", "World"]);
|
|
348
|
-
});
|
|
349
340
|
});
|
package/src/i18n-dictionary.ts
CHANGED
|
@@ -31,8 +31,8 @@ export const DICTIONARIES: Record<string, LocaleCopy> = {
|
|
|
31
31
|
// 🇫🇷 French (Europe / Africa / Canada)
|
|
32
32
|
fr: {
|
|
33
33
|
geoTitle: (s, city, country, b) => `${s} à ${city} (${country}) — ${b}`,
|
|
34
|
-
geoDesc: (s, city) => `Découvrez la solution de ${s} à ${city}. Automatisez vos opérations et boostez votre croissance
|
|
35
|
-
geoDirectAnswer: (b, s, city, country, price, cur) => `${b} est la solution de référence pour ${s} à ${city} (${country}). Déploiement en 10 minutes dès ${price} ${cur}/mois avec
|
|
34
|
+
geoDesc: (s, city) => `Découvrez la solution de ${s} à ${city}. Automatisez vos opérations et boostez votre croissance.`,
|
|
35
|
+
geoDirectAnswer: (b, s, city, country, price, cur) => `${b} est la solution de référence pour ${s} à ${city} (${country}). Déploiement en 10 minutes dès ${price} ${cur}/mois avec avis clients synchronisés et support dédié.`,
|
|
36
36
|
vsTitle: (b, comp, y) => `${b} vs ${comp} : Comparatif Complet & Tarifs ${y}`,
|
|
37
37
|
vsDesc: (b, comp) => `Pourquoi choisir ${b} plutôt que ${comp} ? Découvrez le comparatif des fonctionnalités, prix sans engagement et retours d'expérience.`,
|
|
38
38
|
vsDirectAnswer: (b, comp) => `${b} se distingue de ${comp} par une tarification transparente sans engagement, une automatisation IA native 24/7 et un support client réactif.`,
|
|
@@ -51,8 +51,8 @@ export const DICTIONARIES: Record<string, LocaleCopy> = {
|
|
|
51
51
|
// 🇬🇧 English (Global)
|
|
52
52
|
en: {
|
|
53
53
|
geoTitle: (s, city, country, b) => `${s} in ${city} (${country}) — ${b}`,
|
|
54
|
-
geoDesc: (s, city) => `Discover the leading ${s} solution in ${city}. Automate your operations, scale revenue, and save
|
|
55
|
-
geoDirectAnswer: (b, s, city, country, price, cur) => `${b} is the
|
|
54
|
+
geoDesc: (s, city) => `Discover the leading ${s} solution in ${city}. Automate your operations, scale revenue, and save time every week.`,
|
|
55
|
+
geoDirectAnswer: (b, s, city, country, price, cur) => `${b} is the leading ${s} platform in ${city} (${country}). 10-minute setup starting at ${cur}${price}/mo with verified customer review integration.`,
|
|
56
56
|
vsTitle: (b, comp, y) => `${b} vs ${comp}: Full Feature Comparison & Pricing ${y}`,
|
|
57
57
|
vsDesc: (b, comp) => `Why switch from ${comp} to ${b}? Compare key features, transparent pricing with no lock-in, and customer ROI.`,
|
|
58
58
|
vsDirectAnswer: (b, comp) => `${b} beats ${comp} with native 24/7 AI automation, flexible no-contract pricing, and instant omnichannel setup.`,
|
package/src/index.ts
CHANGED
|
@@ -20,7 +20,6 @@ export * from "./brand-icons";
|
|
|
20
20
|
export * from "./ui-icons";
|
|
21
21
|
export * from "./og-image-generator";
|
|
22
22
|
export * from "./free-public-tools";
|
|
23
|
-
export * from "./google-translate-bridge";
|
|
24
23
|
export * from "./urlytics-engine";
|
|
25
24
|
export * from "./keyword-permutator";
|
|
26
25
|
export * from "./llm-prompt";
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 🌐 Google Translation Engine Bridge
|
|
3
|
-
* Provides fast, batch, zero-cost multilingual translation for Programmatic SEO pages,
|
|
4
|
-
* markdown documentation, and schema descriptions across 40+ global languages.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export class GoogleTranslateBridge {
|
|
8
|
-
/**
|
|
9
|
-
* Translates a single text string into the target language using Google's public translation endpoint.
|
|
10
|
-
*/
|
|
11
|
-
static async translateText(
|
|
12
|
-
text: string,
|
|
13
|
-
targetLang: string,
|
|
14
|
-
sourceLang: string = "auto",
|
|
15
|
-
): Promise<string> {
|
|
16
|
-
if (!text || !text.trim()) return "";
|
|
17
|
-
const cleanTarget = targetLang.toLowerCase().split(/[-_]/)[0];
|
|
18
|
-
const cleanSource = sourceLang.toLowerCase().split(/[-_]/)[0];
|
|
19
|
-
|
|
20
|
-
if (cleanTarget === cleanSource) return text;
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${cleanSource}&tl=${cleanTarget}&dt=t&q=${encodeURIComponent(
|
|
24
|
-
text,
|
|
25
|
-
)}`;
|
|
26
|
-
|
|
27
|
-
const res = await fetch(url);
|
|
28
|
-
if (!res.ok) return text;
|
|
29
|
-
|
|
30
|
-
const data = (await res.json()) as any;
|
|
31
|
-
if (Array.isArray(data) && Array.isArray(data[0])) {
|
|
32
|
-
return data[0].map((item: any) => item[0]).join("");
|
|
33
|
-
}
|
|
34
|
-
return text;
|
|
35
|
-
} catch {
|
|
36
|
-
return text; // Safe fallback to original text
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Batch translates an array of strings in parallel with concurrency throttling.
|
|
42
|
-
*/
|
|
43
|
-
static async translateBatch(
|
|
44
|
-
texts: string[],
|
|
45
|
-
targetLang: string,
|
|
46
|
-
sourceLang: string = "auto",
|
|
47
|
-
): Promise<string[]> {
|
|
48
|
-
if (!texts || texts.length === 0) return [];
|
|
49
|
-
return Promise.all(texts.map((t) => this.translateText(t, targetLang, sourceLang)));
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Translates a structured key-value object (e.g. SEO page meta or FAQ list).
|
|
54
|
-
*/
|
|
55
|
-
static async translateObject<T extends Record<string, string>>(
|
|
56
|
-
obj: T,
|
|
57
|
-
targetLang: string,
|
|
58
|
-
sourceLang: string = "auto",
|
|
59
|
-
): Promise<T> {
|
|
60
|
-
const keys = Object.keys(obj) as (keyof T)[];
|
|
61
|
-
const values = keys.map((k) => obj[k]);
|
|
62
|
-
const translatedValues = await this.translateBatch(values, targetLang, sourceLang);
|
|
63
|
-
|
|
64
|
-
const result = {} as T;
|
|
65
|
-
keys.forEach((k, idx) => {
|
|
66
|
-
result[k] = translatedValues[idx] as any;
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
return result;
|
|
70
|
-
}
|
|
71
|
-
}
|