Translation problems with complex RegEx
See original GitHub issueOverview of the issue
We generated an entity from a JDL file, and complex RegEx on the fields. The generated code in the HTML file executes with a JS error, due to escaping problems with the ngx-translate lib.
Motivation for or Use Case
A complex regex implies a runtime JS error in the generated code.
Reproduce the error
Here is an example of the JDL :
entity Candidate {
companyName String required maxlength(32) pattern("^[a-zA-Z0-9 \-&,'\.]*$"),
lastname String required maxlength(32) pattern("^[^\-][a-zA-Z0-9 \-']*[^\-']$")
}
The generated HTML is :
<small class="form-text text-danger"
[hidden]="!editForm.controls.companyName?.errors?.pattern" jhiTranslate="entity.validation.pattern" translateValues="{ pattern: '^[a-zA-Z0-9 \\-&,'\\.]*$' }">
This field should follow pattern "^[a-zA-Z0-9 \-&,'\.]*$".
</small>
<small class="form-text text-danger"
[hidden]="!editForm.controls.lastname?.errors?.pattern" jhiTranslate="entity.validation.pattern" translateValues="{ pattern: '^[^\\-][a-zA-Z0-9 \\-']*[^\\-']$' }">
This field should follow pattern "^[^\-][a-zA-Z0-9 \-']*[^\-']$".
</small>
The error in the JS console is :
EXCEPTION: Error in ./JhiTranslateComponent class JhiTranslateComponent - inline template:0:6 caused by: Wrong parameter in TranslatePipe. Expected a valid Object, received: { ‘pattern’: ‘^[a-zA-Z0-9 \-&,’\.]*$’ }
Related issues
Suggest a Fix
I think there is a problem with the ngx-translate lib which tries to rewrite the regex :
let validArgs: string = args[0]
.replace(/(\')?([a-zA-Z0-9_]+)(\')?(\s)?:/g, '"$2":')
.replace(/:(\s)?(\')(.*?)(\')/g, ':"$3"');
try {
interpolateParams = JSON.parse(validArgs);
} catch(e) {
throw new SyntaxError(`Wrong parameter in TranslatePipe. Expected a valid Object, received: ${args[0]}`);
}
So perhaps JHipster should escape or transform some caracters, but we didn’t find the good combinaison for our regex.
JHipster Version(s)
recrutement@0.0.0 E:\projets\Prim\eura
+-- UNMET PEER DEPENDENCY @angular/compiler@2.4.7
+-- UNMET PEER DEPENDENCY @angular/core@2.4.7
`-- generator-jhipster@4.0.5
JHipster configuration
{
"generator-jhipster": {
"jhipsterVersion": "4.0.5",
"baseName": "recrutement",
"packageName": "com.prim.eura",
"packageFolder": "com/prim/eura",
"serverPort": "8080",
"authenticationType": "session",
"hibernateCache": "no",
"clusteredHttpSession": false,
"websocket": false,
"databaseType": "sql",
"devDatabaseType": "mssql",
"prodDatabaseType": "mssql",
"searchEngine": false,
"messageBroker": false,
"serviceDiscoveryType": false,
"buildTool": "maven",
"enableSocialSignIn": false,
"rememberMeKey": "",
"clientFramework": "angular2",
"useSass": true,
"clientPackageManager": "yarn",
"applicationType": "monolith",
"testFrameworks": [
"cucumber"
],
"jhiPrefix": "jhi",
"otherModules": [
{
"name": "generator-jhipster-bootstrap-material-design",
"version": "3.5.1"
},
{
"name": "generator-jhipster-mssql",
"version": "2.1.2"
},
{
"name": "generator-jhipster-entity-audit-and-delete",
"version": "2.2.2"
},
{
"name": "generator-jhipster-webservice",
"version": "0.1.0"
}
],
"enableTranslation": true,
"nativeLanguage": "fr",
"languages": [
"fr",
"en"
]
}
}
Entity configuration(s) entityName.json
files generated in the .jhipster
directory
Candidate.json
{
"fluentMethods": true,
"relationships": [
{
"relationshipType": "one-to-one",
"javadoc": "The user account for the candidate",
"relationshipName": "user",
"otherEntityName": "user",
"otherEntityField": "id",
"ownerSide": true,
"otherEntityRelationshipName": "candidate"
}
],
"fields": [
{
"fieldName": "comment",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 44
},
{
"fieldName": "msaNumber",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength"
],
"fieldValidateRulesMaxlength": 3
},
{
"fieldName": "siretNumber",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 14,
"fieldValidateRulesPattern": "^([0-9]{14}|(et|ET|Et|eT)[0-9]{11})$"
},
{
"fieldName": "companyName",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 32,
"fieldValidateRulesPattern": "^[a-zA-Z0-9 \\-&,'\\.]*$"
},
{
"fieldName": "companyAddress1",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 32,
"fieldValidateRulesPattern": "^[a-zA-Z0-9 \\-&,'\\.]*$"
},
{
"fieldName": "companyAddress2",
"fieldType": "String",
"fieldValidateRules": [
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 32,
"fieldValidateRulesPattern": "^[a-zA-Z0-9 \\-&,'\\.]*$"
},
{
"fieldName": "companyPC",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 5,
"fieldValidateRulesPattern": "^[0-9]*$"
},
{
"fieldName": "companyCity",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 27,
"fieldValidateRulesPattern": "^[a-zA-Z0-9 \\-&,'\\.]*$"
},
{
"fieldName": "lastname",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 32,
"fieldValidateRulesPattern": "^[^\\-][a-zA-Z0-9 \\-']*[^\\-']$"
},
{
"fieldName": "firstname",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 32,
"fieldValidateRulesPattern": "^[^\\-][a-zA-Z0-9 \\-']*[^\\-']$"
},
{
"fieldName": "matricule",
"fieldType": "String",
"fieldValidateRules": [
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 13,
"fieldValidateRulesPattern": "^[0-9]{13}$"
},
{
"fieldName": "birthDate",
"fieldType": "ZonedDateTime",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "birthInsee",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength"
],
"fieldValidateRulesMaxlength": 3
},
{
"fieldName": "hireDate",
"fieldType": "ZonedDateTime",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "codeNaf",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 5,
"fieldValidateRulesPattern": "^[a-zA-Z0-9]*$"
},
{
"fieldName": "usename",
"fieldType": "String",
"fieldValidateRules": [
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 32,
"fieldValidateRulesPattern": "^[a-zA-Z0-9 \\-']*$"
},
{
"fieldName": "sex",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 1,
"fieldValidateRulesPattern": "^(M|F)$"
},
{
"fieldName": "birthDepartment",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength"
],
"fieldValidateRulesMaxlength": 2
},
{
"fieldName": "contractType",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 2
},
{
"fieldName": "cddEndDate",
"fieldType": "ZonedDateTime"
},
{
"fieldName": "trialPeriod",
"fieldType": "Integer",
"fieldValidateRules": [
"required",
"max"
],
"fieldValidateRulesMax": 999
},
{
"fieldName": "phone",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 20
},
{
"fieldName": "suffixDelegationAccount",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 5
},
{
"fieldName": "btapeCode",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength"
],
"fieldValidateRulesMaxlength": 4
},
{
"fieldName": "dpaeStatus",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength"
],
"fieldValidateRulesMaxlength": 1
},
{
"fieldName": "employerExemptionOccasionalWorker",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "employerExemptionJobseeker",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "noisyWork",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "vribatingWork",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "bioHazardWork",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "nigthWork",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "chemicalHazardWork",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "otherRisksWork",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 40
},
{
"fieldName": "aptEquivalentWork",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "disabledWorker",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "longTimeSeasonal",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "aptEquivalentWorkSameEmployer",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "aptEquivalentWorkOtherEmployer",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "addressComplement",
"fieldType": "String",
"fieldValidateRules": [
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 25,
"fieldValidateRulesPattern": "^[a-zA-Z0-9 \\-&,'\\.]*$"
},
{
"fieldName": "addressNumber",
"fieldType": "Integer",
"fieldValidateRules": [
"max"
],
"fieldValidateRulesMax": 9999
},
{
"fieldName": "addressBtq",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 1
},
{
"fieldName": "addressLaneType",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 4
},
{
"fieldName": "addressLane",
"fieldType": "String",
"fieldValidateRules": [
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 25,
"fieldValidateRulesPattern": "^[a-zA-Z0-9 \\-&,'\\.]*$"
},
{
"fieldName": "addressPC",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 5,
"fieldValidateRulesPattern": "^[0-9]*$"
},
{
"fieldName": "addressCity",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 25,
"fieldValidateRulesPattern": "^[a-zA-Z0-9 \\-&,'\\.]*$"
},
{
"fieldName": "addressCountry",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength",
"pattern"
],
"fieldValidateRulesMaxlength": 3,
"fieldValidateRulesPattern": "^[0-9]*$"
},
{
"fieldName": "foreignResidentTax",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "workLabel",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 25
},
{
"fieldName": "candidateType",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 3
},
{
"fieldName": "technicalWorker",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "salaryGross",
"fieldType": "Float",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "hierarchyLevel",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 5
},
{
"fieldName": "partialTimeRate",
"fieldType": "Float"
},
{
"fieldName": "workplaceDepartment",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 2
},
{
"fieldName": "workplaceInsee",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 3
},
{
"fieldName": "executive",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "agirc",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "articleFour",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "articleThirtySix",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "paidKind",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "taskPaid",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "equivalentSchedule",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "excludedMonthlyPay",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "seasonal",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "renewableCdd",
"fieldType": "Boolean",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "cddLength",
"fieldType": "Integer",
"fieldValidateRules": [
"max"
],
"fieldValidateRulesMax": 999
},
{
"fieldName": "previousCddEndDate",
"fieldType": "ZonedDateTime"
},
{
"fieldName": "cddEndCause",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 2
},
{
"fieldName": "fileReference",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 36
},
{
"fieldName": "transmitCanal",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 1
},
{
"fieldName": "email",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 50
},
{
"fieldName": "mobile",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 20
}
],
"changelogDate": "20170220135511",
"entityTableName": "candidate",
"dto": "no",
"pagination": "infinite-scroll",
"service": "serviceImpl"
}
Contract.json
{
"fluentMethods": true,
"relationships": [
{
"relationshipType": "many-to-one",
"relationshipName": "candidate",
"otherEntityName": "candidate",
"otherEntityField": "id"
},
{
"relationshipType": "many-to-one",
"relationshipName": "template",
"otherEntityName": "contractTemplate",
"otherEntityField": "id"
}
],
"fields": [
{
"fieldName": "label",
"fieldType": "String"
},
{
"fieldName": "path",
"fieldType": "String"
}
],
"changelogDate": "20170220135511",
"entityTableName": "contract",
"dto": "no",
"pagination": "infinite-scroll",
"service": "serviceImpl"
}
ContractTemplate.json
{
"fluentMethods": true,
"relationships": [],
"fields": [
{
"fieldName": "label",
"fieldType": "String"
},
{
"fieldName": "code",
"fieldType": "String"
},
{
"fieldName": "filename",
"fieldType": "String"
}
],
"changelogDate": "20170220135511",
"entityTableName": "contract_template",
"dto": "no",
"pagination": "no",
"service": "no"
}
ContractTemplateMapping.json
{
"fluentMethods": true,
"relationships": [
{
"relationshipType": "many-to-one",
"relationshipName": "template",
"otherEntityName": "contractTemplate",
"otherEntityField": "id"
}
],
"fields": [
{
"fieldName": "label",
"fieldType": "String"
},
{
"fieldName": "code",
"fieldType": "String"
},
{
"fieldName": "mappingValue",
"fieldType": "String"
}
],
"changelogDate": "20170220135511",
"entityTableName": "contract_template_mapping",
"dto": "no",
"pagination": "no",
"service": "no"
}
DpaeGeneration.json
{
"fluentMethods": true,
"relationships": [],
"fields": [
{
"fieldName": "type",
"fieldType": "DpaeGenerationType",
"fieldValues": "OK,KO"
},
{
"fieldName": "filename",
"fieldType": "String"
}
],
"changelogDate": "20170220135511",
"entityTableName": "dpae_generation",
"dto": "no",
"pagination": "infinite-scroll",
"service": "serviceImpl"
}
Validation.json
{
"fluentMethods": true,
"relationships": [
{
"relationshipType": "many-to-one",
"javadoc": "The candidate to validate",
"relationshipName": "candidate",
"otherEntityName": "candidate",
"otherEntityField": "id"
},
{
"relationshipType": "many-to-one",
"javadoc": "The user validating the candidate",
"relationshipName": "user",
"otherEntityName": "user",
"otherEntityField": "id"
}
],
"fields": [
{
"fieldName": "status",
"fieldType": "ValidationStatus",
"fieldValues": "PENDING,VALIDATED,REFUSED"
},
{
"fieldName": "rank",
"fieldType": "Integer"
}
],
"changelogDate": "20170220135511",
"entityTableName": "validation",
"dto": "no",
"pagination": "no",
"service": "no"
}
Browsers and Operating System
java version “1.8.0_112” Java™ SE Runtime Environment (build 1.8.0_112-b15) Java HotSpot™ 64-Bit Server VM (build 25.112-b15, mixed mode)
git version 2.10.1.windows.1
node: v6.9.5
npm: 3.10.10
yeoman: 1.8.5
yarn: 0.20.3
Docker version 1.13.1, build 092cba3
docker-compose version 1.11.1, build 7afaa436
- Checking this box is mandatory (this is just to show you read everything)
Issue Analytics
- State:
- Created 7 years ago
- Comments:7 (6 by maintainers)
What’s the use of displaying a regexp to a user who may not understand it? The error message should explain the expected format in human words probably with an example.
So I would rather be in favor of not generating error messages including regex patterns.
The easiest fix would be to pass the filed name instead of the pattern for the translation as below as the developer need to write appropriate message as per business need anyway. So no point in spending lot of effort here. Plz go ahead if some one wants to PR this as its not high priority for me