@bagelink/vue 1.9.51 → 1.9.56
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/dist/components/AddressSearch.vue.d.ts.map +1 -1
- package/dist/components/Btn.vue.d.ts +2 -2
- package/dist/components/Btn.vue.d.ts.map +1 -1
- package/dist/components/Filter.vue.d.ts +0 -1
- package/dist/components/Filter.vue.d.ts.map +1 -1
- package/dist/components/ImportData.vue.d.ts.map +1 -1
- package/dist/components/ModalConfirm.vue.d.ts.map +1 -1
- package/dist/components/Spreadsheet/Index.vue.d.ts.map +1 -1
- package/dist/components/form/FieldArray.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/ColorInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/DateInput.vue.d.ts +1 -1
- package/dist/components/form/inputs/DateInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/DatePicker.vue.d.ts +1 -1
- package/dist/components/form/inputs/DatePicker.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/EmailInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/PasswordInput.vue.d.ts +1 -1
- package/dist/components/form/inputs/PasswordInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RadioPillsInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/SelectInput.vue.d.ts +0 -1
- package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/TelInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/Upload/UploadInput.vue.d.ts.map +1 -1
- package/dist/components/lightbox/Lightbox.vue.d.ts.map +1 -1
- package/dist/dialog/DialogConfirm.vue.d.ts +0 -3
- package/dist/dialog/DialogConfirm.vue.d.ts.map +1 -1
- package/dist/dialog/DialogForm.vue.d.ts.map +1 -1
- package/dist/form-flow/FormFlow.vue.d.ts.map +1 -1
- package/dist/form-flow/MultiStepForm.vue.d.ts.map +1 -1
- package/dist/i18n/index.d.ts +995 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/index.cjs +135 -130
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +15388 -11464
- package/dist/plugins/bagel.d.ts +5 -7
- package/dist/plugins/bagel.d.ts.map +1 -1
- package/dist/style.css +1 -1
- package/dist/utils/calendar/dateUtils.d.ts +6 -5
- package/dist/utils/calendar/dateUtils.d.ts.map +1 -1
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/lang.d.ts +6 -7
- package/dist/utils/lang.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/components/AddressSearch.vue +5 -2
- package/src/components/Btn.vue +8 -6
- package/src/components/Filter.vue +37 -76
- package/src/components/ImportData.vue +35 -29
- package/src/components/ModalConfirm.vue +9 -7
- package/src/components/Spreadsheet/Index.vue +35 -60
- package/src/components/calendar/views/AgendaView.vue +1 -1
- package/src/components/calendar/views/DayView.vue +3 -3
- package/src/components/calendar/views/MonthView.vue +1 -1
- package/src/components/calendar/views/WeekView.vue +6 -6
- package/src/components/form/FieldArray.vue +4 -2
- package/src/components/form/inputs/ColorInput.vue +18 -12
- package/src/components/form/inputs/DateInput.vue +8 -5
- package/src/components/form/inputs/EmailInput.vue +9 -7
- package/src/components/form/inputs/PasswordInput.vue +17 -15
- package/src/components/form/inputs/RadioPillsInput.vue +5 -3
- package/src/components/form/inputs/SelectInput.vue +13 -11
- package/src/components/form/inputs/TelInput.vue +11 -9
- package/src/components/form/inputs/Upload/UploadInput.vue +7 -5
- package/src/components/lightbox/Lightbox.vue +4 -1
- package/src/dialog/DialogConfirm.vue +11 -6
- package/src/dialog/DialogForm.vue +9 -9
- package/src/form-flow/FormFlow.vue +7 -15
- package/src/form-flow/MultiStepForm.vue +16 -12
- package/src/i18n/index.ts +136 -0
- package/src/i18n/locales/en.json +153 -0
- package/src/i18n/locales/es.json +153 -0
- package/src/i18n/locales/fr.json +153 -0
- package/src/i18n/locales/he.json +174 -0
- package/src/i18n/locales/it.json +153 -0
- package/src/i18n/locales/ru.json +153 -0
- package/src/index.ts +11 -5
- package/src/plugins/bagel.ts +14 -26
- package/src/styles/text.css +2 -1
- package/src/utils/calendar/dateUtils.ts +108 -63
- package/src/utils/index.ts +0 -2
- package/src/utils/lang.ts +0 -46
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
{
|
|
2
|
+
"modalConfirm": {
|
|
3
|
+
"title": "Подтвердить",
|
|
4
|
+
"message": "Вы уверены, что хотите продолжить?",
|
|
5
|
+
"confirm": "Подтвердить",
|
|
6
|
+
"cancel": "Отмена"
|
|
7
|
+
},
|
|
8
|
+
"upload": {
|
|
9
|
+
"upload": "Загрузить",
|
|
10
|
+
"uploading": "Загрузка {count} файл{plural}...",
|
|
11
|
+
"noFile": "Файл не выбран",
|
|
12
|
+
"dropPlaceholder": "Перетащите файлы сюда или нажмите для загрузки",
|
|
13
|
+
"delete": "Удалить",
|
|
14
|
+
"replace": "Заменить",
|
|
15
|
+
"download": "Скачать"
|
|
16
|
+
},
|
|
17
|
+
"pagination": {
|
|
18
|
+
"of": "из",
|
|
19
|
+
"prev": "Предыдущая",
|
|
20
|
+
"next": "Следующая"
|
|
21
|
+
},
|
|
22
|
+
"form": {
|
|
23
|
+
"required": "Это поле обязательно для заполнения",
|
|
24
|
+
"invalidEmail": "Введите действительный адрес электронной почты",
|
|
25
|
+
"invalidUrl": "Введите действительный URL",
|
|
26
|
+
"minLength": "Должно содержать не менее {min} символов",
|
|
27
|
+
"maxLength": "Должно содержать не более {max} символов",
|
|
28
|
+
"minValue": "Должно быть не менее {min}",
|
|
29
|
+
"maxValue": "Должно быть не более {max}",
|
|
30
|
+
"pattern": "Неверный формат",
|
|
31
|
+
"passwordStrength": "Надежность пароля"
|
|
32
|
+
},
|
|
33
|
+
"password": {
|
|
34
|
+
"veryWeak": "Очень слабый",
|
|
35
|
+
"weak": "Слабый",
|
|
36
|
+
"fair": "Средний",
|
|
37
|
+
"good": "Хороший",
|
|
38
|
+
"strong": "Надёжный"
|
|
39
|
+
},
|
|
40
|
+
"select": {
|
|
41
|
+
"placeholder": "Выбрать",
|
|
42
|
+
"search": "Поиск",
|
|
43
|
+
"yes": "Да",
|
|
44
|
+
"no": "Нет"
|
|
45
|
+
},
|
|
46
|
+
"fieldArray": {
|
|
47
|
+
"loadDefault": "Загрузить {label} по умолчанию"
|
|
48
|
+
},
|
|
49
|
+
"btn": {
|
|
50
|
+
"loading": "Загрузка..."
|
|
51
|
+
},
|
|
52
|
+
"toast": {
|
|
53
|
+
"success": "Успешно",
|
|
54
|
+
"error": "Ошибка",
|
|
55
|
+
"warning": "Предупреждение",
|
|
56
|
+
"info": "Информация"
|
|
57
|
+
},
|
|
58
|
+
"filter": {
|
|
59
|
+
"filter": "Фильтр",
|
|
60
|
+
"noActiveFilters": "Нет активных фильтров",
|
|
61
|
+
"connectors": {
|
|
62
|
+
"and": "И",
|
|
63
|
+
"or": "Или"
|
|
64
|
+
},
|
|
65
|
+
"operators": {
|
|
66
|
+
"eq": "Равно",
|
|
67
|
+
"ne": "Не равно",
|
|
68
|
+
"gt": "Больше чем",
|
|
69
|
+
"ge": "Больше или равно",
|
|
70
|
+
"lt": "Меньше чем",
|
|
71
|
+
"le": "Меньше или равно",
|
|
72
|
+
"co": "Содержит",
|
|
73
|
+
"sw": "Начинается с",
|
|
74
|
+
"ew": "Заканчивается на",
|
|
75
|
+
"pr": "Присутствует"
|
|
76
|
+
},
|
|
77
|
+
"placeholders": {
|
|
78
|
+
"selectField": "Выберите поле",
|
|
79
|
+
"selectOption": "Выберите вариант",
|
|
80
|
+
"selectDate": "Выберите дату",
|
|
81
|
+
"enterValue": "Значение"
|
|
82
|
+
},
|
|
83
|
+
"buttons": {
|
|
84
|
+
"addCondition": "Добавить условие",
|
|
85
|
+
"clearAll": "Очистить всё"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"multiStep": {
|
|
89
|
+
"previous": "Назад",
|
|
90
|
+
"next": "Далее",
|
|
91
|
+
"complete": "Завершить",
|
|
92
|
+
"step": "Шаг {current} из {total}"
|
|
93
|
+
},
|
|
94
|
+
"addressSearch": {
|
|
95
|
+
"placeholder": "Введите адрес"
|
|
96
|
+
},
|
|
97
|
+
"importData": {
|
|
98
|
+
"close": "Закрыть",
|
|
99
|
+
"cancel": "Отмена",
|
|
100
|
+
"importData": "Импорт данных",
|
|
101
|
+
"changeFile": "Изменить файл",
|
|
102
|
+
"selectSheet": "Выбрать лист",
|
|
103
|
+
"hasHeaders": "Отметьте, если файл содержит строку заголовка",
|
|
104
|
+
"sourceKeyField": "Ключевое поле источника (из этого файла)",
|
|
105
|
+
"relatedKeyField": "Ключевое поле связанного (из связанного файла)",
|
|
106
|
+
"selectSourceValue": "Выберите исходное значение",
|
|
107
|
+
"sourceValue": "Исходное значение",
|
|
108
|
+
"selectTargetValue": "Выберите целевое значение",
|
|
109
|
+
"targetValue": "Целевое значение",
|
|
110
|
+
"selectColumn": "Выберите столбец..."
|
|
111
|
+
},
|
|
112
|
+
"timeAgo": {
|
|
113
|
+
"year": "год",
|
|
114
|
+
"month": "месяц",
|
|
115
|
+
"week": "неделя",
|
|
116
|
+
"day": "день",
|
|
117
|
+
"hour": "час",
|
|
118
|
+
"minute": "минута",
|
|
119
|
+
"second": "секунда",
|
|
120
|
+
"ago": "назад",
|
|
121
|
+
"in": "через",
|
|
122
|
+
"justNow": "Только что"
|
|
123
|
+
},
|
|
124
|
+
"dialogForm": {
|
|
125
|
+
"save": "Сохранить",
|
|
126
|
+
"cancel": "Отмена",
|
|
127
|
+
"delete": "Удалить",
|
|
128
|
+
"validationError": "Пожалуйста, исправьте ошибки валидации перед отправкой",
|
|
129
|
+
"errorOccurred": "Произошла ошибка"
|
|
130
|
+
},
|
|
131
|
+
"tel": {
|
|
132
|
+
"phoneNumber": "Номер телефона",
|
|
133
|
+
"invalidPhone": "Пожалуйста, введите действительный номер телефона"
|
|
134
|
+
},
|
|
135
|
+
"email": {
|
|
136
|
+
"invalidEmail": "Введите действительный адрес электронной почты",
|
|
137
|
+
"invalidDomain": "Домен этого адреса электронной почты, похоже, недействителен"
|
|
138
|
+
},
|
|
139
|
+
"date": {
|
|
140
|
+
"invalidFormat": "Неверный формат даты"
|
|
141
|
+
},
|
|
142
|
+
"spreadsheet": {
|
|
143
|
+
"wrapText": "Перенос текста",
|
|
144
|
+
"selectAll": "Выбрать всё",
|
|
145
|
+
"clearAll": "Очистить всё"
|
|
146
|
+
},
|
|
147
|
+
"lightbox": {
|
|
148
|
+
"openFile": "Открыть файл"
|
|
149
|
+
},
|
|
150
|
+
"color": {
|
|
151
|
+
"placeholder": "Введите цвет"
|
|
152
|
+
}
|
|
153
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -10,13 +10,19 @@ export * from './directives'
|
|
|
10
10
|
export * from './form-flow/form-flow'
|
|
11
11
|
export { default as FormFlow } from './form-flow/FormFlow.vue'
|
|
12
12
|
export { default as MultiStepForm } from './form-flow/MultiStepForm.vue'
|
|
13
|
+
// i18n exports
|
|
13
14
|
export {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
bagelinkLocales,
|
|
16
|
+
type CreateBagelI18nOptions,
|
|
17
|
+
createI18n,
|
|
18
|
+
type MessageSchema,
|
|
19
|
+
resolveI18n,
|
|
20
|
+
type TranslatableString,
|
|
21
|
+
useI18n,
|
|
22
|
+
} from './i18n'
|
|
23
|
+
export { type BagelOptions, BagelVue, getI18n } from './plugins/bagel'
|
|
19
24
|
export { ModalPlugin, useModal } from './plugins/useModal'
|
|
25
|
+
|
|
20
26
|
export { type BagelToastOptions, type ToastApi, ToastPlugin, useToast } from './plugins/useToast'
|
|
21
27
|
|
|
22
28
|
export * from './types'
|
package/src/plugins/bagel.ts
CHANGED
|
@@ -1,27 +1,18 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import
|
|
3
|
-
import { inject } from 'vue'
|
|
1
|
+
import type { Plugin } from 'vue'
|
|
2
|
+
import type { CreateBagelI18nOptions } from '../i18n'
|
|
4
3
|
|
|
4
|
+
import type { BagelToastOptions } from './useToast'
|
|
5
|
+
import FloatingVue from 'floating-vue'
|
|
5
6
|
import lightboxPlugin from '../components/lightbox/index'
|
|
6
7
|
import { ripple, pattern } from '../directives'
|
|
7
|
-
import {
|
|
8
|
+
import { createI18n, getI18n } from '../i18n'
|
|
8
9
|
import clickOutside from '../utils/clickOutside'
|
|
9
10
|
import { ModalPlugin } from './useModal'
|
|
10
|
-
import { ToastPlugin
|
|
11
|
-
|
|
12
|
-
export const i18nTInjectionKey = Symbol('bagel') as InjectionKey<(key: string) => string>
|
|
13
|
-
|
|
14
|
-
export function injectI18nT(injectionKey: typeof i18nTInjectionKey = i18nTInjectionKey) {
|
|
15
|
-
const i18nT = inject(injectionKey)
|
|
16
|
-
if (!i18nT) { throw new Error('No i18nT provided') }
|
|
17
|
-
return i18nT
|
|
18
|
-
}
|
|
11
|
+
import { ToastPlugin } from './useToast'
|
|
19
12
|
|
|
20
13
|
export interface BagelOptions {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
language?: string
|
|
24
|
-
i18nT?: (key: string) => string
|
|
14
|
+
/** i18n configuration options */
|
|
15
|
+
i18n?: CreateBagelI18nOptions
|
|
25
16
|
toast?: BagelToastOptions
|
|
26
17
|
}
|
|
27
18
|
|
|
@@ -48,14 +39,11 @@ export const BagelVue: Plugin<BagelOptions> = {
|
|
|
48
39
|
},
|
|
49
40
|
})
|
|
50
41
|
|
|
51
|
-
// Setup
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
if (options.defaultLang) { defaultLang.value = options.defaultLang }
|
|
55
|
-
if (options.language) { lang.value = options.language }
|
|
56
|
-
|
|
57
|
-
// Setup i18n translation function
|
|
58
|
-
app.config.globalProperties.$i18T = options.i18nT || ((key?: string) => key)
|
|
59
|
-
app.provide(i18nTInjectionKey, options.i18nT || ((key: string) => key))
|
|
42
|
+
// Setup i18n
|
|
43
|
+
const i18n = createI18n(options.i18n || {})
|
|
44
|
+
app.use(i18n)
|
|
60
45
|
},
|
|
61
46
|
}
|
|
47
|
+
|
|
48
|
+
// Re-export getI18n for advanced usage
|
|
49
|
+
export { getI18n }
|
package/src/styles/text.css
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DateLike } from '@vueuse/core'
|
|
2
|
-
import type {
|
|
2
|
+
import type { DateTimeAcceptedFormats, TimeUnit } from '../../types/timeAgoT'
|
|
3
|
+
import { getI18n } from '../../i18n'
|
|
3
4
|
|
|
4
5
|
interface TimeDeltaOptions {
|
|
5
6
|
Day?: number
|
|
@@ -26,9 +27,7 @@ interface TimeDeltaOptions {
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export function timeDelta(date: string | Date, options: TimeDeltaOptions) {
|
|
29
|
-
console.log('date', date)
|
|
30
30
|
date = new Date(date)
|
|
31
|
-
console.log('date', date)
|
|
32
31
|
const day = options.Day || options.day || options.days || 0
|
|
33
32
|
const hour = options.Hour || options.hour || options.hours || 0
|
|
34
33
|
const minute = options.Minute || options.minute || options.minutes || 0
|
|
@@ -60,66 +59,92 @@ export function timeDelta(date: string | Date, options: TimeDeltaOptions) {
|
|
|
60
59
|
return date
|
|
61
60
|
}
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
62
|
+
type TimeAgoLang = 'en' | 'es' | 'fr' | 'he' | 'it' | 'ru'
|
|
63
|
+
|
|
64
|
+
interface TimeAgoTranslations {
|
|
65
|
+
year: string | TimeUnit
|
|
66
|
+
month: string | TimeUnit
|
|
67
|
+
week: string | TimeUnit
|
|
68
|
+
day: string | TimeUnit
|
|
69
|
+
hour: string | TimeUnit
|
|
70
|
+
minute: string | TimeUnit
|
|
71
|
+
second: string | TimeUnit
|
|
72
|
+
ago: string
|
|
73
|
+
in: string
|
|
74
|
+
justNow: string
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get timeAgo translations from i18n instance
|
|
79
|
+
*/
|
|
80
|
+
function getTimeAgoTranslations(lang: TimeAgoLang): TimeAgoTranslations {
|
|
81
|
+
try {
|
|
82
|
+
const i18n = getI18n()
|
|
83
|
+
const messages = i18n.global.messages as Record<string, { timeAgo?: TimeAgoTranslations }>
|
|
84
|
+
const localeMessages = messages[lang] || messages.en
|
|
85
|
+
if (localeMessages?.timeAgo) {
|
|
86
|
+
return localeMessages.timeAgo
|
|
87
|
+
}
|
|
88
|
+
// Fallback to English if timeAgo not found
|
|
89
|
+
return {
|
|
90
|
+
year: 'year',
|
|
91
|
+
month: 'month',
|
|
92
|
+
week: 'week',
|
|
93
|
+
day: 'day',
|
|
94
|
+
hour: 'hour',
|
|
95
|
+
minute: 'minute',
|
|
96
|
+
second: 'second',
|
|
97
|
+
ago: 'ago',
|
|
98
|
+
in: 'in',
|
|
99
|
+
justNow: 'Just now',
|
|
100
|
+
}
|
|
101
|
+
} catch {
|
|
102
|
+
// Fallback if i18n not initialized
|
|
103
|
+
return {
|
|
104
|
+
year: 'year',
|
|
105
|
+
month: 'month',
|
|
106
|
+
week: 'week',
|
|
107
|
+
day: 'day',
|
|
108
|
+
hour: 'hour',
|
|
109
|
+
minute: 'minute',
|
|
110
|
+
second: 'second',
|
|
111
|
+
ago: 'ago',
|
|
112
|
+
in: 'in',
|
|
113
|
+
justNow: 'Just now',
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get current locale from i18n instance
|
|
120
|
+
*/
|
|
121
|
+
function getCurrentLocale(): TimeAgoLang {
|
|
122
|
+
try {
|
|
123
|
+
const i18n = getI18n()
|
|
124
|
+
const { locale } = i18n.global
|
|
125
|
+
const lang = typeof locale === 'string' ? locale : locale.value
|
|
126
|
+
// Map to supported timeAgo languages
|
|
127
|
+
const supportedLangs: TimeAgoLang[] = ['en', 'es', 'fr', 'he', 'it', 'ru']
|
|
128
|
+
if (supportedLangs.includes(lang as TimeAgoLang)) {
|
|
129
|
+
return lang as TimeAgoLang
|
|
130
|
+
}
|
|
131
|
+
return 'en'
|
|
132
|
+
} catch {
|
|
133
|
+
return 'en'
|
|
111
134
|
}
|
|
112
135
|
}
|
|
113
136
|
|
|
114
137
|
export function timeAgo(
|
|
115
138
|
date: string | Date,
|
|
116
|
-
langOrConfig?:
|
|
139
|
+
langOrConfig?: TimeAgoLang | { lang?: TimeAgoLang, mode?: 'relative' | 'absolute' }
|
|
117
140
|
) {
|
|
118
141
|
if (!date) { return '' }
|
|
119
142
|
if (typeof date === 'string') { date = new Date(date) }
|
|
120
143
|
|
|
121
|
-
// Parse config
|
|
122
|
-
const lang = typeof langOrConfig === 'string'
|
|
144
|
+
// Parse config - use global i18n locale if no lang specified
|
|
145
|
+
const lang = typeof langOrConfig === 'string'
|
|
146
|
+
? langOrConfig
|
|
147
|
+
: (langOrConfig?.lang || getCurrentLocale())
|
|
123
148
|
const mode = typeof langOrConfig === 'object' ? (langOrConfig.mode || 'relative') : 'relative'
|
|
124
149
|
const isRelative = mode === 'relative'
|
|
125
150
|
|
|
@@ -138,7 +163,13 @@ export function timeAgo(
|
|
|
138
163
|
{ label: 'second', seconds: 1 }
|
|
139
164
|
]
|
|
140
165
|
|
|
141
|
-
const selectedLang =
|
|
166
|
+
const selectedLang = getTimeAgoTranslations(lang)
|
|
167
|
+
|
|
168
|
+
// Helper to get time unit translation
|
|
169
|
+
const getTimeUnit = (label: string): string | TimeUnit => {
|
|
170
|
+
const key = label as keyof TimeAgoTranslations
|
|
171
|
+
return selectedLang[key] as string | TimeUnit
|
|
172
|
+
}
|
|
142
173
|
|
|
143
174
|
for (const interval of intervals) {
|
|
144
175
|
const count = Math.floor(Math.abs(seconds) / interval.seconds)
|
|
@@ -148,7 +179,7 @@ export function timeAgo(
|
|
|
148
179
|
|
|
149
180
|
// Handle Hebrew plural forms
|
|
150
181
|
if (lang === 'he') {
|
|
151
|
-
const timeUnit =
|
|
182
|
+
const timeUnit = getTimeUnit(interval.label) as TimeUnit
|
|
152
183
|
const form = count === 1 ? timeUnit.singular : timeUnit.plural
|
|
153
184
|
|
|
154
185
|
// For Hebrew, we place the prefix/suffix before the number
|
|
@@ -168,12 +199,13 @@ export function timeAgo(
|
|
|
168
199
|
}
|
|
169
200
|
|
|
170
201
|
// Handle other languages
|
|
202
|
+
const intervalLabel = getTimeUnit(interval.label) as string
|
|
171
203
|
if (interval.label === 'day' && seconds > 0) {
|
|
172
204
|
const hours = Math.floor((Math.abs(seconds) % 86400) / 3600)
|
|
173
|
-
const hourLabel = hours > 1 ? `${selectedLang.hour}s` : selectedLang.hour
|
|
174
|
-
return `${prefix}${count} ${
|
|
205
|
+
const hourLabel = hours > 1 ? `${selectedLang.hour}s` : selectedLang.hour as string
|
|
206
|
+
return `${prefix}${count} ${intervalLabel}${hours > 0 ? ` ${hours} ${hourLabel}` : ''}${suffix}`
|
|
175
207
|
}
|
|
176
|
-
return `${prefix}${count} ${
|
|
208
|
+
return `${prefix}${count} ${intervalLabel}${suffix}`
|
|
177
209
|
}
|
|
178
210
|
}
|
|
179
211
|
|
|
@@ -187,6 +219,19 @@ function getBrowserNavigatorLocale(): string {
|
|
|
187
219
|
: navigator.language
|
|
188
220
|
}
|
|
189
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Returns the active i18n locale if initialized, otherwise falls back to
|
|
224
|
+
* the browser's navigator locale. Used as the default for formatDate.
|
|
225
|
+
*/
|
|
226
|
+
function getActiveLocale(): string {
|
|
227
|
+
try {
|
|
228
|
+
const { locale } = getI18n().global
|
|
229
|
+
return typeof locale === 'string' ? locale : locale.value
|
|
230
|
+
} catch {
|
|
231
|
+
return getBrowserNavigatorLocale()
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
190
235
|
/**
|
|
191
236
|
* Adjust a date for a specific timezone
|
|
192
237
|
* @param date The date to adjust
|
|
@@ -278,7 +323,7 @@ const _orderedDateTokens = (
|
|
|
278
323
|
const _tokenRegExPattern = new RegExp(_orderedDateTokens.map(token => token).join('|'), 'g')
|
|
279
324
|
|
|
280
325
|
export interface FormatDateOptions extends Partial<Pick<Intl.DateTimeFormatOptions, 'hour12'>> {
|
|
281
|
-
|
|
326
|
+
format?: DateTimeAcceptedFormats
|
|
282
327
|
locale?: Intl.LocalesArgument
|
|
283
328
|
tz?: string
|
|
284
329
|
}
|
|
@@ -295,7 +340,7 @@ export function formatDate(date?: DateLike, format?: DateTimeAcceptedFormats): s
|
|
|
295
340
|
* Formats a date based on the provided options.
|
|
296
341
|
* @param date The date to format (string or Date object).
|
|
297
342
|
* @param opts Options for formatting the date.
|
|
298
|
-
* @param opts.
|
|
343
|
+
* @param opts.format The format string (default is 'DD.MM.YY').
|
|
299
344
|
* @param opts.locale The locale to use for formatting (default is browser's locale).
|
|
300
345
|
* @param opts.tz The timezone to use for formatting (default is local timezone).
|
|
301
346
|
* @returns Formatted date string.
|
|
@@ -323,7 +368,7 @@ export function formatDate(
|
|
|
323
368
|
format = formatOrOpts
|
|
324
369
|
} else if (formatOrOpts && typeof formatOrOpts === 'object') {
|
|
325
370
|
// Second overload: options object
|
|
326
|
-
format = formatOrOpts.
|
|
371
|
+
format = formatOrOpts.format
|
|
327
372
|
locale = formatOrOpts.locale
|
|
328
373
|
timeZone = formatOrOpts.tz
|
|
329
374
|
rest = formatOrOpts
|
|
@@ -332,7 +377,7 @@ export function formatDate(
|
|
|
332
377
|
if (!date) { return '' }
|
|
333
378
|
format = format || 'DD.MM.YY'
|
|
334
379
|
|
|
335
|
-
locale = locale ||
|
|
380
|
+
locale = locale || getActiveLocale()
|
|
336
381
|
try {
|
|
337
382
|
// Validate the date
|
|
338
383
|
const d = typeof date === 'string' || typeof date === 'number' ? new Date(date) : date
|
package/src/utils/index.ts
CHANGED
|
@@ -201,8 +201,6 @@ export function normalizeDimension(value: string | number | undefined, defaultMe
|
|
|
201
201
|
export * as bagelFormUtils from './BagelFormUtils'
|
|
202
202
|
export { useForm } from './BagelFormUtils'
|
|
203
203
|
|
|
204
|
-
export { useLang } from './lang'
|
|
205
|
-
|
|
206
204
|
export type { ComparisonOperator, FilterCondition, LogicalOperator, QueryConditions, QueryFilter } from './queryFilter'
|
|
207
205
|
export { anyOf, parseQuery, queryFilter, range, search } from './queryFilter'
|
|
208
206
|
export type { ShowdownConverter, ShowdownOptions } from './showdown'
|
package/src/utils/lang.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { computed, reactive } from 'vue'
|
|
2
|
-
|
|
3
|
-
interface State {
|
|
4
|
-
defaultLang: string
|
|
5
|
-
availableLangs: string[]
|
|
6
|
-
lang: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const state: State = reactive({
|
|
10
|
-
defaultLang: '',
|
|
11
|
-
availableLangs: [],
|
|
12
|
-
lang: 'en',
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
function $tdb<T extends { [key: string]: string }>(langEl?: T): string {
|
|
16
|
-
if (!langEl) {
|
|
17
|
-
console.warn('No language element provided for $tdb function')
|
|
18
|
-
return ''
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return langEl[state.lang] || langEl[state.defaultLang] || ''
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function useLang() {
|
|
25
|
-
const lang = computed({
|
|
26
|
-
get: () => state.lang,
|
|
27
|
-
set: val => (state.lang = val),
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
const availableLangs = computed({
|
|
31
|
-
get: () => state.availableLangs,
|
|
32
|
-
set: val => (state.availableLangs = val),
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
const defaultLang = computed({
|
|
36
|
-
get: () => state.defaultLang,
|
|
37
|
-
set: val => (state.defaultLang = val),
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
lang,
|
|
42
|
-
$tdb,
|
|
43
|
-
availableLangs,
|
|
44
|
-
defaultLang,
|
|
45
|
-
}
|
|
46
|
-
}
|