Sync widget copy translations on save
This commit is contained in:
@@ -358,20 +358,20 @@ function defaultWidgetCopy(language) {
|
||||
};
|
||||
}
|
||||
return {
|
||||
title: "Potrebujete poradit?",
|
||||
intro: "Napiste nam. Odpovime co nejdrive.",
|
||||
offlineIntro: "Ted nejsme online, ale zpravu nam muzete nechat.",
|
||||
placeholder: "Napiste zpravu...",
|
||||
title: "Potřebujete poradit?",
|
||||
intro: "Napište nám. Odpovíme co nejdříve.",
|
||||
offlineIntro: "Teď nejsme online, ale zprávu nám můžete nechat.",
|
||||
placeholder: "Napište zprávu...",
|
||||
sendLabel: "Odeslat",
|
||||
dropzoneLabel: "Pridat fotku nebo pretahnout",
|
||||
dropzoneLabel: "Přidat fotku nebo přetáhnout",
|
||||
onlineLabel: "Jsme online",
|
||||
offlineLabel: "Offline",
|
||||
newReplyLabel: "Nova odpoved",
|
||||
typingLabel: "Operator pise...",
|
||||
newReplyLabel: "Nová odpověď",
|
||||
typingLabel: "Operátor píše...",
|
||||
infoTitle: "GDPR informace",
|
||||
infoText: "Zpravu a technicke udaje relace zpracujeme jen pro odpoved na vas dotaz.",
|
||||
closeLabel: "Zmensit chat",
|
||||
operatorReplyLabel: "odpovida"
|
||||
infoText: "Zprávu a technické údaje relace zpracujeme jen pro odpověď na váš dotaz.",
|
||||
closeLabel: "Zmenšit chat",
|
||||
operatorReplyLabel: "odpovídá"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -522,6 +522,8 @@ async function updateSite(req, res) {
|
||||
const currentSettings = parseJson(site.settings_json, defaultSettings());
|
||||
const incomingSettings = body.settings || {};
|
||||
const settings = mergeSiteSettings(currentSettings, incomingSettings);
|
||||
const widgetCopySync = await syncChangedWidgetCopyTranslations(currentSettings, settings);
|
||||
syncLegacyWidgetCopy(settings);
|
||||
db.prepare(`
|
||||
UPDATE sites
|
||||
SET is_online = ?, settings_json = ?, updated_at = CURRENT_TIMESTAMP
|
||||
@@ -529,7 +531,7 @@ async function updateSite(req, res) {
|
||||
`).run(body.isOnline ? 1 : 0, JSON.stringify(settings), site.id);
|
||||
const updated = getDefaultSite();
|
||||
publish("admin", { type: "site:update", site: formatSite(updated) });
|
||||
return json(res, 200, { site: formatSite(updated), snippet: snippetFor(updated) });
|
||||
return json(res, 200, { site: formatSite(updated), snippet: snippetFor(updated), widgetCopySync });
|
||||
}
|
||||
|
||||
function adminUsers(res) {
|
||||
@@ -1205,6 +1207,58 @@ async function translateWidgetCopyOnce(sourceCopy, sourceLanguage, targetLanguag
|
||||
}
|
||||
}
|
||||
|
||||
async function syncChangedWidgetCopyTranslations(previousSettings, nextSettings) {
|
||||
const languageSettings = normalizeWidgetLanguageSettings(nextSettings.widgetLanguage);
|
||||
const defaultLanguage = languageSettings.defaultLanguage;
|
||||
const previousCopy = normalizeWidgetCopy(previousSettings.widgetCopy || {}, previousSettings);
|
||||
const nextCopy = normalizeWidgetCopy(nextSettings.widgetCopy || {}, nextSettings);
|
||||
const previousDefaultCopy = previousCopy[defaultLanguage] || {};
|
||||
const nextDefaultCopy = nextCopy[defaultLanguage] || {};
|
||||
const changedFields = WIDGET_COPY_FIELDS.filter((field) =>
|
||||
String(previousDefaultCopy[field] || "").trim() !== String(nextDefaultCopy[field] || "").trim()
|
||||
);
|
||||
if (!changedFields.length) return { changedFields: [], languages: [], translated: false, errors: [] };
|
||||
|
||||
const translationSettings = {
|
||||
...defaultSettings().translations,
|
||||
...(nextSettings.translations || {})
|
||||
};
|
||||
const apiKey = normalizeOpenAiApiKey(translationSettings.openaiApiKey) || OPENAI_API_KEY;
|
||||
const model = String(translationSettings.model || OPENAI_TRANSLATION_MODEL).trim() || OPENAI_TRANSLATION_MODEL;
|
||||
const languages = Object.keys(nextCopy)
|
||||
.map(allowedWidgetLanguage)
|
||||
.filter((language, index, list) => language && language !== defaultLanguage && list.indexOf(language) === index);
|
||||
|
||||
if (!languages.length) return { changedFields, languages: [], translated: false, errors: [] };
|
||||
if (!translationSettings.enabled || !apiKey) {
|
||||
return { changedFields, languages, translated: false, errors: languages.map((language) => ({ language, error: "missing_ai_settings" })) };
|
||||
}
|
||||
|
||||
nextSettings.widgetCopy = nextCopy;
|
||||
const errors = [];
|
||||
let translated = 0;
|
||||
for (const language of languages) {
|
||||
nextSettings.widgetCopy[language] = normalizeWidgetCopyEntry(nextSettings.widgetCopy[language] || {}, language);
|
||||
for (const field of changedFields) {
|
||||
const value = String(nextDefaultCopy[field] || "").trim();
|
||||
if (!value) {
|
||||
nextSettings.widgetCopy[language][field] = "";
|
||||
translated += 1;
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
const result = await translateText(value, language, model, apiKey);
|
||||
nextSettings.widgetCopy[language][field] = String(result.translatedText || value).trim();
|
||||
translated += 1;
|
||||
} catch (error) {
|
||||
console.error("widget_copy_sync_failed", language, field, error.message);
|
||||
errors.push({ language, field, error: classifyOpenAiError(error.message), message: error.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
return { changedFields, languages, translated: translated > 0, errors };
|
||||
}
|
||||
|
||||
function widgetCopyLooksUntranslated(sourceCopy, translatedCopy) {
|
||||
const importantFields = ["title", "intro", "offlineIntro", "placeholder", "sendLabel"];
|
||||
return importantFields.every((field) => String(sourceCopy[field] || "").trim() === String(translatedCopy[field] || "").trim());
|
||||
|
||||
Reference in New Issue
Block a user