From 58a90ed6b6b03f2b9f1e3e5cd76ed280fa87f4e3 Mon Sep 17 00:00:00 2001 From: "ICX\\Tatsiana.Hashtold" Date: Tue, 24 Dec 2024 11:21:34 +0300 Subject: [PATCH 1/5] FIO-7954: fixed translations --- src/Form.js | 8 +- src/PDFBuilder.js | 8 +- src/Webform.js | 287 +++++++++--------- src/WebformBuilder.js | 20 +- src/Wizard.js | 2 +- src/WizardBuilder.js | 2 +- .../_classes/component/Component.js | 21 +- src/components/_classes/list/ListComponent.js | 8 +- .../_classes/multivalue/Multivalue.js | 4 +- .../nestedarray/NestedArrayComponent.js | 6 +- src/components/address/Address.js | 2 +- src/components/button/Button.js | 12 +- src/components/checkbox/Checkbox.js | 2 +- src/components/datagrid/DataGrid.js | 2 +- src/components/day/Day.js | 4 +- src/components/editgrid/EditGrid.js | 8 +- src/components/file/File.js | 30 +- src/components/form/Form.js | 8 +- src/components/number/Number.js | 2 +- src/components/recaptcha/ReCaptcha.js | 4 +- src/components/select/Select.js | 14 +- src/components/selectboxes/SelectBoxes.js | 4 +- src/components/signature/Signature.js | 4 +- src/components/survey/Survey.js | 4 +- src/components/textarea/TextArea.js | 12 +- src/i18n.js | 2 + src/translations/en.js | 140 ++++++++- src/utils/i18n.js | 17 +- 28 files changed, 396 insertions(+), 241 deletions(-) diff --git a/src/Form.js b/src/Form.js index 15c09c1671..4a2d88c9b3 100644 --- a/src/Form.js +++ b/src/Form.js @@ -439,11 +439,11 @@ export default class Form extends Element { */ build() { if (!this.instance) { - return Promise.reject('Form not ready. Use form.ready promise'); + return Promise.reject(this.t('formNotReady')); } if (!this.element) { - return Promise.reject('No DOM element for form.'); + return Promise.reject(this.t('noFormElement')); } // Add temporary loader. @@ -463,7 +463,7 @@ export default class Form extends Element { render() { if (!this.instance) { - return Promise.reject('Form not ready. Use form.ready promise'); + return Promise.reject(this.t('formNotReady')); } return Promise.resolve(this.instance.render()) .then((param) => { @@ -474,7 +474,7 @@ export default class Form extends Element { attach(element) { if (!this.instance) { - return Promise.reject('Form not ready. Use form.ready promise'); + return Promise.reject(this.t('formNotReady')); } if (this.element) { delete this.element.component; diff --git a/src/PDFBuilder.js b/src/PDFBuilder.js index c195cdbe66..963cc1cc53 100644 --- a/src/PDFBuilder.js +++ b/src/PDFBuilder.js @@ -218,10 +218,10 @@ export default class PDFBuilder extends WebformBuilder { const progress = Math.floor((event.loaded / event.total) * 100); this.refs.uploadProgress.style.width = `${progress}%`; if (progress > 98) { - this.refs.uploadProgress.innerHTML = this.t('Converting PDF. Please wait.'); + this.refs.uploadProgress.innerHTML = this.t('waitPdfConverting'); } else { - this.refs.uploadProgress.innerHTML = `${this.t('Uploading')} ${progress}%`; + this.refs.uploadProgress.innerHTML = `${this.t('uploading')} ${progress}%`; } } }, `${this.projectUrl}/upload`, {}, 'file') @@ -263,7 +263,7 @@ export default class PDFBuilder extends WebformBuilder { return; } this.refs.uploadError.style.display = message ? '' : 'none'; - this.refs.uploadError.innerHTML = message; + this.refs.uploadError.innerHTML = this.t(`${message}`); } createForm(options) { @@ -522,7 +522,7 @@ export default class PDFBuilder extends WebformBuilder { name: 'showBuilderErrors', data: { compId: comp.component.id, - errorMessage: `API Key is not unique: ${comp.key}`, + errorMessage: `${this.t('notUniqueKey')}: ${comp.key}`, } }); } diff --git a/src/Webform.js b/src/Webform.js index 7f9698cbe0..e71ff02426 100644 --- a/src/Webform.js +++ b/src/Webform.js @@ -1,11 +1,11 @@ -import _ from "lodash"; -import moment from "moment"; -import { compareVersions } from "compare-versions"; -import EventEmitter from "./EventEmitter"; -import i18nDefaults from "./i18n"; -import { Formio } from "./Formio"; -import Components from "./components/Components"; -import NestedDataComponent from "./components/_classes/nesteddata/NestedDataComponent"; +import _ from 'lodash'; +import moment from 'moment'; +import { compareVersions } from 'compare-versions'; +import EventEmitter from './EventEmitter'; +import i18nDefaults from './i18n'; +import { Formio } from './Formio'; +import Components from './components/Components'; +import NestedDataComponent from './components/_classes/nesteddata/NestedDataComponent'; import { fastCloneDeep, currentTimezone, @@ -13,8 +13,8 @@ import { getStringFromComponentPath, convertStringToHTMLElement, getArrayFromComponentPath, -} from "./utils/utils"; -import { eachComponent } from "./utils/formUtils"; +} from './utils/utils'; +import { eachComponent } from './utils/formUtils'; // We need this here because dragula pulls in CustomEvent class that requires global to exist. if (typeof window !== 'undefined' && typeof window.global === 'undefined') { @@ -33,10 +33,10 @@ Formio.registerComponent = Components.setComponent; * @returns {any} - The icon set. */ function getIconSet(icons) { - if (icons === "fontawesome") { - return "fa"; + if (icons === 'fontawesome') { + return 'fa'; } - return icons || ""; + return icons || ''; } /** @@ -52,7 +52,7 @@ function getOptions(options) { saveDraft: false, alwaysDirty: false, saveDraftThrottle: 5000, - display: "form", + display: 'form', cdnUrl: Formio.cdn.baseUrl, }); if (!options.events) { @@ -102,10 +102,10 @@ function getOptions(options) { /** * @typedef {object} ButtonSettings - * @property {boolean} [showPrevious] - Show the "Previous" button. - * @property {boolean} [showNext] - Show the "Next" button. - * @property {boolean} [showCancel] - Show the "Cancel" button. - * @property {boolean} [showSubmit] - Show the "Submit" button. + * @property {boolean} [showPrevious] - Show the 'Previous' button. + * @property {boolean} [showNext] - Show the 'Next' button. + * @property {boolean} [showCancel] - Show the 'Cancel' button. + * @property {boolean} [showSubmit] - Show the 'Submit' button. */ /** @@ -187,8 +187,8 @@ export default class Webform extends NestedDataComponent { * The type of this element. * @type {string} */ - this.type = "form"; - this._src = ""; + this.type = 'form'; + this._src = ''; this._loading = false; this._form = {}; this.draftEnabled = false; @@ -359,7 +359,7 @@ export default class Webform extends NestedDataComponent { return; } this.rebuild(); - this.emit("languageChanged"); + this.emit('languageChanged'); }); } @@ -380,7 +380,7 @@ export default class Webform extends NestedDataComponent { addLanguage(code, lang, active = false) { if (this.i18next) { var translations = _.assign(fastCloneDeep(i18nDefaults.resources.en.translation), lang); - this.i18next.addResourceBundle(code, "translation", translations, true, true); + this.i18next.addResourceBundle(code, 'translation', translations, true, true); if (active) { this.language = code; } @@ -388,12 +388,12 @@ export default class Webform extends NestedDataComponent { } keyboardCatchableElement(element) { - if (element.nodeName === "TEXTAREA") { + if (element.nodeName === 'TEXTAREA') { return false; } - if (element.nodeName === "INPUT") { - return ["text", "email", "password"].indexOf(element.type) === -1; + if (element.nodeName === 'INPUT') { + return ['text', 'email', 'password'].indexOf(element.type) === -1; } return true; @@ -407,14 +407,14 @@ export default class Webform extends NestedDataComponent { const ctrl = event.ctrlKey || event.metaKey; const keyCode = event.keyCode; - let char = ""; + let char = ''; if (65 <= keyCode && keyCode <= 90) { char = String.fromCharCode(keyCode); } else if (keyCode === 13) { - char = "Enter"; + char = 'Enter'; } else if (keyCode === 27) { - char = "Esc"; + char = 'Esc'; } _.each(this.shortcuts, (shortcut) => { @@ -436,9 +436,9 @@ export default class Webform extends NestedDataComponent { shortcut = _.capitalize(shortcut); - if (shortcut === "Enter" || shortcut === "Esc") { + if (shortcut === 'Enter' || shortcut === 'Esc') { // Restrict Enter and Esc only for buttons - if (element.tagName !== "BUTTON") { + if (element.tagName !== 'BUTTON') { return; } @@ -548,14 +548,14 @@ export default class Webform extends NestedDataComponent { * @returns {boolean} - TRUE means the url was set, FALSE otherwise. */ setUrl(value, options) { - if (!value || typeof value !== "string" || value === this._src) { + if (!value || typeof value !== 'string' || value === this._src) { return false; } this._src = value; this.nosubmit = true; this.formio = this.options.formio = new Formio(value, options); - if (this.type === "form") { + if (this.type === 'form') { // Set the options source so this can be passed to other components. this.options.src = value; } @@ -592,17 +592,17 @@ export default class Webform extends NestedDataComponent { /** * Set the loading state for this form, and also show the loader spinner. - * @param {boolean} loading - If this form should be "loading" or not. + * @param {boolean} loading - If this form should be 'loading' or not. */ set loading(loading) { if (this._loading !== loading) { this._loading = loading; if (!this.loader && loading) { - this.loader = this.ce("div", { - class: "loader-wrapper", + this.loader = this.ce('div', { + class: 'loader-wrapper', }); - const spinner = this.ce("div", { - class: "loader text-center", + const spinner = this.ce('div', { + class: 'loader text-center', }); this.loader.appendChild(spinner); } @@ -688,15 +688,15 @@ export default class Webform extends NestedDataComponent { // Use the sanitize config from the form settings or the global sanitize config if it is not provided in the options if (!this.options.sanitizeConfig && !this.builderMode) { this.options.sanitizeConfig = - _.get(form, "settings.sanitizeConfig") || - _.get(form, "globalSettings.sanitizeConfig"); + _.get(form, 'settings.sanitizeConfig') || + _.get(form, 'globalSettings.sanitizeConfig'); } - if ("schema" in form && compareVersions(form.schema, "1.x") > 0) { + if ('schema' in form && compareVersions(form.schema, '1.x') > 0) { this.ready.then(() => { this.setAlert( - "alert alert-danger", - "Form schema is for a newer version, please upgrade your renderer. Some functionality may not work." + 'alert alert-danger', + this.t('newFormSchema') ); }); } @@ -704,7 +704,7 @@ export default class Webform extends NestedDataComponent { // See if they pass a module, and evaluate it if so. if (form && form.module) { let formModule = null; - if (typeof form.module === "string") { + if (typeof form.module === 'string') { try { formModule = this.evaluate(`return ${form.module}`); } catch (err) { @@ -726,7 +726,7 @@ export default class Webform extends NestedDataComponent { this.initialized = false; const rebuild = this.rebuild() || Promise.resolve(); return rebuild.then(() => { - this.emit("formLoad", form); + this.emit('formLoad', form); this.triggerCaptcha(); // Make sure to trigger onChange after a render event occurs to speed up form rendering. setTimeout(() => { @@ -807,7 +807,7 @@ export default class Webform extends NestedDataComponent { setSubmission(submission, flags = {}) { flags = { ...flags, - fromSubmission: _.has(flags, "fromSubmission") ? flags.fromSubmission : true, + fromSubmission: _.has(flags, 'fromSubmission') ? flags.fromSubmission : true, }; return (this.onSubmission = this.formReady .then( @@ -827,10 +827,10 @@ export default class Webform extends NestedDataComponent { } handleDraftError(errName, errDetails, restoreDraft) { - const errorMessage = _.trim(`${this.t(errName)} ${errDetails || ""}`); + const errorMessage = _.trim(`${this.t(errName)} ${errDetails || ''}`); console.warn(errorMessage); this.emit( - restoreDraft ? "restoreDraftError" : "saveDraftError", + restoreDraft ? 'restoreDraftError' : 'saveDraftError', errDetails || errorMessage ); } @@ -840,18 +840,18 @@ export default class Webform extends NestedDataComponent { return; } if (!this.formio) { - this.handleDraftError("saveDraftInstanceError"); + this.handleDraftError('saveDraftInstanceError'); return; } if (!Formio.getUser()) { - this.handleDraftError("saveDraftAuthError"); + this.handleDraftError('saveDraftAuthError'); return; } const draft = fastCloneDeep(this.submission); - draft.state = "draft"; + draft.state = 'draft'; if (!this.savingDraft && !this.submitting) { - this.emit("saveDraftBegin"); + this.emit('saveDraftBegin'); this.savingDraft = true; this.formio .saveSubmission(draft) @@ -859,11 +859,11 @@ export default class Webform extends NestedDataComponent { // Set id to submission to avoid creating new draft submission this.submission._id = sub._id; this.savingDraft = false; - this.emit("saveDraft", sub); + this.emit('saveDraft', sub); }) .catch((err) => { this.savingDraft = false; - this.handleDraftError("saveDraftError", err); + this.handleDraftError('saveDraftError', err); }); } } @@ -875,7 +875,7 @@ export default class Webform extends NestedDataComponent { restoreDraft(userId) { const formio = this.formio || this.options.formio; if (!formio) { - this.handleDraftError("restoreDraftInstanceError", null, true); + this.handleDraftError('restoreDraftInstanceError', null, true); return; } this.savingDraft = true; @@ -893,23 +893,23 @@ export default class Webform extends NestedDataComponent { return this.setSubmission(draft).then(() => { this.draftEnabled = true; this.savingDraft = false; - this.emit("restoreDraft", draft); + this.emit('restoreDraft', draft); }); } // Enable drafts so that we can keep track of changes. this.draftEnabled = true; this.savingDraft = false; - this.emit("restoreDraft", null); + this.emit('restoreDraft', null); }) .catch((err) => { this.draftEnabled = true; this.savingDraft = false; - this.handleDraftError("restoreDraftError", err, true); + this.handleDraftError('restoreDraftError', err, true); }); } get schema() { - const schema = fastCloneDeep(_.omit(this._form, ["components"])); + const schema = fastCloneDeep(_.omit(this._form, ['components'])); schema.components = []; this.eachComponent((component) => schema.components.push(component.schema)); return schema; @@ -995,12 +995,12 @@ export default class Webform extends NestedDataComponent { } else { this.component = this.form; } - this.component.type = "form"; + this.component.type = 'form'; this.component.input = false; this.addComponents(); this.on( - "submitButton", + 'submitButton', (options) => { this.submit(false, options).catch((e) => { if (options?.instance) { @@ -1013,14 +1013,14 @@ export default class Webform extends NestedDataComponent { ); this.on( - "checkValidity", - (data) => this.validate(data, { dirty: true, process: "change" }), + 'checkValidity', + (data) => this.validate(data, { dirty: true, process: 'change' }), true ); - this.on("requestUrl", (args) => this.submitUrl(args.url, args.headers), true); - this.on("resetForm", () => this.resetValue(), true); - this.on("deleteSubmission", () => this.deleteSubmission(), true); - this.on("refreshData", () => this.updateValue(), true); + this.on('requestUrl', (args) => this.submitUrl(args.url, args.headers), true); + this.on('resetForm', () => this.resetValue(), true); + this.on('deleteSubmission', () => this.deleteSubmission(), true); + this.on('refreshData', () => this.updateValue(), true); this.executeFormController(); @@ -1052,7 +1052,7 @@ export default class Webform extends NestedDataComponent { * */ teardown() { - this.emit("formDelete", this.id); + this.emit('formDelete', this.id); delete Formio.forms[this.id]; delete this.executeShortcuts; delete this.triggerSaveDraft; @@ -1060,12 +1060,12 @@ export default class Webform extends NestedDataComponent { } destroy(all = false) { - this.off("submitButton"); - this.off("checkValidity"); - this.off("requestUrl"); - this.off("resetForm"); - this.off("deleteSubmission"); - this.off("refreshData"); + this.off('submitButton'); + this.off('checkValidity'); + this.off('requestUrl'); + this.off('resetForm'); + this.off('deleteSubmission'); + this.off('refreshData'); return super.destroy(all); } @@ -1081,20 +1081,20 @@ export default class Webform extends NestedDataComponent { } getClassName() { - let classes = "formio-form"; + let classes = 'formio-form'; if (this.options.readOnly) { - classes += " formio-read-only"; + classes += ' formio-read-only'; } return classes; } render() { return super.render( - this.renderTemplate("webform", { + this.renderTemplate('webform', { classes: this.getClassName(), children: this.renderComponents(), }), - this.builderMode ? "builder" : "form", + this.builderMode ? 'builder' : 'form', true ); } @@ -1111,13 +1111,13 @@ export default class Webform extends NestedDataComponent { attach(element) { this.setElement(element); - this.loadRefs(element, { webform: "single" }); + this.loadRefs(element, { webform: 'single' }); const childPromise = this.attachComponents(this.refs.webform); - this.addEventListener(document, "keydown", this.executeShortcuts); + this.addEventListener(document, 'keydown', this.executeShortcuts); this.currentForm = this; - this.hook("attachWebform", element, this); + this.hook('attachWebform', element, this); return childPromise.then(() => { - this.emit("render", this.element); + this.emit('render', this.element); return this.setValue(this._submission, { noUpdateEvent: true, @@ -1150,7 +1150,7 @@ export default class Webform extends NestedDataComponent { /** * Sets a new alert to display in the error dialog of the form. - * @param {string} type - The type of alert to display. "danger", "success", "warning", etc. + * @param {string} type - The type of alert to display. 'danger', 'success', 'warning', etc. * @param {string} message - The message to show in the alert. * @param {object} options - The options for the alert. */ @@ -1159,8 +1159,8 @@ export default class Webform extends NestedDataComponent { if (this.alert) { if (this.refs.errorRef && this.refs.errorRef.length) { this.refs.errorRef.forEach((el) => { - this.removeEventListener(el, "click"); - this.removeEventListener(el, "keypress"); + this.removeEventListener(el, 'click'); + this.removeEventListener(el, 'keypress'); }); } this.removeChild(this.alert); @@ -1170,7 +1170,7 @@ export default class Webform extends NestedDataComponent { } if (this.options.noAlerts) { if (!message) { - this.emit("error", false); + this.emit('error', false); } return; } @@ -1178,8 +1178,8 @@ export default class Webform extends NestedDataComponent { try { if (this.refs.errorRef && this.refs.errorRef.length) { this.refs.errorRef.forEach((el) => { - this.removeEventListener(el, "click"); - this.removeEventListener(el, "keypress"); + this.removeEventListener(el, 'click'); + this.removeEventListener(el, 'keypress'); }); } this.removeChild(this.alert); @@ -1201,7 +1201,7 @@ export default class Webform extends NestedDataComponent { }; this.alert = convertStringToHTMLElement( - this.renderTemplate("alert", templateOptions), + this.renderTemplate('alert', templateOptions), `#${attrs.id}` ); } @@ -1209,15 +1209,15 @@ export default class Webform extends NestedDataComponent { return; } - this.loadRefs(this.alert, { errorRef: "multiple" }); + this.loadRefs(this.alert, { errorRef: 'multiple' }); if (this.refs.errorRef && this.refs.errorRef.length) { this.refs.errorRef.forEach((el) => { - this.addEventListener(el, "click", (e) => { + this.addEventListener(el, 'click', (e) => { const key = e.currentTarget.dataset.componentKey; this.focusOnComponent(key); }); - this.addEventListener(el, "keydown", (e) => { + this.addEventListener(el, 'keydown', (e) => { if (e.keyCode === 13) { e.preventDefault(); const key = e.currentTarget.dataset.componentKey; @@ -1305,8 +1305,8 @@ export default class Webform extends NestedDataComponent { (err.component && err.component.key) || (err.fromServer && err.path); - const formattedKeyOrPath = keyOrPath ? getStringFromComponentPath(keyOrPath) : ""; - if (typeof err !== "string" && !err.formattedKeyOrPath) { + const formattedKeyOrPath = keyOrPath ? getStringFromComponentPath(keyOrPath) : ''; + if (typeof err !== 'string' && !err.formattedKeyOrPath) { err.formattedKeyOrPath = formattedKeyOrPath; } @@ -1319,8 +1319,8 @@ export default class Webform extends NestedDataComponent { errors.forEach(({ message, context, fromServer, component }, index) => { const text = !component?.label || context?.hasLabel || fromServer - ? this.t("alertMessage", { message: this.t(message) }) - : this.t("alertMessageWithLabel", { + ? this.t('alertMessage', { message: this.t(message) }) + : this.t('alertMessageWithLabel', { label: this.t(component?.label), message: this.t(message), }); @@ -1328,10 +1328,10 @@ export default class Webform extends NestedDataComponent { }); } - const errorsList = this.renderTemplate("errorsList", { errors: displayedErrors }); - this.root.setAlert("danger", errorsList); + const errorsList = this.renderTemplate('errorsList', { errors: displayedErrors }); + this.root.setAlert('danger', errorsList); if (triggerEvent) { - this.emit("error", errors); + this.emit('error', errors); } return errors; @@ -1353,25 +1353,25 @@ export default class Webform extends NestedDataComponent { noValidate: true, noCheck: true, }); - this.setAlert("success", `

${this.t("complete")}

`); + this.setAlert('success', `

${this.t('complete')}

`); // Cancel triggered saveDraft to prevent overriding the submitted state if (this.draftEnabled && this.triggerSaveDraft?.cancel) { this.triggerSaveDraft.cancel(); } - this.emit("submit", submission, saved); + this.emit('submit', submission, saved); if (saved) { - this.emit("submitDone", submission); + this.emit('submitDone', submission); } return submission; } normalizeError(error) { if (error) { - if (typeof error === "object" && "details" in error) { + if (typeof error === 'object' && 'details' in error) { error = error.details; } - if (typeof error === "string") { + if (typeof error === 'string') { error = { message: error }; } } @@ -1389,11 +1389,11 @@ export default class Webform extends NestedDataComponent { this.submitting = false; this.setPristine(false); - this.emit("submitError", error || this.errors); + this.emit('submitError', error || this.errors); // Allow for silent cancellations (no error message, no submit button error state) if (error && error.silent) { - this.emit("change", { isValid: true }, { silent: true }); + this.emit('change', { isValid: true }, { silent: true }); return false; } @@ -1460,13 +1460,13 @@ export default class Webform extends NestedDataComponent { } if (!flags || !flags.noEmit) { - this.emit("change", value, flags, modified); + this.emit('change', value, flags, modified); isChangeEventEmitted = true; } // The form is initialized after the first change event occurs. if (isChangeEventEmitted && !this.initialized) { - this.emit("initialized"); + this.emit('initialized'); this.initialized = true; } } @@ -1477,7 +1477,7 @@ export default class Webform extends NestedDataComponent { */ deleteSubmission() { return this.formio.deleteSubmission().then(() => { - this.emit("submissionDeleted", this.submission); + this.emit('submissionDeleted', this.submission); this.resetValue(); }); } @@ -1489,12 +1489,12 @@ export default class Webform extends NestedDataComponent { * @returns {boolean} - TRUE means the submission was cancelled, FALSE otherwise. */ cancel(noconfirm) { - const shouldReset = this.hook("beforeCancel", true); - if (shouldReset && (noconfirm || confirm(this.t("confirmCancel")))) { + const shouldReset = this.hook('beforeCancel', true); + if (shouldReset && (noconfirm || confirm(this.t('confirmCancel')))) { this.resetValue(); return true; } else { - this.emit("cancelSubmit"); + this.emit('cancelSubmit'); return false; } } @@ -1503,8 +1503,8 @@ export default class Webform extends NestedDataComponent { // Add in metadata about client submitting the form submission.metadata = submission.metadata || {}; _.defaults(submission.metadata, { - timezone: _.get(this, "_submission.metadata.timezone", currentTimezone()), - offset: parseInt(_.get(this, "_submission.metadata.offset", moment().utcOffset()), 10), + timezone: _.get(this, '_submission.metadata.timezone', currentTimezone()), + offset: parseInt(_.get(this, '_submission.metadata.offset', moment().utcOffset()), 10), origin: document.location.origin, referrer: document.referrer, browserName: navigator.appName, @@ -1530,34 +1530,34 @@ export default class Webform extends NestedDataComponent { this.setMetadata(submission); - submission.state = options.state || submission.state || "submitted"; + submission.state = options.state || submission.state || 'submitted'; - const isDraft = submission.state === "draft"; + const isDraft = submission.state === 'draft'; this.hook( - "beforeSubmit", + 'beforeSubmit', { ...submission, component: options.component }, (err, data) => { if (err) { return reject(err); } - submission._vnote = data && data._vnote ? data._vnote : ""; + submission._vnote = data && data._vnote ? data._vnote : ''; try { if (!isDraft && !options.noValidate) { if (!submission.data) { - return reject("Invalid Submission"); + return reject('Invalid Submission'); } const errors = this.validate(submission.data, { local, dirty: true, silentCheck: false, - process: "submit", + process: 'submit', }); if ( errors.length || options.beforeSubmitResults?.some( - (result) => result.status === "rejected" + (result) => result.status === 'rejected' ) ) { return reject(errors); @@ -1568,22 +1568,22 @@ export default class Webform extends NestedDataComponent { } this.everyComponent((comp) => { - if (submission._vnote && comp.type === "form" && comp.component.reference) { + if (submission._vnote && comp.type === 'form' && comp.component.reference) { _.get(submission.data, local ? comp.paths?.localDataPath : comp.path, {})._vnote = submission._vnote; } const { persistent } = comp.component; - if (persistent === "client-only") { + if (persistent === 'client-only') { _.unset(submission.data, local ? comp.paths?.localDataPath : comp.path); } }); this.hook( - "customValidation", + 'customValidation', { ...submission, component: options.component }, (err) => { if (err) { // If string is returned, cast to object. - if (typeof err === "string") { + if (typeof err === 'string') { err = { message: err, }; @@ -1601,8 +1601,8 @@ export default class Webform extends NestedDataComponent { const method = submission.data._id && this._form.action.includes(submission.data._id) - ? "PUT" - : "POST"; + ? 'PUT' + : 'POST'; return Formio.makeStaticRequest( this._form.action, method, @@ -1631,8 +1631,8 @@ export default class Webform extends NestedDataComponent { } // If this is an actionUrl, then make sure to save the action and not the submission. const submitMethod = submitFormio.actionUrl - ? "saveAction" - : "saveSubmission"; + ? 'saveAction' + : 'saveSubmission'; submitFormio[submitMethod](submission) .then((result) => resolve({ @@ -1655,13 +1655,13 @@ export default class Webform extends NestedDataComponent { setServerErrors(error) { if (error.details) { this.serverErrors = error.details - .filter((err) => (err.level ? err.level === "error" : err)) + .filter((err) => (err.level ? err.level === 'error' : err)) .map((err) => { err.fromServer = true; return err; }); - } else if (typeof error === "string") { - this.serverErrors = [{ fromServer: true, level: "error", message: error }]; + } else if (typeof error === 'string') { + this.serverErrors = [{ fromServer: true, level: 'error', message: error }]; } } @@ -1727,19 +1727,19 @@ export default class Webform extends NestedDataComponent { submitUrl(URL, headers) { if (!URL) { - return console.warn("Missing URL argument"); + return console.warn(this.t('missingUrl')); } const submission = this.submission || {}; const API_URL = URL; const settings = { - method: "POST", + method: 'POST', headers: {}, }; if (headers && headers.length > 0) { headers.map((e) => { - if (e.header !== "" && e.value !== "") { + if (e.header !== '' && e.value !== '') { settings.headers[e.header] = this.interpolate(e.value, submission); } }); @@ -1749,20 +1749,21 @@ export default class Webform extends NestedDataComponent { headers: settings.headers, }) .then(() => { - this.emit("requestDone"); - this.setAlert("success", "

Success

"); + this.emit('requestDone'); + this.setAlert('success', `

${this.t('success')}

`); }) .catch((e) => { - const message = `${e.statusText ? e.statusText : ""} ${e.status ? e.status : e}`; - this.emit("error", message); + const message = `${e.statusText ? e.statusText : ''} ${e.status ? e.status : e}`; + this.emit('error', message); console.error(message); - this.setAlert("danger", `

${message}

`); + this.setAlert('danger', `

${message}

`); return Promise.reject(this.onSubmissionError(e)); }); } else { - this.emit("error", "You should add a URL to this button."); - this.setAlert("warning", "You should add a URL to this button."); - return console.warn("You should add a URL to this button."); + const message = this.t('urlNotAttachedToBtn') + this.emit('error', message); + this.setAlert('warning', message); + return console.warn(message); } } @@ -1784,7 +1785,7 @@ export default class Webform extends NestedDataComponent { set nosubmit(value) { this._nosubmit = !!value; - this.emit("nosubmit", this._nosubmit); + this.emit('nosubmit', this._nosubmit); } get nosubmit() { diff --git a/src/WebformBuilder.js b/src/WebformBuilder.js index 1bd3319bf0..de38ce9d6b 100644 --- a/src/WebformBuilder.js +++ b/src/WebformBuilder.js @@ -246,7 +246,7 @@ export default class WebformBuilder extends Component { } } }).catch((err) => { - console.warn(`Could not load project settings: ${err.message || err}`); + console.warn(`${this.t('loadingProjectSettingsError')}: ${err.message || err}`); }); if (!formio.noProject && !isResourcesDisabled && formio.formsUrl) { @@ -375,14 +375,14 @@ export default class WebformBuilder extends Component { }); if (component.refs.copyComponent) { - this.attachTooltip(component.refs.copyComponent, this.t('Copy')); + this.attachTooltip(component.refs.copyComponent, this.t('copy')); component.addEventListener(component.refs.copyComponent, 'click', () => this.copyComponent(component)); } if (component.refs.pasteComponent) { - const pasteToolTip = this.attachTooltip(component.refs.pasteComponent, this.t('Paste below')); + const pasteToolTip = this.attachTooltip(component.refs.pasteComponent, this.t('pasteBelow')); component.addEventListener(component.refs.pasteComponent, 'click', () => { pasteToolTip.hide(); @@ -391,7 +391,7 @@ export default class WebformBuilder extends Component { } if (component.refs.moveComponent) { - this.attachTooltip(component.refs.moveComponent, this.t('Move')); + this.attachTooltip(component.refs.moveComponent, this.t('move')); if (this.keyboardActionsEnabled) { component.addEventListener(component.refs.moveComponent, 'click', () => { this.moveComponent(component); @@ -402,21 +402,21 @@ export default class WebformBuilder extends Component { const parent = this.getParentElement(element); if (component.refs.editComponent) { - this.attachTooltip(component.refs.editComponent, this.t('Edit')); + this.attachTooltip(component.refs.editComponent, this.t('edit')); component.addEventListener(component.refs.editComponent, 'click', () => this.editComponent(component.schema, parent, false, false, component.component, { inDataGrid: component.isInDataGrid })); } if (component.refs.editJson) { - this.attachTooltip(component.refs.editJson, this.t('Edit JSON')); + this.attachTooltip(component.refs.editJson, this.t('editJson')); component.addEventListener(component.refs.editJson, 'click', () => this.editComponent(component.schema, parent, false, true, component.component)); } if (component.refs.removeComponent) { - this.attachTooltip(component.refs.removeComponent, this.t('Remove')); + this.attachTooltip(component.refs.removeComponent, this.t('remove')); component.addEventListener(component.refs.removeComponent, 'click', () => this.removeComponent(component.schema, parent, component.component, component)); @@ -946,7 +946,7 @@ export default class WebformBuilder extends Component { }, true); if (isCompAlreadyExists) { this.webform.redraw(); - this.webform.setAlert('danger', `You cannot add more than one ${_.get(draggableComponent, draggableComponent.uniqueComponent ? 'title' : 'key')} component to one page.`); + this.webform.setAlert('danger', this.t('builderUniqueError', { componentKeyOrTitle: _.get(draggableComponent, draggableComponent.uniqueComponent ? 'title' : 'key') })); return; } } @@ -1788,7 +1788,7 @@ export default class WebformBuilder extends Component { */ copyComponent(component) { if (!window.sessionStorage) { - return console.warn('Session storage is not supported in this browser.'); + return console.warn(this.t('sessionStorageSupportError')); } this.addClass(this.refs.form, 'builder-paste-mode'); window.sessionStorage.setItem('formio.clipboard', JSON.stringify(component.schema)); @@ -1801,7 +1801,7 @@ export default class WebformBuilder extends Component { */ pasteComponent(component) { if (!window.sessionStorage) { - return console.warn('Session storage is not supported in this browser.'); + return console.warn(this.t('sessionStorageSupportError')); } this.removeClass(this.refs.form, 'builder-paste-mode'); if (window.sessionStorage) { diff --git a/src/Wizard.js b/src/Wizard.js index febab6776f..6a6368a0e5 100644 --- a/src/Wizard.js +++ b/src/Wizard.js @@ -701,7 +701,7 @@ export default class Wizard extends Webform { this.redraw(); return Promise.resolve(); } - return Promise.reject('Page not found'); + return Promise.reject(this.t('pageNotFound')); } pageFieldLogic(page) { diff --git a/src/WizardBuilder.js b/src/WizardBuilder.js index 08f3579af4..3334636283 100644 --- a/src/WizardBuilder.js +++ b/src/WizardBuilder.js @@ -260,7 +260,7 @@ export default class WizardBuilder extends WebformBuilder { const isSiblingAnAddPageButton = sibling?.classList.contains('wizard-add-page'); // We still can paste before Add Page button if (!element.dragInfo || (sibling && !sibling.dragInfo && !isSiblingAnAddPageButton)) { - console.warn('There is no Drag Info available for either dragged or sibling element'); + console.warn(this.t('noDragInfoError')); return; } const oldPosition = element.dragInfo.index; diff --git a/src/components/_classes/component/Component.js b/src/components/_classes/component/Component.js index 69cbeef94c..4e21424b02 100644 --- a/src/components/_classes/component/Component.js +++ b/src/components/_classes/component/Component.js @@ -588,7 +588,10 @@ export default class Component extends Element { this.addons.push(addon); } else { - console.warn(`Addon ${name.label} does not support component of type ${this.component.type}.`); + console.warn(this.t('addonSupportTypeError', { + type: this.component.type, + label: name.label + })); } } @@ -651,7 +654,7 @@ export default class Component extends Element { } set path(path) { - throw new Error('Should not be setting the path of a component.'); + throw new Error(this.t('setPathError')); } set parentVisible(value) { @@ -746,7 +749,7 @@ export default class Component extends Element { } get calculatedPath() { - console.error('component.calculatedPath was deprecated, use component.path instead.'); + console.error(this.t('calculatedPathDeprecation')); return this.path; } @@ -937,7 +940,7 @@ export default class Component extends Element { const templatesByName = Templates.defaultTemplates[name]; if (!templatesByName) { - return { template: `Unknown template: ${name}` }; + return { template: this.t('unknownTemplate', { name })}; } const templateByMode = this.checkTemplateMode(templatesByName, modes); @@ -1006,9 +1009,7 @@ export default class Component extends Element { data.disabled = this.disabled; data.builder = this.builderMode; data.render = (...args) => { - console.warn(`Form.io 'render' template function is deprecated. - If you need to render template (template A) inside of another template (template B), - pass pre-compiled template A (use this.renderTemplate('template_A_name') as template context variable for template B`); + console.warn(this.t('renderTemplateFunctionDeprecation')); return this.renderTemplate(...args); }; data.label = data.labelInfo || this.labelInfo; @@ -1246,7 +1247,7 @@ export default class Component extends Element { } return this.renderModalPreview({ - previewText: this.getValueAsString(dataValue, { modalPreview: true }) || this.t('Click to set value'), + previewText: this.getValueAsString(dataValue, { modalPreview: true }) || this.t('clickToSetValue'), messages: '', labelInfo: modalLabel, }); @@ -1274,7 +1275,7 @@ export default class Component extends Element { * @param {boolean} topLevel - If this is the topmost component that is being rendered. * @returns {string} - The rendered HTML string of a component. */ - render(children = `Unknown component: ${this.component.type}`, topLevel = false) { + render(children = this.t('unknownComponent', { type: this.component.type }), topLevel = false) { const isVisible = this.visible; this.rendered = true; @@ -3770,7 +3771,7 @@ export default class Component extends Element { // Maintain reverse compatibility. whenReady() { - console.warn('The whenReady() method has been deprecated. Please use the dataReady property instead.'); + console.warn(this.t('whenReadyDeprecation')); return this.dataReady; } diff --git a/src/components/_classes/list/ListComponent.js b/src/components/_classes/list/ListComponent.js index 1c3ac97779..7a580be636 100644 --- a/src/components/_classes/list/ListComponent.js +++ b/src/components/_classes/list/ListComponent.js @@ -156,13 +156,13 @@ export default class ListComponent extends Field { component: this.component, message: err.toString(), }); - console.warn(`Unable to load resources for ${this.key}`); + console.warn(this.t('loadResourcesError', {componentKey: this.key})); } /* eslint-disable max-statements */ updateItems(searchInput, forceUpdate) { if (!this.component.data) { - console.warn(`Select component ${this.key} does not have data configuration.`); + console.warn(this.t('noSelectDataConfiguration', {componentKey: this.key})); this.itemsLoadedResolve(); return; } @@ -198,7 +198,7 @@ export default class ListComponent extends Field { this.loadItems(resourceUrl, searchInput, this.requestHeaders); } catch (err) { - console.warn(`Unable to load resources for ${this.key}`); + console.warn(this.t('loadResourcesError', {componentKey: this.key})); } } else { @@ -245,7 +245,7 @@ export default class ListComponent extends Field { } if (!window.indexedDB) { - window.alert("Your browser doesn't support current version of indexedDB"); + window.alert(this.t('indexedDBSupportError')); } if (this.component.indexeddb && this.component.indexeddb.database && this.component.indexeddb.table) { diff --git a/src/components/_classes/multivalue/Multivalue.js b/src/components/_classes/multivalue/Multivalue.js index 3c2e318d50..3b19bdaaa9 100644 --- a/src/components/_classes/multivalue/Multivalue.js +++ b/src/components/_classes/multivalue/Multivalue.js @@ -64,7 +64,7 @@ export default class Multivalue extends Field { } get addAnother() { - return this.t(this.component.addAnother || 'Add Another'); + return this.t(this.component.addAnother || 'addAnother'); } /** @@ -208,7 +208,7 @@ export default class Multivalue extends Field { this.saveCaretPosition(element, index); } catch (err) { - console.warn('An error occurred while trying to save caret position', err); + console.warn(this.t('caretPositionSavingError'), err); } // If a mask is present, delay the update to allow mask to update first. diff --git a/src/components/_classes/nestedarray/NestedArrayComponent.js b/src/components/_classes/nestedarray/NestedArrayComponent.js index 0167ace9bf..29067e9665 100644 --- a/src/components/_classes/nestedarray/NestedArrayComponent.js +++ b/src/components/_classes/nestedarray/NestedArrayComponent.js @@ -24,7 +24,7 @@ export default class NestedArrayComponent extends NestedDataComponent { } get iteratableRows() { - throw new Error('Getter #iteratableRows() is not implemented'); + throw new Error(this.t('iteratableRowsError')); } get rowIndex() { @@ -81,7 +81,7 @@ export default class NestedArrayComponent extends NestedDataComponent { } checkRow(...args) { - console.log('Deprecation Warning: checkRow method has been replaced with processRow'); + console.log(this.t('checkRowDeprecation')); return this.processRow.call(this, ...args); } @@ -150,7 +150,7 @@ export default class NestedArrayComponent extends NestedDataComponent { } const label = component.label || component.key; - return `${label}`; + return `${this.t(label, { _userInput: true })}`; }; const components = this.getComponents(0); diff --git a/src/components/address/Address.js b/src/components/address/Address.js index c2e02e3ee2..3fe44cf771 100644 --- a/src/components/address/Address.js +++ b/src/components/address/Address.js @@ -383,7 +383,7 @@ export default class AddressComponent extends ContainerComponent { } get addAnother() { - return this.t(this.component.addAnother || 'Add Another'); + return this.t(this.component.addAnother || 'addAnother'); } renderElement(value) { diff --git a/src/components/button/Button.js b/src/components/button/Button.js index f213ffd799..5a91acbfa8 100644 --- a/src/components/button/Button.js +++ b/src/components/button/Button.js @@ -375,19 +375,19 @@ export default class ButtonComponent extends Field { break; case 'oauth': if (this.root === this) { - console.warn('You must add the OAuth button to a form for it to function properly'); + console.warn(this.t('noOAuthBtn')); return; } // Display Alert if OAuth config is missing if (!this.oauthConfig) { - this.root.setAlert('danger', 'OAuth not configured. You must configure oauth for your project before it will work.'); + this.root.setAlert('danger', this.t('noOAuthConfiguration')); break; } // Display Alert if oAuth has an error is missing if (this.oauthConfig.error) { - this.root.setAlert('danger', `The Following Error Has Occured ${this.oauthConfig.error}`); + this.root.setAlert('danger', `${this.t('oAuthErrorsTitle')} ${this.t(this.oauthConfig.error)}`); break; } @@ -399,7 +399,7 @@ export default class ButtonComponent extends Field { openOauth(settings) { if (!this.root.formio) { - console.warn('You must attach a Form API url to your form in order to use OAuth buttons.'); + console.warn(this.t('noOAuthFormUrl')); return; } @@ -454,7 +454,7 @@ export default class ButtonComponent extends Field { } // TODO: check for error response here if (settings.state !== params.state) { - this.root.setAlert('danger', 'OAuth state does not match. Please try logging in again.'); + this.root.setAlert('danger', this.t('oAuthStateError')); return; } // Depending on where the settings came from, submit to either the submission endpoint (old) or oauth endpoint (new). @@ -490,7 +490,7 @@ export default class ButtonComponent extends Field { } catch (error) { if (error.name !== 'SecurityError' && (error.name !== 'Error' || error.message !== 'Permission denied')) { - this.root.setAlert('danger', error.message || error); + this.root.setAlert('danger', this.t(`${error.message || error}`)); } } if (!popup || popup.closed || popup.closed === undefined) { diff --git a/src/components/checkbox/Checkbox.js b/src/components/checkbox/Checkbox.js index 7120ae85ef..bf95659d8c 100644 --- a/src/components/checkbox/Checkbox.js +++ b/src/components/checkbox/Checkbox.js @@ -213,7 +213,7 @@ export default class CheckBoxComponent extends Field { return ''; } - return this.t(hasValue ? 'Yes' : 'No'); + return this.t(hasValue ? 'yes' : 'no'); } updateValue(value, flags) { diff --git a/src/components/datagrid/DataGrid.js b/src/components/datagrid/DataGrid.js index 76b81e31e6..e56c7ccf52 100644 --- a/src/components/datagrid/DataGrid.js +++ b/src/components/datagrid/DataGrid.js @@ -404,7 +404,7 @@ export default class DataGridComponent extends NestedArrayComponent { onReorder(element, _target, _source, sibling) { if (!element.dragInfo || (sibling && !sibling.dragInfo)) { - console.warn('There is no Drag Info available for either dragged or sibling element'); + console.warn(this.t('noDragInfoError')); return; } diff --git a/src/components/day/Day.js b/src/components/day/Day.js index 5e5ed62727..4b73d5c087 100644 --- a/src/components/day/Day.js +++ b/src/components/day/Day.js @@ -196,7 +196,7 @@ export default class DayComponent extends Field { this._months = [ { value: '', - label: _.get(this.component, 'fields.month.placeholder') || (this.hideInputLabels ? this.t('Month') : '') + label: _.get(this.component, 'fields.month.placeholder') || (this.hideInputLabels ? this.t('month') : '') }, { value: 1, label: 'January' }, { value: 2, label: 'February' }, @@ -303,7 +303,7 @@ export default class DayComponent extends Field { this.saveCaretPosition(element, name); } catch (err) { - console.warn('An error occurred while trying to save caret position', err); + console.warn(this.t('caretPositionSavingError'), err); } this.updateValue(null, { modified: true, diff --git a/src/components/editgrid/EditGrid.js b/src/components/editgrid/EditGrid.js index 0424b0cefe..8654345da7 100644 --- a/src/components/editgrid/EditGrid.js +++ b/src/components/editgrid/EditGrid.js @@ -129,10 +129,10 @@ export default class EditGridComponent extends NestedArrayComponent { get defaultDialogTemplate() { return ` -

${this.t('Do you want to clear data?')}

+

${this.t('wantToClearData')}

- - + +
`; } @@ -1222,7 +1222,7 @@ export default class EditGridComponent extends NestedArrayComponent { if (valid === null) { editRow.errors.push({ type: 'error', - message: `Invalid row validation for ${this.key}` + message: this.t('componentInvalidRowValidation', { componentKey: this.key }) }); } } diff --git a/src/components/file/File.js b/src/components/file/File.js index 2dce0e4332..56f2f6d876 100644 --- a/src/components/file/File.js +++ b/src/components/file/File.js @@ -239,7 +239,7 @@ export default class FileComponent extends Field { const { videoPlayer } = this.refs; if (!videoPlayer) { - console.warn('Video player not found in template.'); + console.warn(this.t('videoPlayerNotFound')); this.cameraMode = false; this.redraw(); return; @@ -267,7 +267,7 @@ export default class FileComponent extends Field { takePicture() { const { videoPlayer } = this.refs; if (!videoPlayer) { - console.warn('Video player not found in template.'); + console.warn(this.t('videoPlayerNotFound')); this.cameraMode = false; this.redraw(); return; @@ -721,7 +721,7 @@ export default class FileComponent extends Field { file, size: file.size, status: 'info', - message: this.t('Processing file. Please wait...'), + message: this.t('waitFileProcessing'), hash: '', }; } @@ -756,7 +756,7 @@ export default class FileComponent extends Field { return fileWithSameNameUploaded || fileWithSameNameUploading ? { status: 'error', - message: this.t(`File with the same name is already ${fileWithSameNameUploading ? 'being ' : ''}uploaded`), + message: this.t(fileWithSameNameUploading ? 'fileWithDuplicatedNameInProgress' : 'fileWithDuplicatedNameLoaded'), } : {}; } @@ -766,7 +766,7 @@ export default class FileComponent extends Field { if (this.component.filePattern && !this.validatePattern(file, this.component.filePattern)) { return { status: 'error', - message: this.t('File is the wrong type; it must be {{ pattern }}', { + message: this.t('wrongFileType', { pattern: this.component.filePattern, }), }; @@ -776,7 +776,7 @@ export default class FileComponent extends Field { if (this.component.fileMinSize && !this.validateMinSize(file, this.component.fileMinSize)) { return { status: 'error', - message: this.t('File is too small; it must be at least {{ size }}', { + message: this.t('fileTooSmall', { size: this.component.fileMinSize, }), }; @@ -786,7 +786,7 @@ export default class FileComponent extends Field { if (this.component.fileMaxSize && !this.validateMaxSize(file, this.component.fileMaxSize)) { return { status: 'error', - message: this.t('File is too big; it must be at most {{ size }}', { + message: this.t('fileTooBig', { size: this.component.fileMaxSize, }), }; @@ -800,7 +800,7 @@ export default class FileComponent extends Field { return !fileService ? { status: 'error', - message: this.t('File Service not provided.'), + message: this.t('noFileService'), } : {}; } @@ -857,7 +857,7 @@ export default class FileComponent extends Field { this.fileDropHidden = false; return { status: 'error', - message: this.t('File processing has been failed.'), + message: this.t('fileProcessingFailed'), }; } finally { @@ -898,7 +898,7 @@ export default class FileComponent extends Field { } if (this.autoSync) { - fileToSync.message = this.t('Ready to be uploaded into storage'); + fileToSync.message = this.t('readyForUpload'); } this.filesToSync.filesToUpload.push({ @@ -942,8 +942,8 @@ export default class FileComponent extends Field { ...fileInfo, status: 'info', message: this.autoSync - ? this.t('Ready to be removed from storage') - : this.t('Preparing file to remove'), + ? this.t('readyForRemovingFromStorage') + : this.t('preparingFileToRemove'), }); const index = this.dataValue.findIndex(file => file.name === fileInfo.name); @@ -989,7 +989,7 @@ export default class FileComponent extends Field { await this.deleteFile(fileToSync); fileToSync.status = 'success'; - fileToSync.message = this.t('Succefully removed'); + fileToSync.message = this.t('succefullyRemoved'); } catch (response) { fileToSync.status = 'error'; @@ -1076,7 +1076,7 @@ export default class FileComponent extends Field { fileInfo = await this.uploadFile(fileToSync); fileToSync.status = 'success'; - fileToSync.message = this.t('Succefully uploaded'); + fileToSync.message = this.t('succefullyUploaded'); fileInfo.originalName = fileToSync.originalName; fileInfo.hash = fileToSync.hash; @@ -1186,7 +1186,7 @@ export default class FileComponent extends Field { await this.syncFiles(); return this.shouldSyncFiles - ? Promise.reject('Synchronization is failed') + ? Promise.reject(this.t('synchronizationFailed')) : Promise.resolve(); } catch (error) { diff --git a/src/components/form/Form.js b/src/components/form/Form.js index 31490bcf9d..4112f6fb29 100644 --- a/src/components/form/Form.js +++ b/src/components/form/Form.js @@ -230,7 +230,7 @@ export default class FormComponent extends Component { render() { if (this.builderMode) { - return super.render(this.component.label || 'Nested form'); + return super.render(this.t(this.component.label || 'nestedForm')); } const subform = this.subForm ? this.subForm.render() : this.renderTemplate('loading'); return super.render(subform); @@ -246,13 +246,13 @@ export default class FormComponent extends Component { getValueAsString(value, options) { if (!value) { - return 'No data provided'; + return this.t('noDataProvided'); } if (!value.data && value._id) { return value._id; } if (!value.data || !Object.keys(value.data).length) { - return 'No data provided'; + return this.t('noDataProvided'); } if (options?.email) { let result = (` @@ -705,7 +705,7 @@ export default class FormComponent extends Component { : {}; this.subForm.setUrl(submissionUrl, { ...this.options, ...options }); this.subForm.loadSubmission().catch((err) => { - console.error(`Unable to load subform submission ${submission._id}:`, err); + console.error(this.t('subformSubmissionLoadingError', { submissionId: submission._id }), err); }); } else { diff --git a/src/components/number/Number.js b/src/components/number/Number.js index 812793a282..a883acd206 100644 --- a/src/components/number/Number.js +++ b/src/components/number/Number.js @@ -63,7 +63,7 @@ export default class NumberComponent extends Input { } else { if (this.component.thousandsSeparator || this.options.properties?.thousandsSeparator || this.options.thousandsSeparator){ - console.warn('In order for thousands separator to work properly, you must set the delimiter to true in the component json'); + console.warn(this.t('noDelimiterSet')); } this.delimiter = ''; } diff --git a/src/components/recaptcha/ReCaptcha.js b/src/components/recaptcha/ReCaptcha.js index 865c325ced..47fb150a5f 100644 --- a/src/components/recaptcha/ReCaptcha.js +++ b/src/components/recaptcha/ReCaptcha.js @@ -54,7 +54,7 @@ export default class ReCaptchaComponent extends Component { this.recaptchaApiReady = Formio.requireLibrary('googleRecaptcha', 'grecaptcha', recaptchaApiScriptUrl, true); } else { - console.warn('There is no Site Key specified in settings in form JSON'); + console.warn(this.t('noSiteKey')); } } } @@ -70,7 +70,7 @@ export default class ReCaptchaComponent extends Component { async verify(actionName) { const siteKey = _get(this.root.form, 'settings.recaptcha.siteKey'); if (!siteKey) { - console.warn('There is no Site Key specified in settings in form JSON'); + console.warn(this.t('noSiteKey')); return; } if (!this.recaptchaApiReady) { diff --git a/src/components/select/Select.js b/src/components/select/Select.js index 068b2dd29e..8b37a8a674 100644 --- a/src/components/select/Select.js +++ b/src/components/select/Select.js @@ -696,7 +696,7 @@ export default class SelectComponent extends ListComponent { component: this.component, message: err.toString(), }); - console.warn(`Unable to load resources for ${this.key}`); + console.warn(this.t('loadResourcesError', { componentKey: this.key})); } /** * Get the request headers for this select dropdown. @@ -853,7 +853,7 @@ export default class SelectComponent extends ListComponent { } } else if (this.component.dataSrc === 'url' || this.component.dataSrc === 'resource') { - this.addOption('', this.t('loading...')); + this.addOption('', `${this.t('loading')}...`); } } @@ -912,9 +912,9 @@ export default class SelectComponent extends ListComponent { allowHTML: true, placeholder: !!this.component.placeholder, placeholderValue: placeholderValue, - noResultsText: this.t('No results found'), - noChoicesText: this.t('No choices to choose from'), - searchPlaceholderValue: this.t('Type to search'), + noResultsText: this.t('noResultsFound'), + noChoicesText: this.t('noChoices'), + searchPlaceholderValue: this.t('typeToSearch'), shouldSort: false, position: (this.component.dropdown || 'auto'), searchEnabled: useSearch, @@ -1436,7 +1436,7 @@ export default class SelectComponent extends ListComponent { return normalize[dataType]().value; } catch (err) { - console.warn('Failed to normalize value', err); + console.warn(this.t('failedToNormalize'), err); return value; } } @@ -1655,7 +1655,7 @@ export default class SelectComponent extends ListComponent { return (JSON.stringify(normalizedOptionValue) === JSON.stringify(value)); } catch (err) { - console.warn.error('Error while comparing items', err); + console.warn.error(this.t('failedToCompareItems'), err); return false; } }; diff --git a/src/components/selectboxes/SelectBoxes.js b/src/components/selectboxes/SelectBoxes.js index a4d22c6046..a9a1ec804f 100644 --- a/src/components/selectboxes/SelectBoxes.js +++ b/src/components/selectboxes/SelectBoxes.js @@ -284,7 +284,7 @@ export default class SelectBoxesComponent extends RadioComponent { if (!isValid && maxCount && count > maxCount) { const message = this.t( - this.component.maxSelectedCountMessage || 'You may only select up to {{maxCount}} items', + this.component.maxSelectedCountMessage || 'maxSelectItems', { maxCount } ); this.errors.push({ message }); @@ -294,7 +294,7 @@ export default class SelectBoxesComponent extends RadioComponent { else if (!isValid && minCount && count < minCount) { this.setInputsDisabled(false); const message = this.t( - this.component.minSelectedCountMessage || 'You must select at least {{minCount}} items', + this.component.minSelectedCountMessage || 'minSelectItems', { minCount } ); this.errors.push({ message }); diff --git a/src/components/signature/Signature.js b/src/components/signature/Signature.js index 000fd3a39f..d796ea6ac9 100644 --- a/src/components/signature/Signature.js +++ b/src/components/signature/Signature.js @@ -201,7 +201,7 @@ export default class SignatureComponent extends Input { return this.renderModalPreview({ previewText: this.dataValue ? `` : - this.t('Click to Sign') + this.t('clickToSign') }); } @@ -282,7 +282,7 @@ export default class SignatureComponent extends Input { if (_.isUndefined(value) && this.inDataTable) { return ''; } - return value ? 'Yes' : 'No'; + return this.t(value ? 'yes' : 'no'); } focus() { diff --git a/src/components/survey/Survey.js b/src/components/survey/Survey.js index db2274bcbe..b9e984e06c 100644 --- a/src/components/survey/Survey.js +++ b/src/components/survey/Survey.js @@ -151,8 +151,8 @@ export default class SurveyComponent extends Field { - - + + diff --git a/src/components/textarea/TextArea.js b/src/components/textarea/TextArea.js index 82204f9236..b30f115fe2 100644 --- a/src/components/textarea/TextArea.js +++ b/src/components/textarea/TextArea.js @@ -149,7 +149,7 @@ export default class TextAreaComponent extends TextFieldComponent { case 'quill': // Normalize the configurations for quill. if (settings.hasOwnProperty('toolbarGroups') || settings.hasOwnProperty('toolbar')) { - console.warn('The WYSIWYG settings are configured for CKEditor. For this renderer, you will need to use configurations for the Quill Editor. See https://quilljs.com/docs/configuration for more information.'); + console.warn(this.t('needConfigurationForQuill')); settings = this.wysiwygDefault.quill; } @@ -232,7 +232,7 @@ export default class TextAreaComponent extends TextFieldComponent { const quillInstance = moduleInstance.quill; if (!files || !files.length) { - console.warn('No files selected'); + console.warn(this.t('noFilesSelected')); return; } @@ -269,7 +269,7 @@ export default class TextAreaComponent extends TextFieldComponent { }) , Quill.sources.USER); }).catch(error => { - console.warn('Quill image upload failed'); + console.warn(this.t('quillImageUploadFailed')); console.warn(error); quillInstance.enable(true); }); @@ -613,7 +613,7 @@ export default class TextAreaComponent extends TextFieldComponent { } this.element.scrollIntoView(); }).catch((err) => { - console.warn('An editor did not initialize properly when trying to focus:', err); + console.warn(this.t('editorFocusError'), err); }); break; } @@ -622,7 +622,7 @@ export default class TextAreaComponent extends TextFieldComponent { this.editors[0].focus(); this.element.scrollIntoView(); }).catch((err) => { - console.warn('An editor did not initialize properly when trying to focus:', err); + console.warn(this.t('editorFocusError'), err); }); break; } @@ -630,7 +630,7 @@ export default class TextAreaComponent extends TextFieldComponent { this.editorsReady[0]?.then(() => { this.editors[0].focus(); }).catch((err) => { - console.warn('An editor did not initialize properly when trying to focus:', err); + console.warn(this.t('editorFocusError'), err); }); break; } diff --git a/src/i18n.js b/src/i18n.js index ead24f9fae..7c86e75529 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -2,12 +2,14 @@ import enTranslation from './translations/en'; import { fastCloneDeep } from './utils/utils'; + export default { lng: 'en', nsSeparator: '::', keySeparator: '.|.', pluralSeparator: '._.', contextSeparator: '._.', + defaultKeys: fastCloneDeep(enTranslation), resources: { en: { translation: fastCloneDeep(enTranslation) diff --git a/src/translations/en.js b/src/translations/en.js index a3b72f3033..b4a65cdaf1 100644 --- a/src/translations/en.js +++ b/src/translations/en.js @@ -77,5 +77,143 @@ export default { requiredDayField: '{{ field }} is required', requiredDayEmpty: '{{ field }} is required', requiredMonthField: '{{ field }} is required', - requiredYearField: '{{ field }} is required' + requiredYearField: '{{ field }} is required', + formNotReady: 'Form not ready. Use form.ready promise', + noFormElement: 'No DOM element for form.', + notUniqueKey: 'API Key is not unique', + newFormSchema: 'Form schema is for a newer version, please upgrade your renderer. Some functionality may not work.', + missingUrl: 'Missing URL argument', + urlNotAttachedToBtn: 'You should add a URL to this button.', + loadingProjectSettingsError: 'Could not load project settings', + sessionStorageSupportError: 'Session storage is not supported in this browser.', + builderUniqueError: `You cannot add more than one {{componentKeyOrTitle}} component to one page.`, + pageNotFound: 'Page not found', + noDragInfoError: 'There is no Drag Info available for either dragged or sibling element', + addonSupportTypeError:'Addon {{label}} does not support component of type {{type}}', + setPathError: 'Should not be setting the path of a component.', + calculatedPathDeprecation: 'component.calculatedPath was deprecated, use component.path instead.', + unknownTemplate: 'Unknown template: {{name}}', + unknownComponent: 'Unknown component: {{type}}', + renderTemplateFunctionDeprecation: `Form.io 'render' template function is deprecated. + If you need to render template (template A) inside of another template (template B), + pass pre-compiled template A (use this.renderTemplate('template_A_name') as template context variable for template B`, + whenReadyDeprecation: 'The whenReady() method has been deprecated. Please use the dataReady property instead.', + loadResourcesError: 'Unable to load resources for {{componentKey}}', + noSelectDataConfiguration: 'Select component {{componentKey}} does not have data configuration.', + indexedDBSupportError: "Your browser doesn't support current version of indexedDB", + caretPositionSavingError: 'An error occurred while trying to save caret position', + iteratableRowsError: 'Getter #iteratableRows() is not implemented', + checkRowDeprecation: 'Deprecation Warning: checkRow method has been replaced with processRow', + noOAuthBtn: 'You must add the OAuth button to a form for it to function properly', + noOAuthConfiguration: 'OAuth not configured. You must configure oauth for your project before it will work.', + oAuthErrorsTitle: 'The Following Error Has Occured', + noOAuthFormUrl: 'You must attach a Form API url to your form in order to use OAuth buttons.', + oAuthStateError: 'OAuth state does not match. Please try logging in again.', + componentInvalidRowValidation: 'Invalid row validation for {{componentKey}}', + videoPlayerNotFound: 'Video player not found in template.', + synchronizationFailed: 'Synchronization is failed', + fileWithDuplicatedNameInProgress: 'File with the same name is already being uploaded', + fileWithDuplicatedNameLoaded: 'File with the same name is already uploaded', + nestedForm: 'Nested form', + noDataProvided: 'No data provided', + subformSubmissionLoadingError: 'Unable to load subform submission {{submissionId}}:', + noDelimiterSet: 'In order for thousands separator to work properly, you must set the delimiter to true in the component json', + noSiteKey:'There is no Site Key specified in settings in form JSON', + failedToNormalize: 'Failed to normalize value', + failedToCompareItems: 'Error while comparing items', + editorFocusError: 'An editor did not initialize properly when trying to focus:', + quillImageUploadFailed: 'Quill image upload failed', + noFilesSelected: 'No files selected', + needConfigurationForQuill: 'The WYSIWYG settings are configured for CKEditor. For this renderer, you will need to use configurations for the Quill Editor. See https://quilljs.com/docs/configuration for more information.', + waitPdfConverting: 'Converting PDF. Please wait.', + uploading: 'Uploading', + pasteBelow: 'Paste below', + copy: 'Copy', + move: 'Move', + edit: 'Edit', + editJson: 'Edit JSON', + remove: 'Remove', + clickToSetValue: 'Click to set value', + words: 'words', + characters: 'characters', + addAnother: 'Add Another', + yes: 'Yes', + no: 'No', + wantToClearData: 'Do you want to clear data?', + yesDelete:'Yes, delete it', + waitFileProcessing: 'Processing file. Please wait...', + wrongFileType: 'File is the wrong type; it must be {{ pattern }}', + fileTooSmall: 'File is too small; it must be at least {{ size }}', + fileTooBig: 'File is too big; it must be at most {{ size }}', + noFileService: 'File Service not provided.', + fileProcessingFailed: 'File processing has been failed.', + readyForUpload: 'Ready to be uploaded into storage', + readyForRemovingFromStorage: 'Ready to be removed from storage', + preparingFileToRemove: 'Preparing file to remove', + succefullyRemoved: 'Succefully removed', + succefullyUploaded: 'Succefully uploaded', + maxSelectItems: 'You may only select up to {{maxCount}} items', + minSelectItems: 'You must select at least {{minCount}} items', + clickToSign: 'Click to Sign', + question: 'Question', + value: 'Value', + success: 'Success', + noResultsFound: 'No results found', + noChoices: 'No choices to choose from', + typeToSearch: 'Type to search', + loading: 'Loading', + help: 'Help', + component: 'Component', + save: 'Save', + preview: 'Preview', + dragAndDropComponent: 'Drag and Drop a form component', + searchFields: 'Search field(s)', + noMatchesFound: 'No Matches Found', + fileName: 'File Name', + size: 'Size', + type: 'Type', + gallery: 'Gallery', + camera: 'Camera', + dropFilesToAttach: 'Drop files to attach,', + useCamera: 'Use Camera', + browse: 'browse', + takePicture: 'Take Picture', + switchToFileUpload: 'Switch to file upload', + completeStatus: 'Complete', + noStorageSet: 'No storage has been set for this field. File uploads are disabled until storage is set up.', + noFileApiSupport: 'File API & FileReader API not supported.', + noFormDataSupport: "XHR2's FormData is not supported.", + noProgressSupport: "XHR2's upload progress isn't supported.", + close: 'Close', + addResource: 'Add Resource', + autocomplete: 'autocomplete', + showPreview: 'Show preview', + hidePreview: 'Hide preview', + createPage: 'Create Page', + page: 'Page', + closeBtnDescription: 'Close button. Click to get back to the form', + cancelBtnDescription: 'Cancel button. Click to cancel the changes and get back to the form.', + saveBtnDescription:'Save button. Click to save the changes and get back to the form.', + addOrRemove: 'Add/Remove', + anyFileTypesAllowed: 'Any file types are allowed', + allowedFileTypes: 'Allowed file types', + syncing: 'Syncing...', + syncNow: 'Sync Now', + pressToOpen: 'Press to open', + browseToAttachFileFor: 'Browse to attach file for', + or: 'or', + numericOnly: 'numeric only', + uploadPdfFile: 'Upload a PDF File', + dropToStart: 'Drop pdf to start, or', + expand: 'Expand', + collapse:'Collapse', + add: 'Add', + delete: 'Delete', + revert: 'Revert', + removeBtnPressToRemove: 'Remove button. Press to remove', + file: 'file', + captureVideo:'Capture Video', + captureAudio: 'Capture Audio', + captureImage: 'Capture Image', + browseFiles: 'Browse Files' }; diff --git a/src/utils/i18n.js b/src/utils/i18n.js index c92b2ce950..d276a2915f 100644 --- a/src/utils/i18n.js +++ b/src/utils/i18n.js @@ -19,6 +19,10 @@ export class I18n { this.changeLanguage(this.language); } + get defaultKeys() { + return i18n.defaultKeys || {}; + } + setLanguages(languages) { if (languages.resources) { for (const lang in languages.resources) { @@ -82,12 +86,21 @@ export class I18n { } t(text, ...args) { - if (this.currentLanguage[text]) { + let currentTranslation = this.currentLanguage[text]; + // provide compatibility with cases where the entire phrase is used as a key + // get the phrase that is possibly being used as a key + const defaultKey = this.defaultKeys[text]; + if (defaultKey && this.currentLanguage[defaultKey]) { + // get translation using the phrase as a key + currentTranslation = this.currentLanguage[defaultKey]; + } + + if (currentTranslation) { const customTranslationFieldName = args[0]?.field; if (customTranslationFieldName && this.currentLanguage[customTranslationFieldName]) { args[0].field = this.currentLanguage[customTranslationFieldName] } - return Evaluator.interpolateString(this.currentLanguage[text], ...args); + return Evaluator.interpolateString(currentTranslation, ...args); } return Evaluator.interpolateString(text, ...args); } From 20d7c821a16862d44419995d53a5380d038fe4ba Mon Sep 17 00:00:00 2001 From: "ICX\\Tatsiana.Hashtold" Date: Fri, 27 Dec 2024 18:19:46 +0300 Subject: [PATCH 2/5] FIO-7954: made translation extended by modules throung Formio.use --- src/formio.form.js | 4 +++ src/i18n.js | 1 - src/translations/en.js | 58 +++--------------------------------------- src/utils/i18n.js | 27 ++++++++++++++++---- 4 files changed, 30 insertions(+), 60 deletions(-) diff --git a/src/formio.form.js b/src/formio.form.js index 479d53a32d..be0672e32a 100644 --- a/src/formio.form.js +++ b/src/formio.form.js @@ -12,6 +12,7 @@ import { Evaluator } from './utils/Evaluator'; import Licenses from './licenses'; import EventEmitter from './EventEmitter'; import Webform from './Webform'; +import { I18n } from './utils/i18n'; Formio.loadModules = (path = `${Formio.getApiUrl() }/externalModules.js`, name = 'externalModules') => { Formio.requireLibrary(name, name, path, true) @@ -88,6 +89,9 @@ export function registerModule(mod, defaultFn = null, options = {}) { case 'evaluator': Formio.Evaluator.registerEvaluator(mod.evaluator); break; + case 'translations': + I18n.setDefaultTranslations(mod.translations); + break; case 'library': options.license ? Formio.Licenses.addLicense(mod.library, options.license) diff --git a/src/i18n.js b/src/i18n.js index 7c86e75529..2024408b52 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -9,7 +9,6 @@ export default { keySeparator: '.|.', pluralSeparator: '._.', contextSeparator: '._.', - defaultKeys: fastCloneDeep(enTranslation), resources: { en: { translation: fastCloneDeep(enTranslation) diff --git a/src/translations/en.js b/src/translations/en.js index b4a65cdaf1..91cd37bb30 100644 --- a/src/translations/en.js +++ b/src/translations/en.js @@ -1,4 +1,8 @@ + +import bootstrap from '@formio/bootstrap'; + export default { + ...(bootstrap?.translations?.en || {}), unsavedRowsError: 'Please save all rows before proceeding.', invalidRowsError: 'Please correct invalid rows before proceeding.', invalidRowError: 'Invalid row. Please correct it or delete.', @@ -162,58 +166,4 @@ export default { noChoices: 'No choices to choose from', typeToSearch: 'Type to search', loading: 'Loading', - help: 'Help', - component: 'Component', - save: 'Save', - preview: 'Preview', - dragAndDropComponent: 'Drag and Drop a form component', - searchFields: 'Search field(s)', - noMatchesFound: 'No Matches Found', - fileName: 'File Name', - size: 'Size', - type: 'Type', - gallery: 'Gallery', - camera: 'Camera', - dropFilesToAttach: 'Drop files to attach,', - useCamera: 'Use Camera', - browse: 'browse', - takePicture: 'Take Picture', - switchToFileUpload: 'Switch to file upload', - completeStatus: 'Complete', - noStorageSet: 'No storage has been set for this field. File uploads are disabled until storage is set up.', - noFileApiSupport: 'File API & FileReader API not supported.', - noFormDataSupport: "XHR2's FormData is not supported.", - noProgressSupport: "XHR2's upload progress isn't supported.", - close: 'Close', - addResource: 'Add Resource', - autocomplete: 'autocomplete', - showPreview: 'Show preview', - hidePreview: 'Hide preview', - createPage: 'Create Page', - page: 'Page', - closeBtnDescription: 'Close button. Click to get back to the form', - cancelBtnDescription: 'Cancel button. Click to cancel the changes and get back to the form.', - saveBtnDescription:'Save button. Click to save the changes and get back to the form.', - addOrRemove: 'Add/Remove', - anyFileTypesAllowed: 'Any file types are allowed', - allowedFileTypes: 'Allowed file types', - syncing: 'Syncing...', - syncNow: 'Sync Now', - pressToOpen: 'Press to open', - browseToAttachFileFor: 'Browse to attach file for', - or: 'or', - numericOnly: 'numeric only', - uploadPdfFile: 'Upload a PDF File', - dropToStart: 'Drop pdf to start, or', - expand: 'Expand', - collapse:'Collapse', - add: 'Add', - delete: 'Delete', - revert: 'Revert', - removeBtnPressToRemove: 'Remove button. Press to remove', - file: 'file', - captureVideo:'Capture Video', - captureAudio: 'Capture Audio', - captureImage: 'Capture Image', - browseFiles: 'Browse Files' }; diff --git a/src/utils/i18n.js b/src/utils/i18n.js index d276a2915f..4385c50b9f 100644 --- a/src/utils/i18n.js +++ b/src/utils/i18n.js @@ -1,5 +1,7 @@ import { Evaluator } from '@formio/core/utils'; import i18n from '../i18n'; +import { isEmpty } from 'lodash'; +import { fastCloneDeep } from '@formio/core'; const i18Defaults = {}; for (const lang in i18n.resources) { if (i18n.resources.hasOwnProperty(lang)) { @@ -11,19 +13,32 @@ for (const lang in i18n.resources) { * This file is used to mimic the i18n library interface. */ export class I18n { - languages = i18Defaults; + static languages = i18Defaults; + languages = fastCloneDeep(I18n.languages || {}); + defaultKeys = I18n.languages?.en || {}; language = 'en'; currentLanguage = i18Defaults.en; + constructor(languages = {}) { this.setLanguages(languages); this.changeLanguage(this.language); } - get defaultKeys() { - return i18n.defaultKeys || {}; + static setDefaultTranslations(languages) { + if (isEmpty(languages)) { + return; + } + for (const lang in languages) { + if (lang !== 'language' && languages.hasOwnProperty(lang)) { + if (!this.languages[lang]) { + this.languages[lang] = {}; + } + this.languages[lang] = { ...languages[lang], ...this.languages[lang], }; + } + } } - setLanguages(languages) { + setLanguages(languages, noDefaultOverride) { if (languages.resources) { for (const lang in languages.resources) { if (languages.resources.hasOwnProperty(lang)) { @@ -51,7 +66,9 @@ export class I18n { if (!this.languages[lang]) { this.languages[lang] = {}; } - this.languages[lang] = { ...this.languages[lang], ...languages[lang] }; + this.languages[lang] = noDefaultOverride + ? { ...languages[lang], ...this.languages[lang] } + : { ...this.languages[lang], ...languages[lang] }; } } } From d07386c934e4a67c816ef14cec6e85cdceeb5412 Mon Sep 17 00:00:00 2001 From: "ICX\\Tatsiana.Hashtold" Date: Mon, 30 Dec 2024 12:16:57 +0300 Subject: [PATCH 3/5] Fixed tests --- package.json | 2 +- src/components/survey/Survey.js | 4 +- src/translations/en.js | 4 +- ...component-bootstrap-datagrid-multiple.html | 4 +- ...component-bootstrap-datagrid-required.html | 4 +- .../renders/component-bootstrap-datagrid.html | 4 +- ...trap-calculateValueWithManualOverride.html | 4 +- test/renders/form-bootstrap-data.html | 8 ++-- test/renders/form-bootstrap-defaults.html | 4 +- ...rm-bootstrap-formWithCustomFormatDate.html | 4 +- yarn.lock | 39 ++++--------------- 11 files changed, 28 insertions(+), 53 deletions(-) diff --git a/package.json b/package.json index 266cd720cf..e37f419b35 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ }, "homepage": "https://github.com/formio/formio.js#readme", "dependencies": { - "@formio/bootstrap": "3.0.0-dev.111.ae7f187", + "@formio/bootstrap": "v3.0.0-dev.121.085d187", "@formio/choices.js": "^10.2.1", "@formio/core": "2.1.0-dev.193.68cf8c3", "@formio/text-mask-addons": "3.8.0-formio.4", diff --git a/src/components/survey/Survey.js b/src/components/survey/Survey.js index b9e984e06c..caf8aed6cf 100644 --- a/src/components/survey/Survey.js +++ b/src/components/survey/Survey.js @@ -151,8 +151,8 @@ export default class SurveyComponent extends Field {
QuestionValue${this.t('question')}${this.t('value')}
- - + + diff --git a/src/translations/en.js b/src/translations/en.js index 91cd37bb30..7facb77ce7 100644 --- a/src/translations/en.js +++ b/src/translations/en.js @@ -159,8 +159,8 @@ export default { maxSelectItems: 'You may only select up to {{maxCount}} items', minSelectItems: 'You must select at least {{minCount}} items', clickToSign: 'Click to Sign', - question: 'Question', - value: 'Value', + surveyQuestion: 'Question', + surveyQuestionValue: 'Value', success: 'Success', noResultsFound: 'No results found', noChoices: 'No choices to choose from', diff --git a/test/renders/component-bootstrap-datagrid-multiple.html b/test/renders/component-bootstrap-datagrid-multiple.html index 67ea65ca24..077439c484 100644 --- a/test/renders/component-bootstrap-datagrid-multiple.html +++ b/test/renders/component-bootstrap-datagrid-multiple.html @@ -6,8 +6,8 @@ "> - diff --git a/test/renders/component-bootstrap-datagrid-required.html b/test/renders/component-bootstrap-datagrid-required.html index 243abad890..59b46292c3 100644 --- a/test/renders/component-bootstrap-datagrid-required.html +++ b/test/renders/component-bootstrap-datagrid-required.html @@ -6,8 +6,8 @@ "> - diff --git a/test/renders/component-bootstrap-datagrid.html b/test/renders/component-bootstrap-datagrid.html index 00181761a3..5964efb21a 100644 --- a/test/renders/component-bootstrap-datagrid.html +++ b/test/renders/component-bootstrap-datagrid.html @@ -6,8 +6,8 @@ "> - diff --git a/test/renders/form-bootstrap-calculateValueWithManualOverride.html b/test/renders/form-bootstrap-calculateValueWithManualOverride.html index 424666d54a..3dbf6a8f0c 100644 --- a/test/renders/form-bootstrap-calculateValueWithManualOverride.html +++ b/test/renders/form-bootstrap-calculateValueWithManualOverride.html @@ -65,8 +65,8 @@
- diff --git a/test/renders/form-bootstrap-data.html b/test/renders/form-bootstrap-data.html index 18383e24ae..2afd9fb976 100644 --- a/test/renders/form-bootstrap-data.html +++ b/test/renders/form-bootstrap-data.html @@ -199,8 +199,8 @@
- @@ -253,8 +253,8 @@
- diff --git a/test/renders/form-bootstrap-defaults.html b/test/renders/form-bootstrap-defaults.html index 23b9a47392..e1b4d33cd2 100644 --- a/test/renders/form-bootstrap-defaults.html +++ b/test/renders/form-bootstrap-defaults.html @@ -426,8 +426,8 @@
- diff --git a/test/renders/form-bootstrap-formWithCustomFormatDate.html b/test/renders/form-bootstrap-formWithCustomFormatDate.html index 04261ece63..ea9e9a0309 100644 --- a/test/renders/form-bootstrap-formWithCustomFormatDate.html +++ b/test/renders/form-bootstrap-formWithCustomFormatDate.html @@ -64,8 +64,8 @@
- diff --git a/yarn.lock b/yarn.lock index 80d47aadb3..a7f1d4f7ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -209,10 +209,10 @@ resolved "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== -"@formio/bootstrap@3.0.0-dev.111.ae7f187": - version "3.0.0-dev.111.ae7f187" - resolved "https://registry.npmjs.org/@formio/bootstrap/-/bootstrap-3.0.0-dev.111.ae7f187.tgz#fc7021a6c10db7cc1bc5d17e140cd93451e991f2" - integrity sha512-96+YO+jOJ208g1p/EvW+duNLTyCytWu0aXVCu9HaTMQ1icO2zX4okreCUaE9BPp+/aoEs8VzRE/U+pfsb27Bew== +"@formio/bootstrap@v3.0.0-dev.121.085d187": + version "3.0.0-dev.121.085d187" + resolved "https://registry.yarnpkg.com/@formio/bootstrap/-/bootstrap-3.0.0-dev.121.085d187.tgz#7cc8c3a62e531b9b508e68d08fa513241c659da6" + integrity sha512-V9AgDNTiFuvw0g/+QbUu2e8c061obSInmwn3qjsxkySg1VtpuVO2hrhgS8Lqxa5Q3IKbgmkrbCJGex8GCxNAnA== "@formio/choices.js@^10.2.1": version "10.2.1" @@ -7243,7 +7243,7 @@ string-replace-loader@^3.1.0: loader-utils "^2.0.0" schema-utils "^3.0.0" -"string-width-cjs@npm:string-width@^4.2.0": +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -7261,15 +7261,6 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -7330,7 +7321,7 @@ stringifier@^1.3.0: traverse "^0.6.6" type-name "^2.0.1" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -7351,13 +7342,6 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -8424,7 +8408,7 @@ workerpool@^6.5.1: resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -8450,15 +8434,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From 07a8cc64fbfb6d2761fb217c993972ce4e2e692e Mon Sep 17 00:00:00 2001 From: "ICX\\Tatsiana.Hashtold" Date: Mon, 30 Dec 2024 12:38:21 +0300 Subject: [PATCH 4/5] fixed test --- test/renders/form-bootstrap-data.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/renders/form-bootstrap-data.html b/test/renders/form-bootstrap-data.html index 8c218bd01a..2afd9fb976 100644 --- a/test/renders/form-bootstrap-data.html +++ b/test/renders/form-bootstrap-data.html @@ -200,7 +200,7 @@ From bed9ce043d68780d0cc0422a766bcc0b6bafe95a Mon Sep 17 00:00:00 2001 From: "ICX\\Tatsiana.Hashtold" Date: Mon, 30 Dec 2024 13:16:21 +0300 Subject: [PATCH 5/5] fixed test --- test/unit/Webform.unit.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/unit/Webform.unit.js b/test/unit/Webform.unit.js index 7d51605d1f..b672a5207e 100644 --- a/test/unit/Webform.unit.js +++ b/test/unit/Webform.unit.js @@ -1974,7 +1974,10 @@ describe('Webform tests', function() { it('Should get the language passed via options', () => { const formElement = document.createElement('div'); const form = new Webform(formElement, { - language: 'es' + language: 'es', + i18n:{ + es: {} + } }); assert.equal(form.language, 'es');
${this.t('question')}${this.t('value')}${this.t('surveyQuestion')}${this.t('surveyQuestionValue')}
- +
- +
- + - + - + - + - + - + -