Add locale data loading for extensions

e312ae6b3bdfdf90ff2e71c3bd1be9912676358e

Cohee <18619528+Cohee1207@users.noreply.github.com>

3 files changed, +65 -3Ignore whitespace
public/scripts/extensions.js+38 -2
@@ -7,7 +7,7 @@ import { renderTemplate, renderTemplateAsync } from './templates.js';
7import { delay, isSubsetOf, sanitizeSelector, setValueByPath } from './utils.js';7import { delay, isSubsetOf, sanitizeSelector, setValueByPath } from './utils.js';
8import { getContext } from './st-context.js';8import { getContext } from './st-context.js';
9import { isAdmin } from './user.js';9import { isAdmin } from './user.js';
10import { t } from './i18n.js';10import { addLocaleData, getCurrentLocale, t } from './i18n.js';
11import { debounce_timeout } from './constants.js';11import { debounce_timeout } from './constants.js';
12import { accountStorage } from './util/AccountStorage.js';12import { accountStorage } from './util/AccountStorage.js';
1313
@@ -384,7 +384,7 @@ async function activateExtensions() {
384 if (meetsModuleRequirements && !isDisabled) {384 if (meetsModuleRequirements && !isDisabled) {
385 try {385 try {
386 console.debug('Activating extension', name);386 console.debug('Activating extension', name);
387 const promise = Promise.all([addExtensionScript(name, manifest), addExtensionStyle(name, manifest)]);387 const promise = Promise.all([addExtensionScript(name, manifest), addExtensionStyle(name, manifest), addExtensionLocale(name, manifest)]);
388 await promise388 await promise
389 .then(() => activeExtensions.add(name))389 .then(() => activeExtensions.add(name))
390 .catch(err => console.log('Could not activate extension', name, err));390 .catch(err => console.log('Could not activate extension', name, err));
@@ -577,6 +577,42 @@ function addExtensionScript(name, manifest) {
577}577}
578578
579/**579/**
580 * Adds a localization data for an extension.
581 * @param {string} name Extension name
582 * @param {object} manifest Manifest object
583 */
584function addExtensionLocale(name, manifest) {
585 // No i18n data in the manifest
586 if (!manifest.i18n || typeof manifest.i18n !== 'object') {
587 return Promise.resolve();
588 }
589
590 const currentLocale = getCurrentLocale();
591 const localeFile = manifest.i18n[currentLocale];
592
593 // Manifest doesn't provide a locale file for the current locale
594 if (!localeFile) {
595 return Promise.resolve();
596 }
597
598 return fetch(`/scripts/extensions/${name}/${localeFile}`)
599 .then(async response => {
600 if (!response.ok) {
601 throw new Error(`HTTP ${response.status}: ${response.statusText}`);
602 }
603
604 const data = await response.json();
605
606 if (data && typeof data === 'object') {
607 addLocaleData(currentLocale, data);
608 }
609 })
610 .catch(err => {
611 console.log('Could not load extension locale data for ' + name, err);
612 });
613}
614
615/**
580 * Generates HTML string for displaying an extension in the UI.616 * Generates HTML string for displaying an extension in the UI.
581 *617 *
582 * @param {string} name - The name of the extension.618 * @param {string} name - The name of the extension.
public/scripts/i18n.js+24 -0
@@ -12,6 +12,30 @@ var localeData;
12export const getCurrentLocale = () => localeFile;12export const getCurrentLocale = () => localeFile;
1313
14/**14/**
15 * Adds additional localization data to the current locale file.
16 * @param {string} localeId Locale ID (e.g. 'fr-fr' or 'zh-cn')
17 * @param {Record<string, string>} data Localization data to add
18 */
19export function addLocaleData(localeId, data) {
20 if (!localeData) {
21 console.warn('Localization data not loaded yet. Additional data will not be added.');
22 return;
23 }
24
25 if (localeId !== localeFile) {
26 console.debug('Ignoring addLocaleData call for different locale', localeId);
27 return;
28 }
29
30 for (const [key, value] of Object.entries(data)) {
31 // Overrides for default locale data are not allowed
32 if (!Object.hasOwn(localeData, key)) {
33 localeData[key] = value;
34 }
35 }
36}
37
38/**
15 * An observer that will check if any new i18n elements are added to the document39 * An observer that will check if any new i18n elements are added to the document
16 * @type {MutationObserver}40 * @type {MutationObserver}
17 */41 */
public/scripts/st-context.js+3 -1
@@ -54,7 +54,7 @@ import {
54 writeExtensionField,54 writeExtensionField,
55} from './extensions.js';55} from './extensions.js';
56import { groups, openGroupChat, selected_group } from './group-chats.js';56import { groups, openGroupChat, selected_group } from './group-chats.js';
57import { t, translate } from './i18n.js';57import { addLocaleData, getCurrentLocale, t, translate } from './i18n.js';
58import { hideLoader, showLoader } from './loader.js';58import { hideLoader, showLoader } from './loader.js';
59import { MacrosParser } from './macros.js';59import { MacrosParser } from './macros.js';
60import { getChatCompletionModel, oai_settings } from './openai.js';60import { getChatCompletionModel, oai_settings } from './openai.js';
@@ -165,6 +165,8 @@ export function getContext() {
165 isMobile,165 isMobile,
166 t,166 t,
167 translate,167 translate,
168 getCurrentLocale,
169 addLocaleData,
168 tags,170 tags,
169 tagMap: tag_map,171 tagMap: tag_map,
170 menuType: menu_type,172 menuType: menu_type,