@itfin/components 1.2.15 → 1.2.18

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itfin/components",
3
- "version": "1.2.15",
3
+ "version": "1.2.18",
4
4
  "author": "Vitalii Savchuk <esvit666@gmail.com>",
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
@@ -1,15 +1,17 @@
1
1
  body[data-theme="dark"] {
2
2
  --bs-body-bg: #{$dark-body-bg};
3
3
  --bs-body-color: #{$dark-body-color};
4
- background-color: $dark-body-bg !important;
5
- color: $dark-body-color !important;
4
+ --bs-link-color: #{$dark-link-color};
5
+ --bs-link-hover-color: #{darken($dark-link-color, 10%)};
6
6
 
7
- a {
8
- color: $dark-link-color;
9
-
10
- &:hover, &:active, &:focus {
11
- color: darken($dark-link-color, 10%);
12
- }
7
+ .color-project-tnm {
8
+ color: lighten($project-tnm, 50%);
9
+ }
10
+ .color-project-fixed {
11
+ color: $project-fixed;
12
+ }
13
+ .color-project-nonprofit {
14
+ color: $project-nonprofit;
13
15
  }
14
16
 
15
17
  .form-control {
@@ -46,4 +48,10 @@ body[data-theme="dark"] {
46
48
  .modal-backdrop {
47
49
  background-color: #000;
48
50
  }
51
+
52
+ .dropdown-menu {
53
+ --bs-dropdown-link-color: #{$dark-link-color};
54
+ --bs-dropdown-link-hover-color: #1e2125;
55
+ --bs-dropdown-link-hover-bg: #{$dark-link-color};
56
+ }
49
57
  }
@@ -140,7 +140,7 @@ class itfApp extends Vue {
140
140
  try {
141
141
  await func();
142
142
  } catch (err) {
143
- this.showError('Sorry, something went wrong. Please try again or contact support. Include a screenshot of this entire page so we can troubleshoot this issue faster.');
143
+ this.showError(this.$t('components.sorrySomethingWentWrongPleaseTryAgainOrContactSupport'));
144
144
  if (errFunc) {
145
145
  errFunc(err);
146
146
  }
@@ -4,7 +4,7 @@
4
4
 
5
5
  <div class="air-datepicker -inline-" v-if="!onlyCalendar">
6
6
  <nav class="air-datepicker-nav align-items-center">
7
- <div class="air-datepicker-title">Relative dates</div>
7
+ <div class="air-datepicker-title">{{$t('components.relativeDates')}}</div>
8
8
  </nav>
9
9
 
10
10
  <div class="d-grid gap-1 p-2">
@@ -64,6 +64,7 @@ import { Vue, Component, Prop } from 'vue-property-decorator';
64
64
  import { DateTime } from 'luxon';
65
65
  import AirDatepicker from 'air-datepicker';
66
66
  import localeEn from 'air-datepicker/locale/en';
67
+ import localeUk from 'air-datepicker/locale/uk';
67
68
  import ITFSettings from '../../ITFSettings';
68
69
 
69
70
  export default @Component({
@@ -81,14 +82,16 @@ class itfDatePickerInline extends Vue {
81
82
  @Prop({ type: [String, Date], default: '' }) minDate;
82
83
  @Prop({
83
84
  type: Array,
84
- default: () => ([
85
- { title: 'Today', date: {} },
86
- { title: 'Tomorrow', date: { days: 1 } },
87
- { title: 'In a week', date: { week: 1 } },
88
- { title: 'In a month', date: { month: 1 } },
89
- { title: 'In a half-year', date: { month: 6 } },
90
- { title: 'In a year', date: { year: 1 } },
91
- ])
85
+ default: function () {
86
+ return [
87
+ { title: this.$t('components.today'), date: {} },
88
+ { title: this.$t('components.tomorrow'), date: { days: 1 } },
89
+ { title: this.$t('components.inAWeek'), date: { week: 1 } },
90
+ { title: this.$t('components.inAMonth'), date: { month: 1 } },
91
+ { title: this.$t('components.inAHalfYear'), date: { month: 6 } },
92
+ { title: this.$t('components.inAYear'), date: { year: 1 } },
93
+ ];
94
+ }
92
95
  }) daysList;
93
96
 
94
97
  calendar = null;
@@ -107,7 +110,7 @@ class itfDatePickerInline extends Vue {
107
110
  }
108
111
 
109
112
  this.calendar = new AirDatepicker(this.$refs.calendar, {
110
- locale: localeEn,
113
+ locale: this.$i18n.locale === 'en' ? localeEn : localeUk,
111
114
  firstDay: 1,
112
115
  range: this.range,
113
116
  view: (this.valueAsLuxon && !this.minView) ? 'days' : this.startView,
@@ -4,7 +4,7 @@
4
4
 
5
5
  <div class="air-datepicker -inline-" v-if="!onlyCalendar">
6
6
  <nav class="air-datepicker-nav align-items-center">
7
- <div class="air-datepicker-title">Relative periods</div>
7
+ <div class="air-datepicker-title">{{$t('components.relativeDates')}}</div>
8
8
  </nav>
9
9
 
10
10
  <div class="d-grid gap-1 p-2">
@@ -60,6 +60,7 @@ import { Vue, Component, Prop } from 'vue-property-decorator';
60
60
  import { DateTime } from 'luxon';
61
61
  import AirDatepicker from 'air-datepicker/air-datepicker.js';
62
62
  import localeEn from 'air-datepicker/locale/en';
63
+ import localeUk from 'air-datepicker/locale/uk';
63
64
  import ITFSettings from '../../ITFSettings';
64
65
 
65
66
  export default @Component({
@@ -73,17 +74,18 @@ class itfDatePickerInline extends Vue {
73
74
  @Prop({ type: Object, default: () => ({}) }) customDays;
74
75
  @Prop({
75
76
  type: Array,
76
- default: () => ([
77
- // { title: 'Today', date: () => [DateTime.local(), DateTime.local()] },
78
- { title: 'This week', date: () => [DateTime.local().startOf('week'), DateTime.local().endOf('week')] },
79
- { title: 'Last week', date: () => [DateTime.local().minus({ week: 1 }).startOf('week'), DateTime.local().minus({ week: 1 }).endOf('week')] },
80
- { title: 'This month', date: () => [DateTime.local().startOf('month'), DateTime.local().endOf('month')] },
81
- { title: 'Last month', date: () => [DateTime.local().minus({ months: 1 }).startOf('month'), DateTime.local().minus({ months: 1 }).endOf('month')] },
82
- { title: 'This quarter', date: () => [DateTime.local().startOf('quarter'), DateTime.local().endOf('quarter')] },
83
- { title: 'Last quarter', date: () => [DateTime.local().minus({ quarter: 1 }).startOf('quarter'), DateTime.local().minus({ quarter: 1 }).endOf('quarter')] },
84
- { title: 'This year', date: () => [DateTime.local().startOf('year'), DateTime.local().endOf('year')] },
85
- { title: 'Last year', date: () => [DateTime.local().minus({ year: 1 }).startOf('year'), DateTime.local().minus({ year: 1 }).endOf('year')] },
86
- ])
77
+ default: function () {
78
+ return [// { title: 'Today', date: () => [DateTime.local(), DateTime.local()] },
79
+ { title: this.$t('components.thisWeek'), date: () => [DateTime.local().startOf('week'), DateTime.local().endOf('week')] },
80
+ { title: this.$t('components.lastWeek'), date: () => [DateTime.local().minus({ week: 1 }).startOf('week'), DateTime.local().minus({ week: 1 }).endOf('week')] },
81
+ { title: this.$t('components.thisMonth'), date: () => [DateTime.local().startOf('month'), DateTime.local().endOf('month')] },
82
+ { title: this.$t('components.lastMonth'), date: () => [DateTime.local().minus({ months: 1 }).startOf('month'), DateTime.local().minus({ months: 1 }).endOf('month')] },
83
+ { title: this.$t('components.thisQuarter'), date: () => [DateTime.local().startOf('quarter'), DateTime.local().endOf('quarter')] },
84
+ { title: this.$t('components.lastQuarter'), date: () => [DateTime.local().minus({ quarter: 1 }).startOf('quarter'), DateTime.local().minus({ quarter: 1 }).endOf('quarter')] },
85
+ { title: this.$t('components.thisYear'), date: () => [DateTime.local().startOf('year'), DateTime.local().endOf('year')] },
86
+ { title: this.$t('components.lastYear'), date: () => [DateTime.local().minus({ year: 1 }).startOf('year'), DateTime.local().minus({ year: 1 }).endOf('year')] },
87
+ ];
88
+ }
87
89
  }) daysList;
88
90
 
89
91
  calendar = null;
@@ -103,7 +105,7 @@ class itfDatePickerInline extends Vue {
103
105
 
104
106
  this.calendar = new AirDatepicker(this.$refs.calendar, {
105
107
  firstDay: 1,
106
- locale: localeEn,
108
+ locale: this.$i18n.locale === 'en' ? localeEn : localeUk,
107
109
  range: true,
108
110
  toggleSelected: false,
109
111
  selectedDates: this.valueAsLuxon
@@ -9,7 +9,7 @@
9
9
  ref="input"
10
10
  readonly
11
11
  :disabled="disabled"
12
- class="form-control"
12
+ class="form-control text-capitalize"
13
13
  :class="{ 'is-invalid': isInvalid(), 'is-valid': isSuccess() }"
14
14
  @focus="onFocus"
15
15
  @blur="onBlur"
@@ -85,7 +85,7 @@ class itfMonthPicker extends Vue {
85
85
  @Prop({ type: String }) value;
86
86
  @Prop({ type: Boolean }) disabled;
87
87
  @Prop({ type: String, default: 'ISO' }) valueFormat;
88
- @Prop({ type: String, default: 'MMMM, yyyy' }) displayFormat;
88
+ @Prop({ type: String, default: 'LLLL, yyyy' }) displayFormat;
89
89
  @Prop({ type: String, default: '' }) placeholder;
90
90
  @Prop({ type: String, default: '' }) prependIcon;
91
91
  @Prop({ type: String, default: 'bottom-start' }) placement;
@@ -201,17 +201,19 @@ class itfPeriodPicker extends Vue {
201
201
 
202
202
  year = DateTime.local().year;
203
203
 
204
- quarters = [
205
- { Name: 'Quarter 1', Months: [1, 2, 3], Number: 1 },
206
- { Name: 'Quarter 2', Months: [4, 5, 6], Number: 2 },
207
- { Name: 'Quarter 3', Months: [7, 8, 9], Number: 3 },
208
- { Name: 'Quarter 4', Months: [10, 11, 12], Number: 4 },
209
- ];
210
-
211
204
  focused = false;
212
205
 
213
206
  tooltip = null;
214
207
 
208
+ get quarters() {
209
+ return [
210
+ { Name: `${this.$t('quarter')} 1`, Months: [1, 2, 3], Number: 1 },
211
+ { Name: `${this.$t('quarter')} 2`, Months: [4, 5, 6], Number: 2 },
212
+ { Name: `${this.$t('quarter')} 3`, Months: [7, 8, 9], Number: 3 },
213
+ { Name: `${this.$t('quarter')} 4`, Months: [10, 11, 12], Number: 4 },
214
+ ];
215
+ }
216
+
215
217
  get nextYear() {
216
218
  return this.year + 1;
217
219
  }
@@ -97,8 +97,7 @@ class itfForm extends Vue {
97
97
  // @todo remove validate when migrate from vuetify
98
98
  const isValid = !invalidComponents.length;
99
99
  if (showError && !isValid && this.$showError) {
100
- console.debug('Invalid', invalidComponents);
101
- this.$showError('Please fix the errors below to proceed.', { duration: 3000 });
100
+ this.$showError(this.$t('components.pleaseFixTheErrorsBelowToProceed'), { duration: 3000 });
102
101
  }
103
102
  return isValid;
104
103
  }
@@ -6,7 +6,7 @@
6
6
 
7
7
  <div class="modal-body p-4 text-center">
8
8
  <slot>
9
- <h5 class="mb-0" v-if="title" v-html="title"></h5>
9
+ <div class="mb-0" v-if="title" v-html="title"></div>
10
10
  <p class="mb-0" v-if="message" v-html="message"></p>
11
11
  </slot>
12
12
  </div>
@@ -37,13 +37,13 @@ export default @Component({
37
37
  })
38
38
  class itfConfirmPopover extends Vue {
39
39
  @PropSync('visible') value;
40
- @Prop({ type: String, default: 'Are you sure<br/> to delete this?' }) title;
40
+ @Prop({ type: String, default: function() { this.$t('areYouSureToDeleteThis'); } }) title;
41
41
  @Prop({ type: String, default: '' }) message;
42
42
  @Prop({ type: String, default: 'bottom', validator: (value) => ['bottom', 'left', 'right', 'top'].includes(value) }) placement;
43
43
  @Prop({ type: String, default: 'click', validator: (value) => ['click', 'focus', 'hover', 'manual'].includes(value) }) trigger;
44
44
 
45
- @Prop({ type: String, default: 'No,&nbsp;keep it' }) cancelCaption;
46
- @Prop({ type: String, default: 'Yes,&nbsp;delete' }) confirmCaption;
45
+ @Prop({ type: String, default: function() { this.$t('noKeepIt'); } }) cancelCaption;
46
+ @Prop({ type: String, default: function() { this.$t('yesDelete'); } }) confirmCaption;
47
47
  @Prop({ type: String, default: '' }) cancelClass;
48
48
  @Prop({ type: String, default: 'text-danger' }) confirmClass;
49
49
 
@@ -69,13 +69,15 @@ class itfPopover extends Vue {
69
69
 
70
70
  modalEl = null;
71
71
 
72
+ ignoreUpdate = false; // потрібно щоб не оновлювалось visible декілька разів, бо буде баг коли вікно відкривається і одразу закривається
73
+
72
74
  beforeDestroy() {
73
75
  this.hide();
74
76
  }
75
77
 
76
78
  @Watch('value')
77
- onVisibleChanged(newValue) {
78
- if (!this.modalEl) {
79
+ onVisibleChanged(newValue, oldValue) {
80
+ if (!this.modalEl || this.ignoreUpdate) {
79
81
  return;
80
82
  }
81
83
  if (newValue) {
@@ -109,13 +111,16 @@ class itfPopover extends Vue {
109
111
  });
110
112
  this.onVisibleChanged(this.value);
111
113
  this.$el.addEventListener('shown.bs.popover', () => {
114
+ this.ignoreUpdate = true;
115
+ this.value = true;
112
116
  document.body.addEventListener('click', this.clickOutside);
113
- this.$emit('update:visible', true);
117
+ this.$nextTick(() => this.ignoreUpdate = false);
114
118
  });
115
119
  this.$el.addEventListener('hidden.bs.popover', () => {
120
+ this.ignoreUpdate = true;
116
121
  this.value = false;
117
122
  document.body.removeEventListener('click', this.clickOutside);
118
- this.$emit('update:visible', false);
123
+ this.$nextTick(() => this.ignoreUpdate = false);
119
124
  });
120
125
  }
121
126
 
@@ -5,7 +5,7 @@
5
5
  class="dropdownInput"
6
6
  type="text"
7
7
  ref="inputRef"
8
- placeholder="Search"
8
+ :placeholder="$t('components.search')"
9
9
  @input="handleSearchValueChange"
10
10
  @keydown="handleInputKeyDown"
11
11
  />
@@ -33,14 +33,13 @@
33
33
  {{
34
34
  isCreatingOption
35
35
  ? `Creating "${searchValue}"...`
36
- : `Create
37
- "${searchValue}"`
36
+ : `Create "${searchValue}"`
38
37
  }}
39
38
  </div>
40
39
  </div>
41
40
 
42
41
  <div v-if="filteredOptions.length === 0" class="optionsNoResults">
43
- No results
42
+ {{$t('components.noResults')}}
44
43
  </div>
45
44
  </div>
46
45
  </template>
@@ -15,126 +15,126 @@ const HEX_REGEXP = /[0-9A-Fa-f]{6}/;
15
15
 
16
16
  export const MEDIUM_TEXT_LENGTH = 16777215;
17
17
 
18
- export function differentValidation (value, message = 'The value must be different') {
19
- return v => !v || !(v === value) || message;
18
+ export function differentValidation (value, message) {
19
+ return (v, $t) => !v || !(v === value) || (message || $t('components.theValueMustBeDifferent'));
20
20
  }
21
21
 
22
- export function lengthValidation (length, message = `Must be less than ${length} characters.`) {
23
- return v => !v || ((v || '').toString().trim().length <= length) || message;
22
+ export function lengthValidation (length, message) {
23
+ return (v, $t) => !v || ((v || '').toString().trim().length <= length) || (message || $t('components.mustBeLessThanLengthCharacters', {length}));
24
24
  }
25
25
 
26
- export function minLengthValidation (length, message = `Must be more than ${length} characters.`) {
27
- return v => !v || ((v || '').toString().trim().length >= length) || message;
26
+ export function minLengthValidation (length, message) {
27
+ return (v, $t) => !v || ((v || '').toString().trim().length >= length) || (message || $t('components.mustBeMoreThanLengthCharacters', {length}));
28
28
  }
29
29
 
30
- export function emailValidation (message = 'Please enter a valid email.') {
31
- return v => !v || !!v.toString().match(EMAIL_REGEXP) || message;
30
+ export function emailValidation (message) {
31
+ return (v, $t) => !v || !!v.toString().match(EMAIL_REGEXP) || (message || $t('components.pleaseEnterAValidEmail'));
32
32
  }
33
33
 
34
- export function emailListValidation (message = 'Please enter valid, comma separated (,) email addresses to send invoicing') {
35
- return v => !v || !!v.toString().match(EMAIL_LIST_REGEXP) || message;
34
+ export function emailListValidation (message) {
35
+ return (v, $t) => !v || !!v.toString().match(EMAIL_LIST_REGEXP) || (message || $t('components.pleaseEnterValidCommaSeparatedEmailAddressesToSendInvoicing'));
36
36
  }
37
37
 
38
- export function urlValidation (message = 'Please enter valid URL.') {
39
- return v => !v || !!v.toString().match(URL_REGEXP) || message;
38
+ export function urlValidation (message) {
39
+ return (v, $t) => !v || !!v.toString().match(URL_REGEXP) || (message || $t('components.pleaseEnterValidURL'));
40
40
  }
41
41
 
42
- export function hexValidation (message = 'Please enter a valid Hex.') {
43
- return v => !v || !!v.toString().match(HEX_REGEXP) || message;
42
+ export function hexValidation (message) {
43
+ return (v, $t) => !v || !!v.toString().match(HEX_REGEXP) || (message || $t('components.pleaseEnteraValidHex'));
44
44
  }
45
45
 
46
- export function passMatchValidation (password, message = 'Passwords don\'t match.') {
47
- return v => !v || !!v.toString().match(`^${password}$`) || message;
46
+ export function passMatchValidation (password, message) {
47
+ return (v, $t) => !v || !!v.toString().match(`^${password}$`) || (message || $t('components.passwordsDontMatch'));
48
48
  }
49
49
 
50
- export function emptyValidation (message = 'This field is required.') {
51
- return v => (v !== '' && typeof v !== 'undefined' && v !== null) || message;
50
+ export function emptyValidation (message) {
51
+ return (v, $t) => (v !== '' && typeof v !== 'undefined' && v !== null) || (message || $t('components.thisFieldIsRequired'));
52
52
  }
53
53
 
54
- export function emptyArrayValidation (message = 'This field is required.') {
55
- return v => (Array.isArray(v) && v.length > 0) || message;
54
+ export function emptyArrayValidation (message) {
55
+ return (v, $t) => (Array.isArray(v) && v.length > 0) || (message || $t('components.thisFieldIsRequired'));
56
56
  }
57
57
 
58
- export function doubleValidation (message = 'This field must be a number (format 0.00).') {
59
- return v => !v || !!(v + '').match(DOUBLE_REGEXP) || message;
58
+ export function doubleValidation (message) {
59
+ return (v, $t) => !v || !!(v + '').match(DOUBLE_REGEXP) || (message || $t('components.thisFieldMustBeANumberFormatZero'));
60
60
  }
61
61
 
62
- export function minMaxValidation (min = 0, max = 100, message = `The value must be greater than or equal to ${min} and lower or equal than ${max}.`) {
63
- return v => !v || (v >= min && v <= max) || message;
62
+ export function minMaxValidation (min = 0, max = 100, message) {
63
+ return (v, $t) => !v || (v >= min && v <= max) || (message || $t('components.theValueMustBeGreaterThanOrEqualToMinAndMax', {min, max}));
64
64
  }
65
65
 
66
- export function minValidation (min = 0, message = `The value must be greater than or equal to ${min}.`) {
67
- return v => !v || (v >= min) || message;
66
+ export function minValidation (min = 0, message) {
67
+ return (v, $t) => !v || (v >= min) || (message || $t('components.theValueMustBeGreaterThanOrEqualToMin', {min}));
68
68
  }
69
69
 
70
- export function maxValidation (max, message = `Must be less than ${max}.`) {
71
- return v => (v <= max) || message;
70
+ export function maxValidation (max, message) {
71
+ return (v, $t) => (v <= max) || (message || $t('components.mustBeLessThanMax'));
72
72
  }
73
73
 
74
- export function preventStuffingValidation (message = 'This isn\'t a valid description.') {
75
- return v => !v || (v.replace(/(.{4,}?)(?:\1{3,})/g, (text, subtext) => /^(\s*(<(\/?[^>]+)>|&nbsp;|[^\s]{0,3})\s*|(.)\4+)$/.test(subtext) ? text : '') === v) || message;
74
+ export function preventStuffingValidation (message) {
75
+ return (v, $t) => !v || (v.replace(/(.{4,}?)(?:\1{3,})/g, (text, subtext) => /^(\s*(<(\/?[^>]+)>|&nbsp;|[^\s]{0,3})\s*|(.)\4+)$/.test(subtext) ? text : '') === v) || (message || $t('components.thisIsntABalidDescription'));
76
76
  }
77
77
 
78
- export function preventUrlsValidation (message = 'Links are not allowed in this field.') {
79
- return v => !v || !v.match(LINK_URL_REGEXP) || message;
78
+ export function preventUrlsValidation (message) {
79
+ return (v, $t) => !v || !v.match(LINK_URL_REGEXP) || (message || $t('components.linksAreNotAllowedInThisField'));
80
80
  }
81
81
 
82
- export function financeAccountCodeValidation (message = 'The value must begin and end with a number and contain only numbers or dots(.)') {
83
- return v => !v || v.match(/^\d+(\.\d+)*$/g) || message;
82
+ export function financeAccountCodeValidation (message) {
83
+ return (v, $t) => !v || v.match(/^\d+(\.\d+)*$/g) || (message || $t('components.theValueMustBeginAndEndWithANumberAndContainOnlyNumbersOrDots'));
84
84
  }
85
85
 
86
- export function preventHtmlValidation (message = 'Please don\'t use HTML markup') {
87
- return v => !v || !v.match(HTML_MARKUP_REGEXP) || message;
86
+ export function preventHtmlValidation (message) {
87
+ return (v, $t) => !v || !v.match(HTML_MARKUP_REGEXP) || (message || $t('components.pleaseDontUseHTMLMarkup'));
88
88
  }
89
89
 
90
- export function preventLinkedinValidation (message = 'Before you continue, make sure your profile does not include your LinkedIn contact information.') {
91
- return v => !v || !v.match(LINKED_IN_REGEXP) || message;
90
+ export function preventLinkedinValidation (message) {
91
+ return (v, $t) => !v || !v.match(LINKED_IN_REGEXP) || (message || $t('components.beforeYouContinueMakeSureYourProfileDoesNotIncludeYourLinkedInContactInformation'));
92
92
  }
93
93
 
94
- export function preventCapitalsValidation (message = 'Too many capital letters.') {
95
- return v => !v || !(v.replace(/[A-Z]/g, '').length < v.length / 2) || message;
94
+ export function preventCapitalsValidation (message) {
95
+ return (v, $t) => !v || !(v.replace(/[A-Z]/g, '').length < v.length / 2) || (message || $t('components.tooManyCapitalLetters'));
96
96
  }
97
97
 
98
- export function preventSpecialCharsValidation (message = 'Your title cannot include special characters like >, ;, !, @, $, %, ^, =, {, }.') {
99
- return v => !v || !!v.match(SPECIAL_CHARS_REGEXP) || message;
98
+ export function preventSpecialCharsValidation (message) {
99
+ return (v, $t) => !v || !!v.match(SPECIAL_CHARS_REGEXP) || (message || $t('components.yourtitleCannotIncludeSpecialCharactersLike'));
100
100
  }
101
101
 
102
- export function preventGreetingsValidation (message = 'Your title should describe the work you do.') {
103
- return v => !v || !v.match(GREETINGS_REGEXP) || message;
102
+ export function preventGreetingsValidation (message) {
103
+ return (v, $t) => !v || !v.match(GREETINGS_REGEXP) || (message || $t('components.yourTitleShouldDescribeTheWorkYouDo'));
104
104
  }
105
105
 
106
- export function preventPhoneValidation (message = 'Please remove any phone number from this field. Potential clients will be able to contact you through Upwork.') {
107
- return v => !v || !v.match(PHONE_REGEXP) || message;
106
+ export function preventPhoneValidation (message) {
107
+ return (v, $t) => !v || !v.match(PHONE_REGEXP) || (message || $t('components.pleaseRemoveAnyPhoneNumberFromThisField'));
108
108
  }
109
109
 
110
- export function allowDigitsOnlyValidation (message = 'This field must contains digits.') {
111
- return v => !v || !!v.match(/^\d+$/) || message;
110
+ export function allowDigitsOnlyValidation (message) {
111
+ return (v, $t) => !v || !!v.match(/^\d+$/) || (message || $t('components.thisFieldMustContainsDigits'));
112
112
  }
113
113
 
114
114
  // export function dateBeforeValidation (dateCompare, message = `The date should be before ${moment(dateCompare).format('MM/DD/YYYY')}`) {
115
- // return v => !v || moment(v).isBefore(dateCompare, 'd') || message;
115
+ // return (v, $t) => !v || moment(v).isBefore(dateCompare, 'd') || (message || $t('components.'));
116
116
  // }
117
117
 
118
- export function dateSameOrBeforeValidationLuxon (dateCompare, message = `The date should be same or before ${DateTime.fromISO(dateCompare).toFormat('dd-MM-yyyy')}`) {
119
- return v => !v || DateTime.fromISO(v) <= DateTime.fromISO(dateCompare) || message;
118
+ export function dateSameOrBeforeValidationLuxon (dateCompare, message) {
119
+ return (v, $t) => !v || DateTime.fromISO(v) <= DateTime.fromISO(dateCompare) || (message || $t('components.thedateShouldBeSameOrBefore', {date: DateTime.fromISO(dateCompare).toFormat('dd-MM-yyyy')}));
120
120
  }
121
121
 
122
122
  // export function dateAfterValidation (dateCompare, message = `The date should be after ${moment(dateCompare).format('MM/DD/YYYY')}`) {
123
- // return v => !v || moment(v).isAfter(dateCompare, 'd') || message;
123
+ // return (v, $t) => !v || moment(v).isAfter(dateCompare, 'd') || (message || $t('components.'));
124
124
  // }
125
125
  //
126
126
  // export function dateSameOrAfterValidation (dateCompare, message = `The date should be after ${moment(dateCompare).format('MM/DD/YYYY')}`) {
127
- // return v => !v || moment(v).isSameOrAfter(dateCompare, 'd') || message;
127
+ // return (v, $t) => !v || moment(v).isSameOrAfter(dateCompare, 'd') || (message || $t('components.'));
128
128
  // }
129
129
  //
130
130
  // export function dateSameOrBeforeValidation (dateCompare, message = `The date should be same or before ${moment(dateCompare).format('MM/DD/YYYY')}`) {
131
- // return v => !v || moment(v).isSameOrBefore(dateCompare, 'd') || message;
131
+ // return (v, $t) => !v || moment(v).isSameOrBefore(dateCompare, 'd') || (message || $t('components.'));
132
132
  // }
133
133
 
134
- export function dateAfterValidationLuxon (dateCompare, message = `The date should be after ${DateTime.fromISO(dateCompare).toFormat('yyyy-MM-dd')}`) {
135
- return v => !v || DateTime.fromISO(v) > DateTime.fromISO(dateCompare) || message;
134
+ export function dateAfterValidationLuxon (dateCompare, message) {
135
+ return (v, $t) => !v || DateTime.fromISO(v) > DateTime.fromISO(dateCompare) || (message || $t('components.thedateShouldBeSameOrAfter', {date: DateTime.fromISO(dateCompare).toFormat('yyyy-MM-dd')}));
136
136
  }
137
137
 
138
- export function hoursValidation (message = 'Invalid time value. Should be in format 0d 0h 0m') {
139
- return v => !v || parseHours(v) !== false || message;
138
+ export function hoursValidation (message) {
139
+ return (v, $t) => !v || parseHours(v) !== false || (message || $t('components.invalidTimeValueShouldBeInFormat'));
140
140
  }
@@ -77,7 +77,7 @@ class ValidatableMixin extends Vue {
77
77
 
78
78
  for (let index = 0; index < this.rules.length; index++) {
79
79
  const rule = this.rules[index];
80
- const valid = typeof rule === 'function' ? rule(value) : rule;
80
+ const valid = typeof rule === 'function' ? rule(value, this.$t.bind(this)) : rule;
81
81
 
82
82
  if (typeof valid === 'string') {
83
83
  errorBucket.push(valid);