diff --git a/src/core/friendly_errors/validate_params.js b/src/core/friendly_errors/validate_params.js index 2e13f962cf..6eab203ba9 100644 --- a/src/core/friendly_errors/validate_params.js +++ b/src/core/friendly_errors/validate_params.js @@ -4,6 +4,7 @@ */ import p5 from '../main'; import * as constants from '../constants'; +import { translator } from '../internationalization'; if (typeof IS_MINIFIED !== 'undefined') { p5._validateParameters = p5._clearValidateParamsCache = () => {}; @@ -484,6 +485,7 @@ if (typeof IS_MINIFIED !== 'undefined') { // function for generating console.log() msg p5._friendlyParamError = function(errorObj, func) { let message; + let translationObj; function formatType() { const format = errorObj.format; @@ -494,9 +496,20 @@ if (typeof IS_MINIFIED !== 'undefined') { switch (errorObj.type) { case 'EMPTY_VAR': { - message = `${func}() was expecting ${formatType()} for parameter #${ - errorObj.position - } (zero-based index), received an empty variable instead. If not intentional, this is often a problem with scope: [https://p5js.org/examples/data-variable-scope.html]`; + translationObj = { + func, + formatType: formatType(), + // It needs to be this way for i18next-extract to work. The comment + // specifies the values that the context can take so that it can + // statically prepare the translation files with them. + /* i18next-extract-mark-context-next-line ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"] */ + position: translator('fes.positions.p', { + context: (errorObj.position + 1).toString(), + defaultValue: (errorObj.position + 1).toString() + }), + link: '[https://p5js.org/examples/data-variable-scope.html]' + }; + break; } case 'WRONG_TYPE': { @@ -505,26 +518,41 @@ if (typeof IS_MINIFIED !== 'undefined') { arg instanceof Array ? 'array' : arg === null ? 'null' : arg.name || typeof arg; - message = `${func}() was expecting ${formatType()} for parameter #${ - errorObj.position - } (zero-based index), received ${argType} instead`; + + translationObj = { + func, + formatType: formatType(), + argType, + /* i18next-extract-mark-context-next-line ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"] */ + position: translator('fes.positions.p', { + context: (errorObj.position + 1).toString(), + defaultValue: (errorObj.position + 1).toString() + }) + }; + break; } case 'TOO_FEW_ARGUMENTS': { - message = `${func}() was expecting at least ${ - errorObj.minParams - } arguments, but received only ${errorObj.argCount}`; + translationObj = { + func, + minParams: errorObj.minParams, + argCount: errorObj.argCount + }; + break; } case 'TOO_MANY_ARGUMENTS': { - message = `${func}() was expecting no more than ${ - errorObj.maxParams - } arguments, but received ${errorObj.argCount}`; + translationObj = { + func, + maxParams: errorObj.maxParams, + argCount: errorObj.argCount + }; + break; } } - if (message) { + if (translationObj) { try { // const re = /Function\.validateParameters.*[\r\n].*[\r\n].*\(([^)]*)/; const myError = new Error(); @@ -544,13 +572,18 @@ if (typeof IS_MINIFIED !== 'undefined') { parsed[3].columnNumber }`; if (location) { - message += ` at ${location}`; + translationObj.location = translator('fes.location', { location }); } } catch (err) { if (err instanceof p5.ValidationError) { throw err; } } + + translationObj.context = errorObj.type; + // i18next-extract-mark-context-next-line ["EMPTY_VAR", "TOO_MANY_ARGUMENTS", "TOO_FEW_ARGUMENTS", "WRONG_TYPE"] + message = translator('fes.friendlyParamError.type', translationObj); + p5._friendlyError(`${message}.`, func, 3); } }; diff --git a/src/core/internationalization.js b/src/core/internationalization.js index 04d82a44ba..97d01860ca 100644 --- a/src/core/internationalization.js +++ b/src/core/internationalization.js @@ -1,6 +1,11 @@ import i18next from 'i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; -import resources from '../../translations'; + +let resources; +// Do not include translations in the minified js +if (typeof IS_MINIFIED === 'undefined') { + resources = require('../../translations').default; +} /** * This is our translation function. Give it a key and @@ -31,6 +36,7 @@ export const initialize = () => nestingPrefix: '$tr(', nestingSuffix: ')', defaultNS: 'translation', + returnEmptyString: false, interpolation: { escapeValue: false }, diff --git a/tasks/build/browserify.js b/tasks/build/browserify.js index c940504eda..701ecefbbd 100644 --- a/tasks/build/browserify.js +++ b/tasks/build/browserify.js @@ -39,7 +39,9 @@ module.exports = function(grunt) { browseified = browseified .exclude('../../docs/reference/data.json') .exclude('../../../docs/parameterData.json') - .ignore('../../translations/index.js'); + .exclude('../../translations') + .ignore('i18next') + .ignore('i18next-browser-languagedetector'); } const babelifyOpts = { plugins: ['static-fs'] }; diff --git a/translations/en/translation.json b/translations/en/translation.json index 3e1f5a522d..4c77eeb508 100644 --- a/translations/en/translation.json +++ b/translations/en/translation.json @@ -13,7 +13,28 @@ "table": "It looks like there was a problem loading your table file. {{suggestion}}", "xml": "It looks like there was a problem loading your XML file. {{suggestion}}" }, + "friendlyParamError": { + "type_EMPTY_VAR": "{{func}}() was expecting {{formatType}} for the {{position}} parameter, received an empty variable instead. {{location}}\n\nIf not intentional, this is often a problem with scope: {{link}}", + "type_TOO_FEW_ARGUMENTS": "{{func}}() was expecting at least {{minParams}} arguments, but received only {{argCount}}. {{location}}", + "type_TOO_MANY_ARGUMENTS": "{{func}}() was expecting no more than {{maxParams}} arguments, but received {{argCount}}. {{location}}", + "type_WRONG_TYPE": "{{func}}() was expecting {{formatType}} for the {{position}} parameter, received {{argType}} instead. {{location}}" + }, + "location": "(at {{location}})", "misusedTopLevel": "Did you just try to use p5.js's {{symbolName}} {{symbolType}}? If so, you may want to move it into your sketch's setup() function.\n\nFor more details, see: {{link}}", + "positions": { + "p_1": "first", + "p_10": "tenth", + "p_11": "eleventh", + "p_12": "twelfth", + "p_2": "second", + "p_3": "third", + "p_4": "fourth", + "p_5": "fifth", + "p_6": "sixth", + "p_7": "seventh", + "p_8": "eighth", + "p_9": "ninth" + }, "pre": "🌸 p5.js says: {{message}}", "welcome": "Welcome! This is your friendly debugger. To turn me off, switch to using p5.min.js." } diff --git a/translations/es/translation.json b/translations/es/translation.json index d91413c8eb..b2fbe22131 100644 --- a/translations/es/translation.json +++ b/translations/es/translation.json @@ -13,7 +13,28 @@ "table": "", "xml": "" }, + "friendlyParamError": { + "type_EMPTY_VAR": "", + "type_TOO_FEW_ARGUMENTS": "", + "type_TOO_MANY_ARGUMENTS": "", + "type_WRONG_TYPE": "" + }, + "location": "", "misusedTopLevel": "", + "positions": { + "p_1": "", + "p_10": "", + "p_11": "", + "p_12": "", + "p_2": "", + "p_3": "", + "p_4": "", + "p_5": "", + "p_6": "", + "p_7": "", + "p_8": "", + "p_9": "" + }, "pre": "🌸 p5.js dice: {{message}}", "welcome": "" }