Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
<body>
<header class="tw-header">
<nav class="tw-nav">
<p> 😀</p>
<p> hello there i m vineet 😀</p>
<a href="#home">Home</a>
<a href="#products">Product</a>
<a href="#about">About</a>
Expand Down
60 changes: 23 additions & 37 deletions src/lib/storage/localstorage.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import LZString from "lz-string";
import { TranslationContent } from "../../types";

export class LocalStorageWrapper {
private prefix: string;
private readonly COMPRESSION_THRESHOLD = 10000;
private readonly COMPRESSION_THRESHOLD = 100000;
private readonly COMPRESSION_MARKER = "__COMPRESSED__";

constructor(prefix = "") {
this.prefix = prefix;
}

getPageKey(url: string, targetLang: string): string {
const urlWithoutQuery = url.split("?")[0];
return `${this.prefix}page-${encodeURIComponent(urlWithoutQuery)}-${targetLang}`;
getPageKey(targetLang: string): string {
return `${this.prefix}-${targetLang}`;
}

private shouldCompress(value: string): boolean {
Expand All @@ -36,7 +36,7 @@ export class LocalStorageWrapper {
}
}

getItem(key: string): any {
getItem(key: string): TranslationContent | null {
const item = localStorage.getItem(key);
if (!item) return null;

Expand All @@ -49,7 +49,7 @@ export class LocalStorageWrapper {
}
}

setItem(key: string, value: any): void {
setItem(key: string, value: TranslationContent): void {
const stringified = JSON.stringify(value);
const storeValue = () => {
try {
Expand All @@ -67,48 +67,34 @@ export class LocalStorageWrapper {
}
}

// Get translation for a node from the page cache (object of node hashes)
getNodeTranslation(nodeHash: string, url: string, targetLang: string): { o: string; t: string } | null {
const pageKey = this.getPageKey(url, targetLang);
const translations: { [key: string]: { o: string; t: string } } = this.getItem(pageKey) || {};
const nodeKey = `jss-node-${nodeHash}`;
return translations[nodeKey] || null;
// Get translation for a node from the page cache (object of originalText)
getNodeTranslation(originalText: string, targetLang: string): string | null {
const pageKey = this.getPageKey(targetLang);
const translations: TranslationContent = this.getItem(pageKey) || {};
return translations[originalText] || null;
}

// Store translation for a node in the page cache (object of node hashes)
setNodeTranslation(nodeHash: string, url: string, targetLang: string, translation: { o: string; t: string }): void {
const pageKey = this.getPageKey(url, targetLang);
let translations: { [key: string]: { o: string; t: string } }[] = this.getItem(pageKey) || [];
const nodeKey = `${nodeHash}`;
translations.push({ [nodeKey]: translation });
this.setItem(pageKey, translations);
// Store translation for a node in the page cache (object of originalText)
setNodeTranslation(originalText: string, targetLang: string, translatedText: string): void {
const pageKey = this.getPageKey(targetLang);
let translations: TranslationContent = this.getItem(pageKey) || {};
translations[originalText] = translatedText;
this.setItem(pageKey, translations );
}

setBatchNodeTranslationsArray(
url: string,
targetLang: string,
batch: Array<{ [key: string]: { o: string; t: string } }>
batch: Array<{ originalText: string; translatedText: string }>
): void {
const pageKey = this.getPageKey(url, targetLang);
const existing: Array<{ [key: string]: { o: string; t: string } }> = this.getItem(pageKey) || [];

// Convert existing to a map for fast lookup
const map: { [key: string]: { o: string; t: string } } = {};
existing.forEach(obj => {
const key = Object.keys(obj)[0];
map[key] = obj[key];
});
const pageKey = this.getPageKey(targetLang);
const existing: TranslationContent = this.getItem(pageKey) || {};

// Add/overwrite with new batch
batch.forEach(obj => {
const key = Object.keys(obj)[0];
map[key] = obj[key];
batch.forEach(({ originalText, translatedText }) => {
existing[originalText] = translatedText;
});

// Convert back to array of objects
const merged = Object.keys(map).map(key => ({ [key]: map[key] }));

this.setItem(pageKey, merged);
this.setItem(pageKey, existing);
}

removeItem(key: string): void {
Expand Down
4 changes: 3 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,6 @@ export interface TranslationResult {
translatedNodes: number;
error?: string;
duration?: number;
}
}

export interface TranslationContent { [key: string]: string }
24 changes: 9 additions & 15 deletions src/widget/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { languages } from "../constants/languages";
import { BATCH_SIZE, DEFAULT_CONFIG } from "../constants";
import type { Language, TranslationConfig, WidgetElements, TranslationResult } from "../types";
import widgetTemplate from "../templates/html/widget.html?raw";
import { generateHashForContent, generateNodeHash, getUserLanguage, removeEmojis } from "../utils/utils";
import { generateHashForContent, getUserLanguage, removeEmojis } from "../utils/utils";
import { CACHE_PREFIX } from "../constants";
import { LocalStorageWrapper } from "../lib/storage/localstorage";

Expand Down Expand Up @@ -445,17 +445,14 @@ export class TranslationWidget {

// Add text and node to the batch if valid
if (textToTranslate) {
const nodeHash = generateNodeHash(textToTranslate);
// Use the new cache structure: array of objects
const cacheArray = cache.getItem(cache.getPageKey(window.location.href, targetLang)) || [];
const found = cacheArray.find((obj: Record<string, { o: string; t: string }>) => Object.prototype.hasOwnProperty.call(obj, nodeHash));
const cachedTranslation = found ? found[nodeHash] : null;

const cacheObject = cache.getItem(cache.getPageKey(targetLang)) || {};
const cachedTranslation = cacheObject[textToTranslate] || null;

if (cachedTranslation) {
// Use cached translation
if (this.lastRequestedLanguage === targetLang) {
const originalText = cachedTranslation.o;
const translatedText = cachedTranslation.t;
const originalText = textToTranslate;
const translatedText = cachedTranslation;
const originalFontSize = parent.getAttribute("data-original-font-size") || "16px";
const newFontSize = this.calculateFontSize(translatedText, originalFontSize, originalText);
parent.style.fontSize = newFontSize;
Expand All @@ -466,7 +463,6 @@ export class TranslationWidget {

textsToTranslate.push(textToTranslate.trim());
batchNodes.push(node);
batchNodeHashes.push(nodeHash);
}
});

Expand All @@ -492,20 +488,18 @@ export class TranslationWidget {
);

// Process translated batches
const batchArray: Array<{ [key: string]: { o: string; t: string } }> = [];
const batchArray: Array<{ originalText: string; translatedText: string }> = [];
allTranslatedTexts.forEach((translations, batchIndex) => {
const batchNodes = allBatchNodes[batchIndex];
const batchNodeHashes = allBatchNodeHashes[batchIndex];

batchNodes.forEach((node, nodeIndex) => {
const parent = node.element;
if (parent) {
const originalText = node.text;
const translatedText = translations[nodeIndex];
const nodeHash = batchNodeHashes[nodeIndex];

// Collect the translation for batch saving
batchArray.push({ [`${nodeHash}`]: { o: originalText, t: translatedText } });
batchArray.push({ originalText, translatedText });

// Update DOM if this is the most recent request
if (this.lastRequestedLanguage === targetLang) {
Expand All @@ -520,7 +514,7 @@ export class TranslationWidget {

// Save all translations in one batch
if (batchArray.length > 0) {
cache.setBatchNodeTranslationsArray(window.location.href, targetLang, batchArray);
cache.setBatchNodeTranslationsArray(targetLang, batchArray);
}

// Update UI state if this is the most recent request
Expand Down