@unicef-polymer/etools-form-builder 2.1.1 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/assets/translations.d.ts +6 -0
  2. package/dist/assets/translations.js +67 -0
  3. package/dist/form-attachments-popup/form-attachments-popup.d.ts +1 -0
  4. package/dist/form-attachments-popup/form-attachments-popup.js +8 -1
  5. package/dist/form-attachments-popup/form-attachments-popup.tpl.js +7 -5
  6. package/dist/form-fields/abstract-field-base.class.d.ts +5 -0
  7. package/dist/form-fields/abstract-field-base.class.js +20 -2
  8. package/dist/form-fields/repeatable-fields/repeatable-attachment-field.js +3 -2
  9. package/dist/form-fields/repeatable-fields/repeatable-base-field.js +3 -2
  10. package/dist/form-fields/repeatable-fields/repeatable-number-field.js +3 -2
  11. package/dist/form-fields/single-fields/attachment-field.js +2 -1
  12. package/dist/form-fields/single-fields/base-field.js +2 -1
  13. package/dist/form-fields/single-fields/number-field.js +2 -1
  14. package/dist/form-fields/single-fields/scale-field.js +2 -1
  15. package/dist/form-groups/form-abstract-group.d.ts +5 -0
  16. package/dist/form-groups/form-abstract-group.js +25 -3
  17. package/dist/form-groups/form-card.js +10 -5
  18. package/dist/form-groups/form-collapsed-card.js +11 -10
  19. package/dist/lib/additional-components/confirmation-dialog.d.ts +2 -0
  20. package/dist/lib/additional-components/confirmation-dialog.js +9 -2
  21. package/dist/lib/additional-components/etools-fb-card.d.ts +5 -0
  22. package/dist/lib/additional-components/etools-fb-card.js +26 -3
  23. package/dist/lib/utils/translate.d.ts +1 -0
  24. package/dist/lib/utils/translate.js +9 -0
  25. package/dist/lib/utils/validations.helper.d.ts +1 -1
  26. package/dist/lib/utils/validations.helper.js +14 -7
  27. package/package.json +8 -8
@@ -0,0 +1,6 @@
1
+ declare const translations: {
2
+ [lang: string]: {
3
+ [key: string]: string;
4
+ };
5
+ };
6
+ export default translations;
@@ -0,0 +1,67 @@
1
+ const translations = {
2
+ en: {
3
+ SAVE: 'Save',
4
+ DOWNLOAD: 'Download',
5
+ CHANGE: 'Change',
6
+ DELETE: 'Delete',
7
+ CANCEL: 'Cancel',
8
+ OK: 'Ok',
9
+ ADD: 'Add',
10
+ UPLOAD_ATTACHMENTS_FAILED: 'Can not upload attachments. Please try again later',
11
+ REQUIRED_FIELD: 'This field is required',
12
+ MUST_BE_INTEGER: 'Must be an integer',
13
+ MUST_BE_NUMBER: 'Must be a number',
14
+ CLEAR: 'Clear',
15
+ GROUP_REQUIRED: 'Group is required. At least one group must exist',
16
+ GROUP: 'group',
17
+ THIS_GROUP: 'this group',
18
+ CHECK_FIELDS_TRY_AGAIN: 'Please check all fields and try again',
19
+ CONFIRM_DELETE: 'Are you sure you want to delete',
20
+ UPLOAD_FILES: 'Upload Files',
21
+ FILE: 'File',
22
+ FILES: 'Files',
23
+ ATTACHMENTS_FOR: 'Attachments for',
24
+ PARTNER: 'Partner',
25
+ CP_OUTPUT: 'CP Output',
26
+ PD_SSFA: 'PD/SSFA',
27
+ TEXT_MUST_BE_LESS_CHARS: 'Text must be less than {0} character',
28
+ DOES_NOT_MATCH_PATTERN: 'Does not match allowed pattern',
29
+ NUMBER_MUST_BE_GREATER_THAN: 'Number must be greater than {0}',
30
+ NUMBER_MUST_BE_LOWER_THAN: 'Number must be lower than {0}',
31
+ DOCUMENT_TYPE: 'Document type',
32
+ SELECT_DOCUMENT_TYPE: 'Select Document Type'
33
+ },
34
+ fr: {
35
+ SAVE: 'Sauvegarder',
36
+ DOWNLOAD: 'Télécharger',
37
+ CHANGE: 'Changer',
38
+ DELETE: 'Effacer',
39
+ CANCEL: 'Annuler',
40
+ OK: "D'accord",
41
+ ADD: 'Ajouter',
42
+ UPLOAD_ATTACHMENTS_FAILED: 'Impossible de télécharger les pièces jointes. Veuillez réessayer plus tard',
43
+ REQUIRED_FIELD: 'Ce champ est requis',
44
+ MUST_BE_INTEGER: 'Doit être un entier',
45
+ MUST_BE_NUMBER: 'Doit être un nombre',
46
+ CLEAR: 'Dégager',
47
+ GROUP_REQUIRED: 'Le groupe est requis. Au moins un groupe doit exister',
48
+ GROUP: 'groupe',
49
+ THIS_GROUP: 'ce groupe',
50
+ CHECK_FIELDS_TRY_AGAIN: 'Veuillez vérifier tous les champs et réessayer',
51
+ CONFIRM_DELETE: 'Etes-vous sûr que vous voulez supprimer',
52
+ UPLOAD_FILES: 'Télécharger des fichiers',
53
+ FILE: 'Dossier',
54
+ FILES: 'Des dossiers',
55
+ ATTACHMENTS_FOR: 'Pièces jointes pour',
56
+ PARTNER: 'Partenaire',
57
+ CP_OUTPUT: 'Sortie CP',
58
+ PD_SSFA: 'PD/SSFA',
59
+ TEXT_MUST_BE_LESS_CHARS: 'Le texte doit comporter moins de {0} caractères',
60
+ DOES_NOT_MATCH_PATTERN: 'Ne correspond pas au modèle autorisé',
61
+ NUMBER_MUST_BE_GREATER_THAN: 'Le nombre doit être supérieur à {0}',
62
+ NUMBER_MUST_BE_LOWER_THAN: 'Le nombre doit être inférieur à {0}',
63
+ DOCUMENT_TYPE: 'Type de document',
64
+ SELECT_DOCUMENT_TYPE: 'Sélectionnez le type de document'
65
+ }
66
+ };
67
+ export default translations;
@@ -51,6 +51,7 @@ export declare class FormAttachmentsPopup extends LitElement {
51
51
  saveBtnClicked: boolean;
52
52
  attachments: StoredAttachment[];
53
53
  metadata: BlueprintMetadata;
54
+ language: string;
54
55
  link: HTMLLinkElement;
55
56
  readonly: boolean;
56
57
  popupTitle: string;
@@ -17,6 +17,7 @@ import { SharedStyles } from '../lib/styles/shared-styles';
17
17
  import { AttachmentsStyles } from '../lib/styles/attachments.styles';
18
18
  import { AttachmentsHelper } from './form-attachments-popup.helper';
19
19
  import { deleteFileFromDexie } from '@unicef-polymer/etools-upload/offline/dexie-operations';
20
+ import { getTranslation } from '../lib/utils/translate';
20
21
  let FormAttachmentsPopup = class FormAttachmentsPopup extends LitElement {
21
22
  constructor() {
22
23
  super();
@@ -36,6 +37,9 @@ let FormAttachmentsPopup = class FormAttachmentsPopup extends LitElement {
36
37
  if (!AttachmentsHelper.isInitialized) {
37
38
  throw new Error('Please initialize attachments popup before use');
38
39
  }
40
+ if (!this.language) {
41
+ this.language = window.localStorage.defaultLanguage || 'en';
42
+ }
39
43
  }
40
44
  set dialogData({ attachments, title, metadata, readonly, computedPath, errors }) {
41
45
  this.popupTitle = title;
@@ -148,7 +152,7 @@ let FormAttachmentsPopup = class FormAttachmentsPopup extends LitElement {
148
152
  this.attachments = [...this.attachments, ...parsedAttachments];
149
153
  if (error && error.length) {
150
154
  console.error(error);
151
- fireEvent(this, 'toast', { text: 'Can not upload attachments. Please try again later' });
155
+ fireEvent(this, 'toast', { text: getTranslation(this.language, 'UPLOAD_ATTACHMENTS_FAILED') });
152
156
  }
153
157
  }
154
158
  deleteAttachment(index) {
@@ -239,6 +243,9 @@ __decorate([
239
243
  __decorate([
240
244
  property()
241
245
  ], FormAttachmentsPopup.prototype, "metadata", void 0);
246
+ __decorate([
247
+ property()
248
+ ], FormAttachmentsPopup.prototype, "language", void 0);
242
249
  __decorate([
243
250
  query('#link')
244
251
  ], FormAttachmentsPopup.prototype, "link", void 0);
@@ -1,6 +1,7 @@
1
1
  import { html } from 'lit-html';
2
2
  import { InputStyles } from '../lib/styles/input-styles';
3
3
  import { DialogStyles } from '../lib/styles/dialog.styles';
4
+ import { getTranslation } from '../lib/utils/translate';
4
5
  export function template() {
5
6
  var _a;
6
7
  return html `
@@ -11,7 +12,8 @@ export function template() {
11
12
  no-padding
12
13
  keep-dialog-open
13
14
  ?opened="${this.dialogOpened}"
14
- .okBtnText="Save"
15
+ .okBtnText="${getTranslation(this.language, 'SAVE')}"
16
+ .cancelBtnText="${getTranslation(this.language, 'CANCEL')}"
15
17
  .hideConfirmBtn="${this.readonly}"
16
18
  dialog-title="${this.popupTitle}"
17
19
  @close="${this.onClose}"
@@ -31,8 +33,8 @@ export function template() {
31
33
  .selected="${attachment.file_type}"
32
34
  @etools-selected-item-changed="${({ detail }) => { var _a; return this.changeFileType(attachment, (_a = detail.selectedItem) === null || _a === void 0 ? void 0 : _a.value, index); }}"
33
35
  trigger-value-change-event
34
- label="Document Type"
35
- placeholder="Select Document Type"
36
+ label="${getTranslation(this.language, 'DOCUMENT_TYPE')}"
37
+ placeholder="${getTranslation(this.language, 'SELECT_DOCUMENT_TYPE')}"
36
38
  required
37
39
  ?readonly="${this.readonly}"
38
40
  hide-search
@@ -58,7 +60,7 @@ export function template() {
58
60
  @tap="${() => this.downloadFile(attachment)}"
59
61
  >
60
62
  <iron-icon icon="cloud-download" class="dw-icon"></iron-icon>
61
- Download
63
+ ${getTranslation(this.language, 'DOWNLOAD')}
62
64
  </paper-button>
63
65
 
64
66
  <!-- Delete Button -->
@@ -67,7 +69,7 @@ export function template() {
67
69
  ?hidden="${this.readonly}"
68
70
  @tap="${() => this.deleteAttachment(index)}"
69
71
  >
70
- Delete
72
+ ${getTranslation(this.language, 'DELETE')}
71
73
  </paper-button>
72
74
  </div>
73
75
  `;
@@ -5,6 +5,7 @@ import { FieldValidator } from '../lib/utils/validations.helper';
5
5
  */
6
6
  export declare abstract class AbstractFieldBaseClass<T> extends LitElement {
7
7
  questionText: string;
8
+ language: string;
8
9
  set isReadonly(readonly: boolean);
9
10
  get isReadonly(): boolean;
10
11
  required: boolean;
@@ -15,6 +16,10 @@ export declare abstract class AbstractFieldBaseClass<T> extends LitElement {
15
16
  set defaultValue(value: any);
16
17
  private _defaultValue;
17
18
  private _readonly;
19
+ constructor();
20
+ connectedCallback(): void;
21
+ disconnectedCallback(): void;
22
+ handleLanguageChange(e: CustomEvent): void;
18
23
  protected render(): TemplateResult;
19
24
  protected questionTemplate(): TemplateResult;
20
25
  protected metaValidation(value: unknown): string | null;
@@ -12,7 +12,7 @@ import { FlexLayoutClasses } from '../lib/styles/flex-layout-classes';
12
12
  */
13
13
  export class AbstractFieldBaseClass extends LitElement {
14
14
  constructor() {
15
- super(...arguments);
15
+ super();
16
16
  this.questionText = '';
17
17
  this.required = false;
18
18
  this.placeholder = '';
@@ -20,6 +20,10 @@ export class AbstractFieldBaseClass extends LitElement {
20
20
  this.validators = [];
21
21
  this.touched = false;
22
22
  this._readonly = false;
23
+ if (!this.language) {
24
+ this.language = window.localStorage.defaultLanguage || 'en';
25
+ }
26
+ this.handleLanguageChange = this.handleLanguageChange.bind(this);
23
27
  }
24
28
  set isReadonly(readonly) {
25
29
  this._readonly = readonly;
@@ -34,6 +38,17 @@ export class AbstractFieldBaseClass extends LitElement {
34
38
  this.setDefaultValue(this._readonly, value);
35
39
  this.requestUpdate();
36
40
  }
41
+ connectedCallback() {
42
+ super.connectedCallback();
43
+ document.addEventListener('language-changed', this.handleLanguageChange.bind(this));
44
+ }
45
+ disconnectedCallback() {
46
+ super.disconnectedCallback();
47
+ document.removeEventListener('language-changed', this.handleLanguageChange.bind(this));
48
+ }
49
+ handleLanguageChange(e) {
50
+ this.language = e.detail.language;
51
+ }
37
52
  render() {
38
53
  return html `
39
54
  <div class="finding-container">
@@ -46,7 +61,7 @@ export class AbstractFieldBaseClass extends LitElement {
46
61
  return html `<span class="question-text">${this.questionText}</span>`;
47
62
  }
48
63
  metaValidation(value) {
49
- const message = validate(this.validators, value);
64
+ const message = validate(this.validators, value, this.language);
50
65
  return message ? message : this.customValidation(value);
51
66
  }
52
67
  setDefaultValue(readonly, defaultValue) {
@@ -162,6 +177,9 @@ export class AbstractFieldBaseClass extends LitElement {
162
177
  __decorate([
163
178
  property({ type: String })
164
179
  ], AbstractFieldBaseClass.prototype, "questionText", void 0);
180
+ __decorate([
181
+ property()
182
+ ], AbstractFieldBaseClass.prototype, "language", void 0);
165
183
  __decorate([
166
184
  property({ type: Boolean, attribute: 'is-readonly' })
167
185
  ], AbstractFieldBaseClass.prototype, "isReadonly", null);
@@ -11,6 +11,7 @@ import { html, css, customElement } from 'lit-element';
11
11
  import { fireEvent } from '../../lib/utils/fire-custom-event';
12
12
  import { SharedStyles } from '../../lib/styles/shared-styles';
13
13
  import { AttachmentsStyles } from '../../lib/styles/attachments.styles';
14
+ import { getTranslation } from '../../lib/utils/translate';
14
15
  let RepeatableAttachmentField = class RepeatableAttachmentField extends RepeatableBaseField {
15
16
  constructor() {
16
17
  super(...arguments);
@@ -45,7 +46,7 @@ let RepeatableAttachmentField = class RepeatableAttachmentField extends Repeatab
45
46
  @tap="${() => this.downloadFile(value)}"
46
47
  >
47
48
  <iron-icon icon="cloud-download" class="dw-icon"></iron-icon>
48
- Download
49
+ ${getTranslation(this.language, 'DOWNLOAD')}
49
50
  </paper-button>
50
51
 
51
52
  <!-- Delete Button -->
@@ -54,7 +55,7 @@ let RepeatableAttachmentField = class RepeatableAttachmentField extends Repeatab
54
55
  ?hidden="${this.isReadonly}"
55
56
  @tap="${() => this.removeControl(index)}"
56
57
  >
57
- Delete
58
+ ${getTranslation(this.language, 'DELETE')}
58
59
  </paper-button>
59
60
  </div>
60
61
  `
@@ -7,6 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { css, html, property } from 'lit-element';
8
8
  import { AbstractFieldBaseClass } from '../abstract-field-base.class';
9
9
  import { fireEvent } from '../../lib/utils/fire-custom-event';
10
+ import { getTranslation } from '../../lib/utils/translate';
10
11
  export class RepeatableBaseField extends AbstractFieldBaseClass {
11
12
  constructor() {
12
13
  super(...arguments);
@@ -34,7 +35,7 @@ export class RepeatableBaseField extends AbstractFieldBaseClass {
34
35
  ></iron-icon>
35
36
  </div>`)}
36
37
  <paper-button class="add-button" ?hidden="${this.isReadonly}" @click="${() => this.addNewField()}">
37
- Add
38
+ ${getTranslation(this.language, 'ADD')}
38
39
  </paper-button>
39
40
  </div>
40
41
  </div>
@@ -66,7 +67,7 @@ export class RepeatableBaseField extends AbstractFieldBaseClass {
66
67
  }
67
68
  let errorMessage;
68
69
  if (this.required && !value && value !== null && typeof value !== 'number') {
69
- errorMessage = 'This field is required!';
70
+ errorMessage = getTranslation(this.language, 'REQUIRED_FIELD');
70
71
  }
71
72
  else {
72
73
  errorMessage = this.metaValidation(value);
@@ -9,6 +9,7 @@ import '@polymer/paper-input/paper-input';
9
9
  import { InputStyles } from '../../lib/styles/input-styles';
10
10
  import { RepeatableBaseField } from './repeatable-base-field';
11
11
  import { AbstractFieldBaseClass } from '../abstract-field-base.class';
12
+ import { getTranslation } from '../../lib/utils/translate';
12
13
  let RepeatableNumberField = class RepeatableNumberField extends RepeatableBaseField {
13
14
  constructor() {
14
15
  super(...arguments);
@@ -41,10 +42,10 @@ let RepeatableNumberField = class RepeatableNumberField extends RepeatableBaseFi
41
42
  return null;
42
43
  }
43
44
  if (isNaN(value)) {
44
- return 'Must be a number';
45
+ return getTranslation(this.language, 'MUST_BE_NUMBER');
45
46
  }
46
47
  const integerValidation = !this.isInteger || value - Math.floor(value) === 0;
47
- return integerValidation ? null : 'Must be an integer';
48
+ return integerValidation ? null : getTranslation(this.language, 'MUST_BE_INTEGER');
48
49
  }
49
50
  static get styles() {
50
51
  // language=CSS
@@ -11,6 +11,7 @@ import { html, customElement } from 'lit-element';
11
11
  import { fireEvent } from '../../lib/utils/fire-custom-event';
12
12
  import { SharedStyles } from '../../lib/styles/shared-styles';
13
13
  import { AttachmentsStyles } from '../../lib/styles/attachments.styles';
14
+ import { getTranslation } from '../../lib/utils/translate';
14
15
  let AttachmentField = class AttachmentField extends BaseField {
15
16
  constructor() {
16
17
  super(...arguments);
@@ -64,7 +65,7 @@ let AttachmentField = class AttachmentField extends BaseField {
64
65
  }
65
66
  if (error && error.length) {
66
67
  console.error(error);
67
- fireEvent(this, 'toast', { text: 'Can not upload attachments. Please try again later' });
68
+ fireEvent(this, 'toast', { text: getTranslation(this.language, 'UPLOAD_ATTACHMENTS_FAILED') });
68
69
  }
69
70
  }
70
71
  downloadFile(attachment) {
@@ -7,6 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { property } from 'lit-element';
8
8
  import { fireEvent } from '../../lib/utils/fire-custom-event';
9
9
  import { AbstractFieldBaseClass } from '../abstract-field-base.class';
10
+ import { getTranslation } from '../../lib/utils/translate';
10
11
  export class BaseField extends AbstractFieldBaseClass {
11
12
  constructor() {
12
13
  super(...arguments);
@@ -40,7 +41,7 @@ export class BaseField extends AbstractFieldBaseClass {
40
41
  validateField(value) {
41
42
  let errorMessage;
42
43
  if (this.required && !value && typeof value !== 'number') {
43
- errorMessage = 'This field is required!';
44
+ errorMessage = getTranslation(this.language, 'REQUIRED_FIELD');
44
45
  }
45
46
  else {
46
47
  errorMessage = this.metaValidation(value);
@@ -8,6 +8,7 @@ import { css, customElement, html } from 'lit-element';
8
8
  import { BaseField } from './base-field';
9
9
  import '@polymer/paper-input/paper-input';
10
10
  import { InputStyles } from '../../lib/styles/input-styles';
11
+ import { getTranslation } from '../../lib/utils/translate';
11
12
  let NumberField = class NumberField extends BaseField {
12
13
  constructor() {
13
14
  super(...arguments);
@@ -44,7 +45,7 @@ let NumberField = class NumberField extends BaseField {
44
45
  return 'Must be a number';
45
46
  }
46
47
  const integerValidation = !this.isInteger || value - Math.floor(value) === 0;
47
- return integerValidation ? null : 'Must be an integer';
48
+ return integerValidation ? null : getTranslation(this.language, 'MUST_BE_INTEGER');
48
49
  }
49
50
  static get styles() {
50
51
  // language=CSS
@@ -10,6 +10,7 @@ import { repeat } from 'lit-html/directives/repeat';
10
10
  import '@polymer/paper-radio-group/paper-radio-group';
11
11
  import '@polymer/paper-radio-button/paper-radio-button';
12
12
  import { InputStyles } from '../../lib/styles/input-styles';
13
+ import { getTranslation } from '../../lib/utils/translate';
13
14
  let ScaleField = class ScaleField extends BaseField {
14
15
  constructor() {
15
16
  super(...arguments);
@@ -32,7 +33,7 @@ let ScaleField = class ScaleField extends BaseField {
32
33
  </paper-radio-group>
33
34
 
34
35
  <paper-button ?hidden="${this.isReadonly}" @click="${() => this.valueChanged(null)}" class="clear-button">
35
- <iron-icon icon="clear"></iron-icon>Clear
36
+ <iron-icon icon="clear"></iron-icon>${getTranslation(this.language, 'CLEAR')}
36
37
  </paper-button>
37
38
  </div>
38
39
  <div ?hidden="${!this.errorMessage}" class="error-text">${this.errorMessage}</div>
@@ -27,6 +27,7 @@ export declare class FormAbstractGroup extends LitElement implements IFormBuilde
27
27
  groupStructure: BlueprintGroup;
28
28
  metadata: BlueprintMetadata;
29
29
  parentGroupName: string;
30
+ language: string;
30
31
  readonly: boolean;
31
32
  protected _errors: GenericObject;
32
33
  protected _value: GenericObject;
@@ -45,6 +46,10 @@ export declare class FormAbstractGroup extends LitElement implements IFormBuilde
45
46
  * @param errors
46
47
  */
47
48
  set errors(errors: GenericObject | string[] | null);
49
+ constructor();
50
+ connectedCallback(): void;
51
+ disconnectedCallback(): void;
52
+ handleLanguageChange(e: CustomEvent): void;
48
53
  render(): TemplateResult;
49
54
  renderChild(child: BlueprintGroup | BlueprintField | Information): TemplateResult | TemplateResult[];
50
55
  renderField(blueprintField: BlueprintField): TemplateResult;
@@ -19,6 +19,7 @@ import { clone } from 'ramda';
19
19
  import { live } from 'lit-html/directives/live';
20
20
  import { openDialog } from '../lib/utils/dialog';
21
21
  import { FormBuilderCardStyles } from '../lib/styles/form-builder-card.styles';
22
+ import { getTranslation } from '../lib/utils/translate';
22
23
  export var FieldTypes;
23
24
  (function (FieldTypes) {
24
25
  FieldTypes["FILE_TYPE"] = "file";
@@ -40,12 +41,16 @@ export var StructureTypes;
40
41
  })(StructureTypes || (StructureTypes = {}));
41
42
  let FormAbstractGroup = class FormAbstractGroup extends LitElement {
42
43
  constructor() {
43
- super(...arguments);
44
+ super();
44
45
  this.parentGroupName = '';
45
46
  this.readonly = false;
46
47
  this._errors = {};
47
48
  this._value = {};
48
49
  this.computedPath = [];
50
+ if (!this.language) {
51
+ this.language = window.localStorage.defaultLanguage || 'en';
52
+ }
53
+ this.handleLanguageChange = this.handleLanguageChange.bind(this);
49
54
  }
50
55
  /**
51
56
  * Make value property immutable
@@ -73,6 +78,17 @@ let FormAbstractGroup = class FormAbstractGroup extends LitElement {
73
78
  this._errors = errors;
74
79
  }
75
80
  }
81
+ connectedCallback() {
82
+ super.connectedCallback();
83
+ document.addEventListener('language-changed', this.handleLanguageChange.bind(this));
84
+ }
85
+ disconnectedCallback() {
86
+ super.disconnectedCallback();
87
+ document.removeEventListener('language-changed', this.handleLanguageChange.bind(this));
88
+ }
89
+ handleLanguageChange(e) {
90
+ this.language = e.detail.language;
91
+ }
76
92
  render() {
77
93
  if (!this.groupStructure || !this.metadata) {
78
94
  return html ``;
@@ -122,7 +138,10 @@ let FormAbstractGroup = class FormAbstractGroup extends LitElement {
122
138
  return html `
123
139
  ${value.map((_, index) => this.getGroupTemplate(groupStructure, index))}
124
140
  <paper-button class="add-group save-button" @click="${() => this.addGroup(groupStructure.name)}">
125
- Add ${!groupStructure.title || groupStructure.title.length > 15 ? 'group' : groupStructure.title}
141
+ ${getTranslation(this.language, 'ADD')}
142
+ ${!groupStructure.title || groupStructure.title.length > 15
143
+ ? getTranslation(this.language, 'GROUP')
144
+ : groupStructure.title}
126
145
  </paper-button>
127
146
  `;
128
147
  }
@@ -240,7 +259,7 @@ let FormAbstractGroup = class FormAbstractGroup extends LitElement {
240
259
  openDialog({
241
260
  dialog: 'confirmation-popup',
242
261
  dialogData: {
243
- text: `Group is required. At least one group must exist`,
262
+ text: getTranslation(this.language, 'GROUP_REQUIRED'),
244
263
  hideConfirmBtn: true,
245
264
  dialogTitle: ''
246
265
  }
@@ -338,6 +357,9 @@ __decorate([
338
357
  __decorate([
339
358
  property({ type: String })
340
359
  ], FormAbstractGroup.prototype, "parentGroupName", void 0);
360
+ __decorate([
361
+ property()
362
+ ], FormAbstractGroup.prototype, "language", void 0);
341
363
  __decorate([
342
364
  property({ type: Boolean, attribute: 'readonly' })
343
365
  ], FormAbstractGroup.prototype, "readonly", void 0);
@@ -10,6 +10,7 @@ import { clone, equals } from 'ramda';
10
10
  import { FormAbstractGroup } from './form-abstract-group';
11
11
  import '@polymer/iron-collapse';
12
12
  import { openDialog } from '../lib/utils/dialog';
13
+ import { getTranslation } from '../lib/utils/translate';
13
14
  let FormCard = class FormCard extends FormAbstractGroup {
14
15
  constructor() {
15
16
  super(...arguments);
@@ -46,10 +47,12 @@ let FormCard = class FormCard extends FormAbstractGroup {
46
47
  <div
47
48
  class="remove-group"
48
49
  ?hidden="${!this.groupStructure.repeatable}"
49
- @click="${() => this.confirmRemove(this.groupStructure.title || 'this group')}"
50
+ @click="${() => this.confirmRemove(this.groupStructure.title || getTranslation(this.language, 'THIS_GROUP'))}"
50
51
  >
51
52
  Remove
52
- ${!this.groupStructure.title || this.groupStructure.title.length > 15 ? 'group' : this.groupStructure.title}
53
+ ${!this.groupStructure.title || this.groupStructure.title.length > 15
54
+ ? getTranslation(this.language, 'GROUP')
55
+ : this.groupStructure.title}
53
56
  <paper-icon-button icon="delete" class="attachments-warning"></paper-icon-button>
54
57
  </div>
55
58
  </div>
@@ -57,7 +60,9 @@ let FormCard = class FormCard extends FormAbstractGroup {
57
60
 
58
61
  <iron-collapse ?opened="${this.showSaveButton}">
59
62
  <div class="layout horizontal end-justified card-buttons actions-container">
60
- <paper-button class="save-button" @tap="${() => this.saveChanges()}">Save</paper-button>
63
+ <paper-button class="save-button" @tap="${() => this.saveChanges()}"
64
+ >${getTranslation(this.language, 'SAVE')}</paper-button
65
+ >
61
66
  </div>
62
67
  </iron-collapse>
63
68
  </section>
@@ -77,7 +82,7 @@ let FormCard = class FormCard extends FormAbstractGroup {
77
82
  }
78
83
  saveChanges() {
79
84
  if (Object.keys(this._errors).length) {
80
- fireEvent(this, 'toast', { text: 'Please check all fields and try again' });
85
+ fireEvent(this, 'toast', { text: getTranslation(this.language, 'CHECK_FIELDS_TRY_AGAIN') });
81
86
  return;
82
87
  }
83
88
  fireEvent(this, 'value-changed', { value: this.value });
@@ -87,7 +92,7 @@ let FormCard = class FormCard extends FormAbstractGroup {
87
92
  openDialog({
88
93
  dialog: 'confirmation-popup',
89
94
  dialogData: {
90
- text: `Are you sure you want to delete ${groupName}`
95
+ text: `${getTranslation(this.language, 'CONFIRM_DELETE')} ${groupName}`
91
96
  }
92
97
  }).then((response) => {
93
98
  if (response.confirmed) {
@@ -11,6 +11,7 @@ import { openDialog } from '../lib/utils/dialog';
11
11
  import { FormAbstractGroup, StructureTypes } from './form-abstract-group';
12
12
  import '../lib/additional-components/etools-fb-card';
13
13
  import '../lib/additional-components/confirmation-dialog';
14
+ import { getTranslation } from '../lib/utils/translate';
14
15
  const PARTNER_KEY = 'partner';
15
16
  const OUTPUT_KEY = 'output';
16
17
  const INTERVENTION_KEY = 'intervention';
@@ -87,7 +88,7 @@ let FormCollapsedCard = class FormCollapsedCard extends FormAbstractGroup {
87
88
  <paper-icon-button
88
89
  icon="close"
89
90
  class="attachments-warning"
90
- @click="${() => this.confirmRemove(this.groupStructure.title || 'this group')}"
91
+ @click="${() => this.confirmRemove(this.groupStructure.title || getTranslation(this.language, 'THIS_GROUP'))}"
91
92
  ></paper-icon-button>
92
93
  </div>
93
94
  <div slot="content">${this.renderGroupChildren()}</div>
@@ -125,11 +126,11 @@ let FormCollapsedCard = class FormCollapsedCard extends FormAbstractGroup {
125
126
  retrieveTitle(target) {
126
127
  switch (target) {
127
128
  case PARTNER_KEY:
128
- return `Partner: `;
129
+ return `${getTranslation(this.language, 'PARTNER')}: `;
129
130
  case OUTPUT_KEY:
130
- return `CP Output: `;
131
+ return `${getTranslation(this.language, 'CP_OUTPUT')}: `;
131
132
  case INTERVENTION_KEY:
132
- return `PD/SSFA: `;
133
+ return `${getTranslation(this.language, 'PD_SSFA')}: `;
133
134
  default:
134
135
  return '';
135
136
  }
@@ -166,7 +167,7 @@ let FormCollapsedCard = class FormCollapsedCard extends FormAbstractGroup {
166
167
  }
167
168
  saveChanges() {
168
169
  if (Object.keys(this._errors).length) {
169
- fireEvent(this, 'toast', { text: 'Please check all fields and try again' });
170
+ fireEvent(this, 'toast', { text: getTranslation(this.language, 'CHECK_FIELDS_TRY_AGAIN') });
170
171
  return;
171
172
  }
172
173
  this.isEditMode = false;
@@ -187,7 +188,7 @@ let FormCollapsedCard = class FormCollapsedCard extends FormAbstractGroup {
187
188
  dialogData: {
188
189
  attachments: (_a = this.value) === null || _a === void 0 ? void 0 : _a.attachments,
189
190
  metadata: this.metadata,
190
- title: `Attachments for ${this.retrieveTitle(this.parentGroupName) + ': ' + this.groupStructure.title}`,
191
+ title: `${getTranslation(this.language, 'ATTACHMENTS_FOR')} ${this.retrieveTitle(this.parentGroupName) + ': ' + this.groupStructure.title}`,
191
192
  computedPath: this.computedPath.concat([this.groupStructure.name, 'attachments']),
192
193
  errors: this._errors.attachments
193
194
  },
@@ -218,7 +219,7 @@ let FormCollapsedCard = class FormCollapsedCard extends FormAbstractGroup {
218
219
  openDialog({
219
220
  dialog: 'confirmation-popup',
220
221
  dialogData: {
221
- text: `Are you sure you want to delete ${groupName}`
222
+ text: `${getTranslation(this.language, 'CONFIRM_DELETE')} ${groupName}`
222
223
  }
223
224
  }).then((response) => {
224
225
  if (response.confirmed) {
@@ -228,13 +229,13 @@ let FormCollapsedCard = class FormCollapsedCard extends FormAbstractGroup {
228
229
  }
229
230
  getAttachmentsBtnText(attachmentsCount = 0) {
230
231
  if (attachmentsCount === 1) {
231
- return `${attachmentsCount} File`;
232
+ return `${attachmentsCount} ${getTranslation(this.language, 'FILE')}`;
232
233
  }
233
234
  else if (attachmentsCount > 1) {
234
- return `${attachmentsCount} Files`;
235
+ return `${attachmentsCount} ${getTranslation(this.language, 'FILES')}`;
235
236
  }
236
237
  else {
237
- return 'Upload Files';
238
+ return getTranslation(this.language, 'UPLOAD_FILES');
238
239
  }
239
240
  }
240
241
  };
@@ -1,6 +1,7 @@
1
1
  import { LitElement, CSSResultArray } from 'lit-element';
2
2
  export declare class ConfirmationDialog extends LitElement {
3
3
  dialogOpened: boolean;
4
+ language: string;
4
5
  text: string;
5
6
  dialogTitle: string;
6
7
  hideConfirmBtn: boolean;
@@ -9,6 +10,7 @@ export declare class ConfirmationDialog extends LitElement {
9
10
  dialogTitle: string;
10
11
  hideConfirmBtn: boolean;
11
12
  });
13
+ constructor();
12
14
  render(): unknown;
13
15
  onClose(): void;
14
16
  confirm(): void;
@@ -6,13 +6,17 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { LitElement, property, html, css, customElement } from 'lit-element';
8
8
  import { fireEvent } from '../utils/fire-custom-event';
9
+ import { getTranslation } from '../utils/translate';
9
10
  let ConfirmationDialog = class ConfirmationDialog extends LitElement {
10
11
  constructor() {
11
- super(...arguments);
12
+ super();
12
13
  this.dialogOpened = true;
13
14
  this.text = '';
14
15
  this.dialogTitle = '';
15
16
  this.hideConfirmBtn = false;
17
+ if (!this.language) {
18
+ this.language = window.localStorage.defaultLanguage || 'en';
19
+ }
16
20
  }
17
21
  set dialogData({ text, dialogTitle = 'Are you', hideConfirmBtn = false }) {
18
22
  this.text = text;
@@ -28,7 +32,7 @@ let ConfirmationDialog = class ConfirmationDialog extends LitElement {
28
32
  no-padding
29
33
  keep-dialog-open
30
34
  ?hide-confirm-btn="${this.hideConfirmBtn}"
31
- cancel-btn-text="${this.hideConfirmBtn ? 'Ok' : 'Cancel'}"
35
+ cancel-btn-text="${getTranslation(this.language, this.hideConfirmBtn ? 'OK' : 'CANCEL')}"
32
36
  ?opened="${this.dialogOpened}"
33
37
  theme="confirmation"
34
38
  dialog-title="${this.dialogTitle}"
@@ -59,6 +63,9 @@ let ConfirmationDialog = class ConfirmationDialog extends LitElement {
59
63
  __decorate([
60
64
  property()
61
65
  ], ConfirmationDialog.prototype, "dialogOpened", void 0);
66
+ __decorate([
67
+ property()
68
+ ], ConfirmationDialog.prototype, "language", void 0);
62
69
  ConfirmationDialog = __decorate([
63
70
  customElement('confirmation-popup')
64
71
  ], ConfirmationDialog);
@@ -7,10 +7,15 @@ export declare class EtoolsFbCard extends LitElement {
7
7
  hideEditButton: boolean;
8
8
  collapsed: boolean;
9
9
  edit: boolean;
10
+ language: string;
10
11
  static get styles(): CSSResultArray;
12
+ constructor();
11
13
  save(): void;
12
14
  cancel(): void;
13
15
  startEdit(): void;
14
16
  toggleCollapse(): void;
17
+ connectedCallback(): void;
18
+ disconnectedCallback(): void;
19
+ handleLanguageChange(e: CustomEvent): void;
15
20
  protected render(): TemplateResult;
16
21
  }
@@ -10,14 +10,19 @@ import { CardStyles } from '../styles/card-styles';
10
10
  import { elevationStyles } from '../styles/elevation-styles';
11
11
  import { FlexLayoutClasses } from '../styles/flex-layout-classes';
12
12
  import { fireEvent } from '../utils/fire-custom-event';
13
+ import { getTranslation } from '../utils/translate';
13
14
  let EtoolsFbCard = class EtoolsFbCard extends LitElement {
14
15
  constructor() {
15
- super(...arguments);
16
+ super();
16
17
  this.isEditable = false;
17
18
  this.isCollapsible = false;
18
19
  this.hideEditButton = false;
19
20
  this.collapsed = false;
20
21
  this.edit = false;
22
+ if (!this.language) {
23
+ this.language = window.localStorage.defaultLanguage || 'en';
24
+ }
25
+ this.handleLanguageChange = this.handleLanguageChange.bind(this);
21
26
  }
22
27
  static get styles() {
23
28
  // language=CSS
@@ -142,6 +147,17 @@ let EtoolsFbCard = class EtoolsFbCard extends LitElement {
142
147
  toggleCollapse() {
143
148
  this.collapsed = !this.collapsed;
144
149
  }
150
+ connectedCallback() {
151
+ super.connectedCallback();
152
+ document.addEventListener('language-changed', this.handleLanguageChange.bind(this));
153
+ }
154
+ disconnectedCallback() {
155
+ super.disconnectedCallback();
156
+ document.removeEventListener('language-changed', this.handleLanguageChange.bind(this));
157
+ }
158
+ handleLanguageChange(e) {
159
+ this.language = e.detail.language;
160
+ }
145
161
  // language=HTML
146
162
  render() {
147
163
  return html `
@@ -180,8 +196,12 @@ let EtoolsFbCard = class EtoolsFbCard extends LitElement {
180
196
  ${this.isEditable && this.edit
181
197
  ? html `
182
198
  <div class="layout horizontal end-justified card-buttons">
183
- <paper-button @tap="${() => this.cancel()}">Cancel</paper-button>
184
- <paper-button class="save-button" @tap="${() => this.save()}">Save</paper-button>
199
+ <paper-button @tap="${() => this.cancel()}"
200
+ >${getTranslation(this.language, 'CANCEL')}</paper-button
201
+ >
202
+ <paper-button class="save-button" @tap="${() => this.save()}"
203
+ >${getTranslation(this.language, 'SAVE')}</paper-button
204
+ >
185
205
  </div>
186
206
  `
187
207
  : ''}
@@ -209,6 +229,9 @@ __decorate([
209
229
  __decorate([
210
230
  property({ type: Boolean })
211
231
  ], EtoolsFbCard.prototype, "edit", void 0);
232
+ __decorate([
233
+ property()
234
+ ], EtoolsFbCard.prototype, "language", void 0);
212
235
  EtoolsFbCard = __decorate([
213
236
  customElement('etools-fb-card')
214
237
  ], EtoolsFbCard);
@@ -0,0 +1 @@
1
+ export declare function getTranslation(lang: string, key: string): string;
@@ -0,0 +1,9 @@
1
+ import translations from '../../assets/translations';
2
+ export function getTranslation(lang, key) {
3
+ try {
4
+ return translations[lang][key];
5
+ }
6
+ catch (error) {
7
+ return translations.en[key];
8
+ }
9
+ }
@@ -23,4 +23,4 @@ export declare type LowerValidation = {
23
23
  allow_equality: boolean;
24
24
  };
25
25
  export declare type FieldValidator = MaxLengthValidation | RegexValidation | GreaterValidation | LowerValidation;
26
- export declare function validate(validators: FieldValidator[], value: any): string | null;
26
+ export declare function validate(validators: FieldValidator[], value: any, language: string): string | null;
@@ -1,3 +1,4 @@
1
+ import { getTranslation } from './translate';
1
2
  export var Validations;
2
3
  (function (Validations) {
3
4
  Validations["MAX_LENGTH"] = "max_length";
@@ -5,30 +6,36 @@ export var Validations;
5
6
  Validations["LOWER_THAN"] = "lt";
6
7
  Validations["GREATER_THAN"] = "gt";
7
8
  })(Validations || (Validations = {}));
8
- export function validate(validators, value) {
9
+ export function validate(validators, value, language) {
9
10
  let message = null;
10
11
  for (const validator of validators) {
11
- message = checkValidation(validator, value);
12
+ message = checkValidation(validator, value, language);
12
13
  if (message) {
13
14
  break;
14
15
  }
15
16
  }
16
17
  return message;
17
18
  }
18
- function checkValidation(validation, value) {
19
+ function checkValidation(validation, value, language) {
19
20
  switch (validation.name) {
20
21
  case Validations.MAX_LENGTH:
21
22
  const maxLength = Number(validation[Validations.MAX_LENGTH]) + 1;
22
- return String(value).length < maxLength ? null : `Text must be less than ${maxLength} character`;
23
+ return String(value).length < maxLength
24
+ ? null
25
+ : getTranslation(language, 'TEXT_MUST_BE_LESS_CHARS').replace('{0}', String(maxLength));
23
26
  case Validations.REGEX:
24
27
  const regex = new RegExp(`^${validation[Validations.REGEX]}$`);
25
- return regex.test(String(value)) ? null : `Doesn't match allowed pattern`;
28
+ return regex.test(String(value)) ? null : getTranslation(language, 'DOES_NOT_MATCH_PATTERN');
26
29
  case Validations.GREATER_THAN:
27
30
  const greaterThan = Number(validation.threshold) - Number(validation.allow_equality);
28
- return Number(value) > greaterThan ? null : `Number must be greater than ${greaterThan}`;
31
+ return Number(value) > greaterThan
32
+ ? null
33
+ : getTranslation(language, 'NUMBER_MUST_BE_GREATER_THAN').replace('{0}', String(greaterThan));
29
34
  case Validations.LOWER_THAN:
30
35
  const lowerThan = Number(validation.threshold) + Number(validation.allow_equality);
31
- return Number(value) < lowerThan ? null : `Number must be lower than ${lowerThan}`;
36
+ return Number(value) < lowerThan
37
+ ? null
38
+ : getTranslation(language, 'NUMBER_MUST_BE_LOWER_THAN').replace('{0}', String(lowerThan));
32
39
  default:
33
40
  return null;
34
41
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@unicef-polymer/etools-form-builder",
3
3
  "description": "Etools FM Form Builder components",
4
- "version": "2.1.1",
4
+ "version": "2.1.2",
5
5
  "contributors": [
6
6
  "eTools Team"
7
7
  ],
@@ -28,9 +28,9 @@
28
28
  "@polymer/paper-toast": "^3.0.1",
29
29
  "@polymer/paper-toggle-button": "^3.0.1",
30
30
  "@types/ramda": "^0.26.43",
31
- "@unicef-polymer/etools-dialog": "^6.0.3",
32
- "@unicef-polymer/etools-dropdown": "^3.9.2",
33
- "@unicef-polymer/etools-upload": "^4.3.0",
31
+ "@unicef-polymer/etools-dialog": "^6.0.4",
32
+ "@unicef-polymer/etools-dropdown": "^3.9.7",
33
+ "@unicef-polymer/etools-upload": "^4.4.1",
34
34
  "@webcomponents/webcomponentsjs": "^2.6.0",
35
35
  "lit-element": "^2.5.1",
36
36
  "lit-translate": "^1.2.1",
@@ -41,16 +41,16 @@
41
41
  "@typescript-eslint/eslint-plugin": "^3.10.1",
42
42
  "@typescript-eslint/parser": "^3.10.1",
43
43
  "acorn": "^8.0.4",
44
- "ansi-regex": ">=5.0.1",
45
44
  "eslint": "^7.14.0",
46
45
  "eslint-config-prettier": "^6.15.0",
47
46
  "eslint-plugin-html": "^6.1.1",
48
47
  "eslint-plugin-lit": "^1.2.4",
49
48
  "eslint-plugin-prettier": "^3.1.3",
50
- "glob-parent": ">=5.1.2",
51
- "lodash": ">=4.17.21",
52
49
  "minimist": ">=0.2.1",
53
50
  "prettier": "~2.2.0",
54
- "typescript": "^3.9.10"
51
+ "typescript": "^3.9.7",
52
+ "lodash": ">=4.17.21",
53
+ "ansi-regex": ">=5.0.1",
54
+ "glob-parent": ">=5.1.2"
55
55
  }
56
56
  }