diff --git a/src/editor/ConfigObj.js b/src/editor/ConfigObj.js index 6a83d64d..1e701aec 100644 --- a/src/editor/ConfigObj.js +++ b/src/editor/ConfigObj.js @@ -170,11 +170,12 @@ export default class ConfigObj { // 'ext-markers', 'ext-overview_window', 'ext-panning', - 'ext-polygon', 'ext-shapes', 'ext-star', + 'ext-polygon', 'ext-storage', - 'ext-opensave' + 'ext-opensave', + 'ext-helloworld', ]; this.curConfig = { // We do not put on defaultConfig to simplify object copying diff --git a/src/editor/extensions/ext-eyedropper/ext-eyedropper.js b/src/editor/extensions/ext-eyedropper/ext-eyedropper.js index 2cde4162..60c8f35c 100644 --- a/src/editor/extensions/ext-eyedropper/ext-eyedropper.js +++ b/src/editor/extensions/ext-eyedropper/ext-eyedropper.js @@ -4,27 +4,19 @@ * @license MIT * * @copyright 2010 Jeff Schiller + * @copyright 2021 OptimistikSAS * */ -const loadExtensionTranslation = async function (lang) { - let translationModule; - try { - // eslint-disable-next-line no-unsanitized/method - translationModule = await import(`./locale/${encodeURIComponent(lang)}.js`); - } catch (_error) { - // eslint-disable-next-line no-console - console.error(`Missing translation (${lang}) - using 'en'`); - translationModule = await import(`./locale/en.js`); - } - return translationModule.default; -}; +import { loadExtensionTranslation } from '../../locale.js'; + +const name = "eyedropper"; export default { - name: 'eyedropper', + name, async init(S) { const svgEditor = this; - const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang')); + await loadExtensionTranslation(svgEditor, name); const { ChangeElementCommand } = S, // , svgcontent, // svgdoc = S.svgroot.parentNode.ownerDocument, { svgCanvas } = svgEditor, @@ -74,12 +66,15 @@ export default { }; return { - name: strings.name, + name: svgEditor.i18next.t(`${name}:name`), callback() { // Add the button and its handler(s) const buttonTemplate = document.createElement("template"); + const title = svgEditor.i18next.t(`${name}:buttons.0.title`); + const key = svgEditor.i18next.t(`${name}:buttons.0.key`); + // eslint-disable-next-line no-unsanitized/property buttonTemplate.innerHTML = ` - + `; $id('tools_left').append(buttonTemplate.content.cloneNode(true)); $id('tool_eyedropper').addEventListener("click", () => { diff --git a/src/editor/extensions/ext-eyedropper/locale/fr.js b/src/editor/extensions/ext-eyedropper/locale/fr.js new file mode 100644 index 00000000..525cbf77 --- /dev/null +++ b/src/editor/extensions/ext-eyedropper/locale/fr.js @@ -0,0 +1,9 @@ +export default { + name: 'pipette', + buttons: [ + { + title: 'Outil pipette', + key: 'I' + } + ] +}; diff --git a/src/editor/extensions/ext-grid/ext-grid.js b/src/editor/extensions/ext-grid/ext-grid.js index 0291f4e7..37e998ca 100644 --- a/src/editor/extensions/ext-grid/ext-grid.js +++ b/src/editor/extensions/ext-grid/ext-grid.js @@ -7,24 +7,15 @@ * */ -const loadExtensionTranslation = async function (lang) { - let translationModule; - try { - // eslint-disable-next-line no-unsanitized/method - translationModule = await import(`./locale/${encodeURIComponent(lang)}.js`); - } catch (_error) { - // eslint-disable-next-line no-console - console.error(`Missing translation (${lang}) - using 'en'`); - translationModule = await import(`./locale/en.js`); - } - return translationModule.default; -}; + import { loadExtensionTranslation } from '../../locale.js'; + + const name = "grid"; export default { - name: 'grid', + name, async init ({ NS, getTypeMap }) { const svgEditor = this; - const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang')); + await loadExtensionTranslation(svgEditor, name); const { svgCanvas } = svgEditor; const { $id } = svgCanvas; const svgdoc = document.getElementById('svgcanvas').ownerDocument; @@ -152,15 +143,18 @@ export default { document.getElementById('view_grid').pressed = showGrid; }; return { - name: strings.name, + name: svgEditor.i18next.t(`${name}:name`), zoomChanged (zoom) { if (showGrid) { updateGrid(zoom); } }, callback () { // Add the button and its handler(s) const buttonTemplate = document.createElement("template"); + const title = svgEditor.i18next.t(`${name}:buttons.0.title`); + + // eslint-disable-next-line no-unsanitized/property buttonTemplate.innerHTML = ` - + `; $id('editor_panel').append(buttonTemplate.content.cloneNode(true)); $id('view_grid').addEventListener("click", () => { diff --git a/src/editor/extensions/ext-grid/locale/fr.js b/src/editor/extensions/ext-grid/locale/fr.js new file mode 100644 index 00000000..60f5b63b --- /dev/null +++ b/src/editor/extensions/ext-grid/locale/fr.js @@ -0,0 +1,8 @@ +export default { + name: 'Grille', + buttons: [ + { + title: 'Afficher/Cacher Grille' + } + ] +}; diff --git a/src/editor/extensions/ext-helloworld/ext-helloworld.js b/src/editor/extensions/ext-helloworld/ext-helloworld.js index c7b1b73b..1afc39c6 100644 --- a/src/editor/extensions/ext-helloworld/ext-helloworld.js +++ b/src/editor/extensions/ext-helloworld/ext-helloworld.js @@ -13,39 +13,32 @@ * will show the user the point on the canvas that was clicked on. */ -const loadExtensionTranslation = async function (lang) { - let translationModule; - try { - // eslint-disable-next-line no-unsanitized/method - translationModule = await import(`./locale/${encodeURIComponent(lang)}.js`); - } catch (_error) { - // eslint-disable-next-line no-console - console.error(`Missing translation (${lang}) - using 'en'`); - translationModule = await import(`./locale/en.js`); - } - return translationModule.default; -}; +import { loadExtensionTranslation } from '../../locale.js'; + +const name = "helloworld"; export default { - name: 'helloworld', + name, async init ({ _importLocale }) { const svgEditor = this; - const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang')); + await loadExtensionTranslation(svgEditor, name); const { svgCanvas } = svgEditor; + const { $id } = svgCanvas; return { - name: strings.name, - events: [ { - // Must match the icon ID in helloworld-icon.xml - id: 'hello_world', - // Tooltip text - title: strings.buttons[0].title, - click () { - // The action taken when the button is clicked on. - // For "mode" buttons, any other button will - // automatically be de-pressed. + name: svgEditor.i18next.t(`${name}:name`), + callback() { + // Add the button and its handler(s) + const buttonTemplate = document.createElement("template"); + const title = svgEditor.i18next.t(`${name}:buttons.0.title`); + // eslint-disable-next-line no-unsanitized/property + buttonTemplate.innerHTML = ` + + `; + $id('tools_left').append(buttonTemplate.content.cloneNode(true)); + $id('hello_world').addEventListener("click", () => { svgCanvas.setMode('hello_world'); - } - } ], + }); + }, // This is triggered when the main mouse button is pressed down // on the editor canvas (not the tool panels) mouseDown () { @@ -70,14 +63,7 @@ export default { const y = opts.mouse_y / zoom; // We do our own formatting - let { text } = strings; - [ - [ 'x', x ], - [ 'y', y ] - ].forEach(([ prop, val ]) => { - text = text.replace('{' + prop + '}', val); - }); - + let text = svgEditor.i18next.t(`${name}:text`, { x, y }); // Show the text using the custom alert function alert(text); } diff --git a/src/editor/extensions/ext-helloworld/locale/en.js b/src/editor/extensions/ext-helloworld/locale/en.js index e52406fa..f7413775 100644 --- a/src/editor/extensions/ext-helloworld/locale/en.js +++ b/src/editor/extensions/ext-helloworld/locale/en.js @@ -1,6 +1,6 @@ export default { name: 'Hello World', - text: 'Hello World!\n\nYou clicked here: {x}, {y}', + text: 'Hello World!\n\nYou clicked here: {{x}}, {{y}}', buttons: [ { title: "Say 'Hello World'" diff --git a/src/editor/extensions/ext-helloworld/locale/fr.js b/src/editor/extensions/ext-helloworld/locale/fr.js new file mode 100644 index 00000000..01e044ac --- /dev/null +++ b/src/editor/extensions/ext-helloworld/locale/fr.js @@ -0,0 +1,9 @@ +export default { + name: 'Bonjour le Monde', + text: 'Bonjour le Monde!\n\nVous avez cliqué ici: {{x}}, {{y}}', + buttons: [ + { + title: "Dire 'Bonjour le Monde'" + } + ] +}; diff --git a/src/editor/extensions/ext-helloworld/locale/zh-CN.js b/src/editor/extensions/ext-helloworld/locale/zh-CN.js index 87912014..608da298 100755 --- a/src/editor/extensions/ext-helloworld/locale/zh-CN.js +++ b/src/editor/extensions/ext-helloworld/locale/zh-CN.js @@ -1,6 +1,6 @@ export default { name: 'Hello World', - text: 'Hello World!\n\n 请点击: {x}, {y}', + text: 'Hello World!\n\n 请点击: {{x}}, {{y}}', buttons: [ { title: "输出 'Hello World'" diff --git a/src/editor/extensions/ext-polygon/ext-polygon.js b/src/editor/extensions/ext-polygon/ext-polygon.js index fe2ccf9e..a662e926 100644 --- a/src/editor/extensions/ext-polygon/ext-polygon.js +++ b/src/editor/extensions/ext-polygon/ext-polygon.js @@ -6,119 +6,114 @@ * */ -const loadExtensionTranslation = async function (lang) { - let translationModule; - try { - // eslint-disable-next-line no-unsanitized/method - translationModule = await import(`./locale/${encodeURIComponent(lang)}.js`); - } catch (_error) { - // eslint-disable-next-line no-console - console.error(`Missing translation (${lang}) - using 'en'`); - translationModule = await import(`./locale/en.js`); - } - return translationModule.default; -}; +import { loadExtensionTranslation } from "../../locale.js"; + +const name = "polygon"; export default { - name: 'polygon', - async init (_S) { + name, + async init(_S) { const svgEditor = this; const { svgCanvas } = svgEditor; const { $id } = svgCanvas; // const editingitex = false; - const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang')); + await loadExtensionTranslation(svgEditor, name); let selElems; let started; let newFO; /** - * @param {boolean} on - * @returns {void} - */ - const showPanel = (on) => { - $id('polygon_panel').style.display = (on) ? 'block' : 'none'; + * @param {boolean} on + * @returns {void} + */ + const showPanel = on => { + $id("polygon_panel").style.display = on ? "block" : "none"; }; /** - * @param {string} attr - * @param {string|Float} val - * @returns {void} - */ + * @param {string} attr + * @param {string|Float} val + * @returns {void} + */ const setAttr = (attr, val) => { svgCanvas.changeSelectedAttribute(attr, val); - svgCanvas.call('changed', selElems); + svgCanvas.call("changed", selElems); }; /** - * @param {Float} n - * @returns {Float} - */ - const cot = (n) => (1 / Math.tan(n)); + * @param {Float} n + * @returns {Float} + */ + const cot = n => 1 / Math.tan(n); /** - * @param {Float} n - * @returns {Float} - */ - const sec = (n) => (1 / Math.cos(n)); + * @param {Float} n + * @returns {Float} + */ + const sec = n => 1 / Math.cos(n); return { - name: strings.name, + name: svgEditor.i18next.t(`${name}:name`), // The callback should be used to load the DOM with the appropriate UI items - callback () { - // Add the button and its handler(s) - // Note: the star extension may also add the same flying button so we check first - if ($id('tools_polygon') === null) { - const buttonTemplate = document.createElement("template"); - buttonTemplate.innerHTML = ` - - - - - `; - $id('tools_left').append(buttonTemplate.content.cloneNode(true)); + callback() { + if ($id("tools_polygon") === null) { + console.error( + "this polygon extension must be added after the star extension" + ); } - $id('tool_polygon').addEventListener("click", () => { - if (this.leftPanel.updateLeftPanel('tool_polygon')) { - svgCanvas.setMode('polygon'); + const title = svgEditor.i18next.t(`${name}:buttons.0.title`); + const buttonTemplate = document.createElement("template"); + // eslint-disable-next-line no-unsanitized/property + buttonTemplate.innerHTML = ` + + + `; + $id("tools_polygon").append(buttonTemplate.content.cloneNode(true)); + + $id("tool_polygon").addEventListener("click", () => { + if (this.leftPanel.updateLeftPanel("tool_polygon")) { + svgCanvas.setMode("polygon"); showPanel(true); } }); - + const label0 = svgEditor.i18next.t(`${name}:contextTools.0.label`); + const title0 = svgEditor.i18next.t(`${name}:contextTools.0.title`); // Add the context panel and its handler(s) const panelTemplate = document.createElement("template"); + // eslint-disable-next-line no-unsanitized/property panelTemplate.innerHTML = `
- +
`; - $id('tools_top').appendChild(panelTemplate.content.cloneNode(true)); - $id("polygon_panel").style.display = 'none'; - $id("polySides").addEventListener("change", (event) => { - setAttr('sides', event.target.value); + $id("tools_top").appendChild(panelTemplate.content.cloneNode(true)); + $id("polygon_panel").style.display = "none"; + $id("polySides").addEventListener("change", event => { + setAttr("sides", event.target.value); }); }, - mouseDown (opts) { - if (svgCanvas.getMode() !== 'polygon') { + mouseDown(opts) { + if (svgCanvas.getMode() !== "polygon") { return undefined; } // const e = opts.event; - const rgb = svgCanvas.getColor('fill'); + const rgb = svgCanvas.getColor("fill"); // const ccRgbEl = rgb.substring(1, rgb.length); - const sRgb = svgCanvas.getColor('stroke'); + const sRgb = svgCanvas.getColor("stroke"); // ccSRgbEl = sRgb.substring(1, rgb.length); const sWidth = svgCanvas.getStrokeWidth(); started = true; newFO = svgCanvas.addSVGElementFromJson({ - element: 'polygon', + element: "polygon", attr: { cx: opts.start_x, cy: opts.start_y, id: svgCanvas.getNextId(), - shape: 'regularPoly', - sides: document.getElementById('polySides').value, - orient: 'x', + shape: "regularPoly", + sides: document.getElementById("polySides").value, + orient: "x", edge: 0, fill: rgb, strokecolor: sRgb, @@ -130,67 +125,67 @@ export default { started: true }; }, - mouseMove (opts) { - if (!started || svgCanvas.getMode() !== 'polygon') { + mouseMove(opts) { + if (!started || svgCanvas.getMode() !== "polygon") { return undefined; } - const cx = Number(newFO.getAttribute('cx')); - const cy = Number(newFO.getAttribute('cy')); - const sides = Number(newFO.getAttribute('sides')); + const cx = Number(newFO.getAttribute("cx")); + const cy = Number(newFO.getAttribute("cy")); + const sides = Number(newFO.getAttribute("sides")); // const orient = newFO.getAttribute('orient'); - const fill = newFO.getAttribute('fill'); - const strokecolor = newFO.getAttribute('strokecolor'); - const strokeWidth = Number(newFO.getAttribute('strokeWidth')); + const fill = newFO.getAttribute("fill"); + const strokecolor = newFO.getAttribute("strokecolor"); + const strokeWidth = Number(newFO.getAttribute("strokeWidth")); let x = opts.mouse_x; let y = opts.mouse_y; - const edg = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5; - newFO.setAttribute('edge', edg); + const edg = Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)) / 1.5; + newFO.setAttribute("edge", edg); const inradius = (edg / 2) * cot(Math.PI / sides); const circumradius = inradius * sec(Math.PI / sides); - let points = ''; + let points = ""; for (let s = 0; sides >= s; s++) { - const angle = 2.0 * Math.PI * s / sides; - x = (circumradius * Math.cos(angle)) + cx; - y = (circumradius * Math.sin(angle)) + cy; + const angle = (2.0 * Math.PI * s) / sides; + x = circumradius * Math.cos(angle) + cx; + y = circumradius * Math.sin(angle) + cy; - points += x + ',' + y + ' '; + points += x + "," + y + " "; } // const poly = newFO.createElementNS(NS.SVG, 'polygon'); - newFO.setAttribute('points', points); - newFO.setAttribute('fill', fill); - newFO.setAttribute('stroke', strokecolor); - newFO.setAttribute('stroke-width', strokeWidth); + newFO.setAttribute("points", points); + newFO.setAttribute("fill", fill); + newFO.setAttribute("stroke", strokecolor); + newFO.setAttribute("stroke-width", strokeWidth); return { started: true }; }, - mouseUp () { - if (svgCanvas.getMode() !== 'polygon') { + mouseUp() { + if (svgCanvas.getMode() !== "polygon") { return undefined; } - const edge = newFO.getAttribute('edge'); - const keep = (edge !== '0'); + const edge = newFO.getAttribute("edge"); + const keep = edge !== "0"; // svgCanvas.addToSelection([newFO], true); return { keep, element: newFO }; }, - selectedChanged (opts) { + selectedChanged(opts) { // Use this to update the current selected elements selElems = opts.elems; let i = selElems.length; while (i--) { const elem = selElems[i]; - if (elem && elem.getAttribute('shape') === 'regularPoly') { + if (elem && elem.getAttribute("shape") === "regularPoly") { if (opts.selectedElement && !opts.multiselected) { - $id('polySides').value = elem.getAttribute('sides'); + $id("polySides").value = elem.getAttribute("sides"); showPanel(true); } else { @@ -201,7 +196,7 @@ export default { } } }, - elementChanged () { + elementChanged() { // const elem = opts.elems[0]; } }; diff --git a/src/editor/extensions/ext-polygon/locale/fr.js b/src/editor/extensions/ext-polygon/locale/fr.js new file mode 100644 index 00000000..9b503d8c --- /dev/null +++ b/src/editor/extensions/ext-polygon/locale/fr.js @@ -0,0 +1,14 @@ +export default { + name: 'polygone', + buttons: [ + { + title: 'Outil Polygone' + } + ], + contextTools: [ + { + title: 'Nombre de côtés', + label: 'côtés' + } + ] +}; diff --git a/src/editor/extensions/ext-star/ext-star.js b/src/editor/extensions/ext-star/ext-star.js index bd044b86..7ab42b52 100644 --- a/src/editor/extensions/ext-star/ext-star.js +++ b/src/editor/extensions/ext-star/ext-star.js @@ -6,21 +6,12 @@ * */ -const loadExtensionTranslation = async function (lang) { - let translationModule; - try { - // eslint-disable-next-line no-unsanitized/method - translationModule = await import(`./locale/${encodeURIComponent(lang)}.js`); - } catch (_error) { - // eslint-disable-next-line no-console - console.error(`Missing translation (${lang}) - using 'en'`); - translationModule = await import(`./locale/en.js`); - } - return translationModule.default; -}; + import { loadExtensionTranslation } from '../../locale.js'; -export default { - name: 'star', + const name = "star"; + + export default { + name, async init (_S) { const svgEditor = this; const { svgCanvas } = svgEditor; @@ -28,7 +19,7 @@ export default { let selElems; let started; let newFO; - const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang')); + await loadExtensionTranslation(svgEditor, name); /** * @@ -51,21 +42,23 @@ export default { }; return { - name: strings.name, + name: svgEditor.i18next.t(`${name}:name`), // The callback should be used to load the DOM with the appropriate UI items callback () { // Add the button and its handler(s) - // Note: the star extension may also add the same flying button so we check first - if ($id('tools_polygon') === null) { - const buttonTemplate = document.createElement("template"); - buttonTemplate.innerHTML = ` - - - + // Note: the star extension needs to be loaded before the polygon extension + const fbtitle = svgEditor.i18next.t(`${name}:title`); + const title = svgEditor.i18next.t(`${name}:buttons.0.title`); + const buttonTemplate = document.createElement("template"); + // eslint-disable-next-line no-unsanitized/property + buttonTemplate.innerHTML = ` + + + `; - $id('tools_left').append(buttonTemplate.content.cloneNode(true)); - } + $id('tools_left').append(buttonTemplate.content.cloneNode(true)); + // handler $id('tool_star').addEventListener("click", () => { showPanel(true); if (this.leftPanel.updateLeftPanel('tool_polygon')) { svgCanvas.setMode('star'); @@ -73,15 +66,22 @@ export default { } }); + const label0 = svgEditor.i18next.t(`${name}:contextTools.0.label`); + const title0 = svgEditor.i18next.t(`${name}:contextTools.0.title`); + const label1 = svgEditor.i18next.t(`${name}:contextTools.1.label`); + const title1 = svgEditor.i18next.t(`${name}:contextTools.1.title`); + const label2 = svgEditor.i18next.t(`${name}:contextTools.2.label`); + const title2 = svgEditor.i18next.t(`${name}:contextTools.2.title`); // Add the context panel and its handler(s) const panelTemplate = document.createElement("template"); + // eslint-disable-next-line no-unsanitized/property panelTemplate.innerHTML = `
- + - + - +
`; diff --git a/src/editor/extensions/ext-star/locale/en.js b/src/editor/extensions/ext-star/locale/en.js index da9d857c..080cc46c 100644 --- a/src/editor/extensions/ext-star/locale/en.js +++ b/src/editor/extensions/ext-star/locale/en.js @@ -1,5 +1,6 @@ export default { name: 'star', + title: 'Polygone/Star Tool', buttons: [ { title: 'Star Tool' diff --git a/src/editor/extensions/ext-star/locale/fr.js b/src/editor/extensions/ext-star/locale/fr.js new file mode 100644 index 00000000..0526905b --- /dev/null +++ b/src/editor/extensions/ext-star/locale/fr.js @@ -0,0 +1,23 @@ +export default { + name: 'etoile', + title: 'Outil Polygone/Etoile', + buttons: [ + { + title: 'Outil Etoile' + } + ], + contextTools: [ + { + title: 'Nombre de côtés', + label: 'points' + }, + { + title: 'Précision', + label: 'Précision' + }, + { + title: 'Torsion Etoile', + label: 'Décalage Radial' + } + ] +}; diff --git a/src/editor/extensions/ext-star/locale/zh-CN.js b/src/editor/extensions/ext-star/locale/zh-CN.js index d9ee06da..0d7b256d 100755 --- a/src/editor/extensions/ext-star/locale/zh-CN.js +++ b/src/editor/extensions/ext-star/locale/zh-CN.js @@ -1,5 +1,6 @@ export default { name: '星形', + title: 'Polygone/Star Tool', buttons: [ { title: '星形工具' diff --git a/src/editor/locale.js b/src/editor/locale.js index 7c0976a9..b7a12d6f 100644 --- a/src/editor/locale.js +++ b/src/editor/locale.js @@ -86,3 +86,18 @@ export const putLocale = async function (givenParam, goodLangs) { console.log(`Lang: ${i18next.t('lang')}`); return { langParam, i18next }; }; + +export const loadExtensionTranslation = async function (svgEditor, name) { + let translationModule; + const lang = svgEditor.configObj.pref('lang'); + try { + // eslint-disable-next-line no-unsanitized/method + translationModule = await import(`./extensions/ext-${name}/locale/${lang}.js`); + } catch (_error) { + // eslint-disable-next-line no-console + console.warn(`Missing translation (${lang}) for ${name} - using 'en'`); + // eslint-disable-next-line no-unsanitized/method + translationModule = await import(`./extensions/ext-${name}/locale/en.js`); + } + svgEditor.i18next.addResourceBundle(lang, name, translationModule.default); +};