static substitute( context, substitutions, str, escape ) {
		substitutions = makeArray( substitutions );

		// tokenize string (search for strings)
		return Substitution.tokenize( String( str ) )
			// and reduce token array back to a string
			.reduce( ( result, token ) => {
				// search for variables in each token independently
				result.push( token.substituteVariables( ( all, left, name, right ) => {
					// ignore double curly bracket vars
					if ( left ) { return all; }

					// var names are case independent
					name = name.toLowerCase();

					let res = false;
					// find the first matching variable and get its value
					substitutions.every( substitution => {
						if ( !substitution.hasVar( name ) ) { return true; }

						res = substitution.getValue( context );
						if ( escape && res !== false ) {
							// escape the variable's content
							res = token.escape( res );
						}
					});

					return res === false
						? all
						: `${res}${right || ""}`;
				}) );

				return result;
			}, [] )
			.join( "" );
	}
Apply multiple substituions at once.
@param {Object} context
@param {(Substitution|Substitution[])} substitutions
@param {String} str
@param {Boolean?} escape
@return {String}