@sveltebase/i18n 0.4.2 → 0.4.3

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/README.md CHANGED
@@ -39,8 +39,23 @@ export const languages = [
39
39
  messages: {
40
40
  "app-title": "My app",
41
41
  "welcome": "Welcome, {name}",
42
+
42
43
  "just-now": "Just now",
44
+
43
45
  "minutes-ago": "{minutes} minutes ago",
46
+ "hours-ago": "{hours} hours ago",
47
+ "days-ago": "{days} days ago",
48
+ "weeks-ago": "{weeks} weeks ago",
49
+ "months-ago": "{months} months ago",
50
+ "years-ago": "{years} years ago",
51
+
52
+ "in-minutes": "in {minutes} minutes",
53
+ "in-hours": "in {hours} hours",
54
+ "in-days": "in {days} days",
55
+ "in-weeks": "in {weeks} weeks",
56
+ "in-months": "in {months} months",
57
+ "in-years": "in {years} years",
58
+
44
59
  "today-at": "Today at {time}",
45
60
  "yesterday-at": "Yesterday at {time}"
46
61
  }
@@ -51,8 +66,23 @@ export const languages = [
51
66
  messages: {
52
67
  "app-title": "Mening ilovam",
53
68
  "welcome": "Xush kelibsiz, {name}",
69
+
54
70
  "just-now": "Hozirgina",
71
+
55
72
  "minutes-ago": "{minutes} daqiqa oldin",
73
+ "hours-ago": "{hours} soat oldin",
74
+ "days-ago": "{days} kun oldin",
75
+ "weeks-ago": "{weeks} hafta oldin",
76
+ "months-ago": "{months} oy oldin",
77
+ "years-ago": "{years} yil oldin",
78
+
79
+ "in-minutes": "{minutes} daqiqadan keyin",
80
+ "in-hours": "{hours} soatdan keyin",
81
+ "in-days": "{days} kundan keyin",
82
+ "in-weeks": "{weeks} haftadan keyin",
83
+ "in-months": "{months} oydan keyin",
84
+ "in-years": "{years} yildan keyin",
85
+
56
86
  "today-at": "Bugun {time} da",
57
87
  "yesterday-at": "Kecha {time} da"
58
88
  }
@@ -272,6 +302,7 @@ const format = getFormat();
272
302
 
273
303
  format(new Date(), { preset: "full" });
274
304
  format(new Date(), { preset: "custom", withTime: true });
305
+ format(Date.now() - 1000 * 60 * 5, { preset: "relative" });
275
306
  format("13:45:00", { preset: "timestring" });
276
307
  ```
277
308
 
@@ -295,11 +326,19 @@ console.log(i18n.currentLanguage.label);
295
326
 
296
327
  - `default`
297
328
  - `custom`
329
+ - `relative`
298
330
  - `birthday`
299
331
  - `month`
300
332
  - `timestring`
301
333
  - `full`
302
334
 
335
+ ### Preset notes
336
+
337
+ - `relative` always returns relative text for both past and future values. It does not fall back to an absolute date.
338
+ - `custom` can still mix relative labels such as `just-now` or `today-at` with locale-aware absolute dates for older values.
339
+ - `full` returns a full locale-aware date and optionally time.
340
+ - `timestring` is for time-only string values such as `"08:30:00"`.
341
+
303
342
  ### Example
304
343
 
305
344
  ```ts
@@ -308,9 +347,73 @@ const format = getFormat();
308
347
  format(new Date(), { preset: "month" });
309
348
  format(new Date(), { preset: "birthday" });
310
349
  format(new Date(), { preset: "full", withTime: true });
350
+ format(Date.now() - 1000 * 60 * 5, { preset: "relative" });
311
351
  format("08:30:00", { preset: "timestring" });
312
352
  ```
313
353
 
354
+ ## Required locale strings for relative formatting
355
+
356
+ If you use `preset: "relative"`, make sure every locale provides these message keys:
357
+
358
+ - `just-now`
359
+ - `minutes-ago`
360
+ - `hours-ago`
361
+ - `days-ago`
362
+ - `weeks-ago`
363
+ - `months-ago`
364
+ - `years-ago`
365
+ - `in-minutes`
366
+ - `in-hours`
367
+ - `in-days`
368
+ - `in-weeks`
369
+ - `in-months`
370
+ - `in-years`
371
+
372
+ Example:
373
+
374
+ ```ts
375
+ const languages = [
376
+ {
377
+ code: "en",
378
+ label: "English",
379
+ messages: {
380
+ "just-now": "Just now",
381
+ "minutes-ago": "{minutes} minutes ago",
382
+ "hours-ago": "{hours} hours ago",
383
+ "days-ago": "{days} days ago",
384
+ "weeks-ago": "{weeks} weeks ago",
385
+ "months-ago": "{months} months ago",
386
+ "years-ago": "{years} years ago",
387
+ "in-minutes": "in {minutes} minutes",
388
+ "in-hours": "in {hours} hours",
389
+ "in-days": "in {days} days",
390
+ "in-weeks": "in {weeks} weeks",
391
+ "in-months": "in {months} months",
392
+ "in-years": "in {years} years"
393
+ }
394
+ },
395
+ {
396
+ code: "uz",
397
+ label: "O‘zbekcha",
398
+ messages: {
399
+ "just-now": "Hozirgina",
400
+ "minutes-ago": "{minutes} daqiqa oldin",
401
+ "hours-ago": "{hours} soat oldin",
402
+ "days-ago": "{days} kun oldin",
403
+ "weeks-ago": "{weeks} hafta oldin",
404
+ "months-ago": "{months} oy oldin",
405
+ "years-ago": "{years} yil oldin",
406
+ "in-minutes": "{minutes} daqiqadan keyin",
407
+ "in-hours": "{hours} soatdan keyin",
408
+ "in-days": "{days} kundan keyin",
409
+ "in-weeks": "{weeks} haftadan keyin",
410
+ "in-months": "{months} oydan keyin",
411
+ "in-years": "{years} yildan keyin"
412
+ }
413
+ }
414
+ ] as const;
415
+ ```
416
+
314
417
  ## Type safety
315
418
 
316
419
  When your language array is declared with `as const`, locale codes are inferred automatically.
package/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@ type LanguageDefinition<TLocale extends string = string, TMessages extends Messa
13
13
  messages: TMessages;
14
14
  };
15
15
  type FormatOptions = {
16
- preset?: "default" | "custom" | "birthday" | "month" | "timestring" | "full";
16
+ preset?: "default" | "custom" | "birthday" | "month" | "timestring" | "full" | "relative";
17
17
  withTime?: boolean;
18
18
  };
19
19
 
package/dist/index.js CHANGED
@@ -44,6 +44,36 @@ function formatTimeWithDateFns(value, format) {
44
44
  const minutes = String(value.getMinutes()).padStart(2, "0");
45
45
  return `${hours}:${minutes}`;
46
46
  }
47
+ function formatRelativeDate(value, t) {
48
+ const now = new SvelteDate();
49
+ const diffMinutes = Math.floor((value.getTime() - now.getTime()) / 6e4);
50
+ const absMinutes = Math.abs(diffMinutes);
51
+ if (absMinutes < 1) {
52
+ return t("just-now");
53
+ }
54
+ const isFuture = diffMinutes > 0;
55
+ if (absMinutes < 60) {
56
+ return isFuture ? t("in-minutes", { minutes: absMinutes }) : t("minutes-ago", { minutes: absMinutes });
57
+ }
58
+ const absHours = Math.floor(absMinutes / 60);
59
+ if (absHours < 24) {
60
+ return isFuture ? t("in-hours", { hours: absHours }) : t("hours-ago", { hours: absHours });
61
+ }
62
+ const absDays = Math.floor(absHours / 24);
63
+ if (absDays < 7) {
64
+ return isFuture ? t("in-days", { days: absDays }) : t("days-ago", { days: absDays });
65
+ }
66
+ const absWeeks = Math.floor(absDays / 7);
67
+ if (absDays < 30) {
68
+ return isFuture ? t("in-weeks", { weeks: absWeeks }) : t("weeks-ago", { weeks: absWeeks });
69
+ }
70
+ const absMonths = Math.floor(absDays / 30);
71
+ if (absDays < 365) {
72
+ return isFuture ? t("in-months", { months: absMonths }) : t("months-ago", { months: absMonths });
73
+ }
74
+ const absYears = Math.floor(absDays / 365);
75
+ return isFuture ? t("in-years", { years: absYears }) : t("years-ago", { years: absYears });
76
+ }
47
77
  var UZ_WEEKDAYS = [
48
78
  "Yakshanba",
49
79
  "Dushanba",
@@ -119,6 +149,9 @@ function createFormatForLocale(languages, locale, fallbackLocale, timeZone = "As
119
149
  });
120
150
  }
121
151
  const date = toDate(value);
152
+ if (preset === "relative") {
153
+ return formatRelativeDate(date, t);
154
+ }
122
155
  if (preset === "full") {
123
156
  return locale === "uz" ? formatUzDate(date, true, withTime) : formatter.dateTime(date, {
124
157
  year: "numeric",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltebase/i18n",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -18,7 +18,7 @@
18
18
  }
19
19
  },
20
20
  "dependencies": {
21
- "@sveltebase/state": "0.4.2",
21
+ "@sveltebase/state": "0.4.3",
22
22
  "use-intl": "^4.4.0"
23
23
  },
24
24
  "peerDependencies": {