@stridge/noctis-intl 1.0.0-beta.0

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 (82) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +41 -0
  3. package/dist/date/CalendarDate.d.ts +211 -0
  4. package/dist/date/CalendarDate.js +340 -0
  5. package/dist/date/DateFormatter.d.ts +26 -0
  6. package/dist/date/DateFormatter.js +114 -0
  7. package/dist/date/calendars/BuddhistCalendar.d.ts +20 -0
  8. package/dist/date/calendars/BuddhistCalendar.js +33 -0
  9. package/dist/date/calendars/EthiopicCalendar.d.ts +49 -0
  10. package/dist/date/calendars/EthiopicCalendar.js +129 -0
  11. package/dist/date/calendars/GregorianCalendar.d.ts +26 -0
  12. package/dist/date/calendars/GregorianCalendar.js +117 -0
  13. package/dist/date/calendars/HebrewCalendar.d.ts +25 -0
  14. package/dist/date/calendars/HebrewCalendar.js +114 -0
  15. package/dist/date/calendars/IndianCalendar.d.ts +21 -0
  16. package/dist/date/calendars/IndianCalendar.js +75 -0
  17. package/dist/date/calendars/IslamicCalendar.d.ts +55 -0
  18. package/dist/date/calendars/IslamicCalendar.js +162 -0
  19. package/dist/date/calendars/JapaneseCalendar.d.ts +26 -0
  20. package/dist/date/calendars/JapaneseCalendar.js +154 -0
  21. package/dist/date/calendars/PersianCalendar.d.ts +23 -0
  22. package/dist/date/calendars/PersianCalendar.js +63 -0
  23. package/dist/date/calendars/TaiwanCalendar.d.ts +23 -0
  24. package/dist/date/calendars/TaiwanCalendar.js +51 -0
  25. package/dist/date/conversion.d.ts +41 -0
  26. package/dist/date/conversion.js +181 -0
  27. package/dist/date/createCalendar.d.ts +7 -0
  28. package/dist/date/createCalendar.js +30 -0
  29. package/dist/date/manipulation.js +274 -0
  30. package/dist/date/queries.d.ts +92 -0
  31. package/dist/date/queries.js +233 -0
  32. package/dist/date/string.d.ts +36 -0
  33. package/dist/date/string.js +162 -0
  34. package/dist/date/types.d.ts +138 -0
  35. package/dist/date/utils.d.ts +4 -0
  36. package/dist/date/utils.js +6 -0
  37. package/dist/date/weekStartData.js +100 -0
  38. package/dist/date.d.ts +17 -0
  39. package/dist/date.js +16 -0
  40. package/dist/i18n/context.d.ts +17 -0
  41. package/dist/i18n/context.js +13 -0
  42. package/dist/i18n/use-collator.d.ts +8 -0
  43. package/dist/i18n/use-collator.js +19 -0
  44. package/dist/i18n/use-date-formatter.d.ts +14 -0
  45. package/dist/i18n/use-date-formatter.js +25 -0
  46. package/dist/i18n/use-deep-memo.d.ts +8 -0
  47. package/dist/i18n/use-deep-memo.js +15 -0
  48. package/dist/i18n/use-filter.d.ts +17 -0
  49. package/dist/i18n/use-filter.js +49 -0
  50. package/dist/i18n/use-list-formatter.d.ts +5 -0
  51. package/dist/i18n/use-list-formatter.js +11 -0
  52. package/dist/i18n/use-locale.d.ts +7 -0
  53. package/dist/i18n/use-locale.js +13 -0
  54. package/dist/i18n/use-localized-string-formatter.d.ts +13 -0
  55. package/dist/i18n/use-localized-string-formatter.js +30 -0
  56. package/dist/i18n/use-number-formatter.d.ts +14 -0
  57. package/dist/i18n/use-number-formatter.js +15 -0
  58. package/dist/i18n/utils.d.ts +15 -0
  59. package/dist/i18n/utils.js +50 -0
  60. package/dist/index.d.ts +22 -0
  61. package/dist/index.js +21 -0
  62. package/dist/messages/en.d.ts +6 -0
  63. package/dist/messages/en.js +68 -0
  64. package/dist/messages/fa.d.ts +6 -0
  65. package/dist/messages/fa.js +68 -0
  66. package/dist/number/NumberFormatter.d.ts +32 -0
  67. package/dist/number/NumberFormatter.js +135 -0
  68. package/dist/number/NumberParser.d.ts +30 -0
  69. package/dist/number/NumberParser.js +234 -0
  70. package/dist/number.d.ts +3 -0
  71. package/dist/number.js +3 -0
  72. package/dist/react.d.ts +17 -0
  73. package/dist/react.js +17 -0
  74. package/dist/ssr/use-is-ssr.d.ts +8 -0
  75. package/dist/ssr/use-is-ssr.js +15 -0
  76. package/dist/string/LocalizedStringDictionary.d.ts +22 -0
  77. package/dist/string/LocalizedStringDictionary.js +58 -0
  78. package/dist/string/LocalizedStringFormatter.d.ts +22 -0
  79. package/dist/string/LocalizedStringFormatter.js +46 -0
  80. package/dist/string.d.ts +3 -0
  81. package/dist/string.js +3 -0
  82. package/package.json +80 -0
package/dist/date.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ import { CalendarDate, CalendarDateTime, DateValue, Time, ZonedDateTime } from "./date/CalendarDate.js";
2
+ import { AnyCalendarDate, AnyDateTime, AnyTime, Calendar, CalendarIdentifier, CycleOptions, CycleTimeOptions, DateDuration, DateField, DateFields, DateTimeDuration, Disambiguation, TimeDuration, TimeField, TimeFields } from "./date/types.js";
3
+ import { GregorianCalendar } from "./date/calendars/GregorianCalendar.js";
4
+ import { JapaneseCalendar } from "./date/calendars/JapaneseCalendar.js";
5
+ import { BuddhistCalendar } from "./date/calendars/BuddhistCalendar.js";
6
+ import { TaiwanCalendar } from "./date/calendars/TaiwanCalendar.js";
7
+ import { PersianCalendar } from "./date/calendars/PersianCalendar.js";
8
+ import { IndianCalendar } from "./date/calendars/IndianCalendar.js";
9
+ import { IslamicCivilCalendar, IslamicTabularCalendar, IslamicUmalquraCalendar } from "./date/calendars/IslamicCalendar.js";
10
+ import { HebrewCalendar } from "./date/calendars/HebrewCalendar.js";
11
+ import { CopticCalendar, EthiopicAmeteAlemCalendar, EthiopicCalendar } from "./date/calendars/EthiopicCalendar.js";
12
+ import { createCalendar } from "./date/createCalendar.js";
13
+ import { fromAbsolute, fromDate, fromDateToLocal, toCalendar, toCalendarDate, toCalendarDateTime, toLocalTimeZone, toTime, toTimeZone, toZoned } from "./date/conversion.js";
14
+ import { endOfMonth, endOfWeek, endOfYear, getDayOfWeek, getHoursInDay, getLocalTimeZone, getMinimumDayInMonth, getMinimumMonthInYear, getWeeksInMonth, isEqualCalendar, isEqualDay, isEqualMonth, isEqualYear, isSameDay, isSameMonth, isSameYear, isToday, isWeekday, isWeekend, maxDate, minDate, now, resetLocalTimeZone, setLocalTimeZone, startOfMonth, startOfWeek, startOfYear, today } from "./date/queries.js";
15
+ import { parseAbsolute, parseAbsoluteToLocal, parseDate, parseDateTime, parseDuration, parseTime, parseZonedDateTime } from "./date/string.js";
16
+ import { DateFormatter } from "./date/DateFormatter.js";
17
+ export { type AnyCalendarDate, type AnyDateTime, type AnyTime, BuddhistCalendar, type Calendar, CalendarDate, CalendarDateTime, type CalendarIdentifier, CopticCalendar, type CycleOptions, type CycleTimeOptions, type DateDuration, type DateField, type DateFields, DateFormatter, type DateTimeDuration, type DateValue, type Disambiguation, EthiopicAmeteAlemCalendar, EthiopicCalendar, GregorianCalendar, HebrewCalendar, IndianCalendar, IslamicCivilCalendar, IslamicTabularCalendar, IslamicUmalquraCalendar, JapaneseCalendar, PersianCalendar, TaiwanCalendar, Time, type TimeDuration, type TimeField, type TimeFields, ZonedDateTime, createCalendar, endOfMonth, endOfWeek, endOfYear, fromAbsolute, fromDate, fromDateToLocal, getDayOfWeek, getHoursInDay, getLocalTimeZone, getMinimumDayInMonth, getMinimumMonthInYear, getWeeksInMonth, isEqualCalendar, isEqualDay, isEqualMonth, isEqualYear, isSameDay, isSameMonth, isSameYear, isToday, isWeekday, isWeekend, maxDate, minDate, now, parseAbsolute, parseAbsoluteToLocal, parseDate, parseDateTime, parseDuration, parseTime, parseZonedDateTime, resetLocalTimeZone, setLocalTimeZone, startOfMonth, startOfWeek, startOfYear, toCalendar, toCalendarDate, toCalendarDateTime, toLocalTimeZone, toTime, toTimeZone, toZoned, today };
package/dist/date.js ADDED
@@ -0,0 +1,16 @@
1
+ import { GregorianCalendar } from "./date/calendars/GregorianCalendar.js";
2
+ import { endOfMonth, endOfWeek, endOfYear, getDayOfWeek, getHoursInDay, getLocalTimeZone, getMinimumDayInMonth, getMinimumMonthInYear, getWeeksInMonth, isEqualCalendar, isEqualDay, isEqualMonth, isEqualYear, isSameDay, isSameMonth, isSameYear, isToday, isWeekday, isWeekend, maxDate, minDate, now, resetLocalTimeZone, setLocalTimeZone, startOfMonth, startOfWeek, startOfYear, today } from "./date/queries.js";
3
+ import { fromAbsolute, fromDate, fromDateToLocal, toCalendar, toCalendarDate, toCalendarDateTime, toLocalTimeZone, toTime, toTimeZone, toZoned } from "./date/conversion.js";
4
+ import { parseAbsolute, parseAbsoluteToLocal, parseDate, parseDateTime, parseDuration, parseTime, parseZonedDateTime } from "./date/string.js";
5
+ import { CalendarDate, CalendarDateTime, Time, ZonedDateTime } from "./date/CalendarDate.js";
6
+ import { JapaneseCalendar } from "./date/calendars/JapaneseCalendar.js";
7
+ import { BuddhistCalendar } from "./date/calendars/BuddhistCalendar.js";
8
+ import { TaiwanCalendar } from "./date/calendars/TaiwanCalendar.js";
9
+ import { PersianCalendar } from "./date/calendars/PersianCalendar.js";
10
+ import { IndianCalendar } from "./date/calendars/IndianCalendar.js";
11
+ import { IslamicCivilCalendar, IslamicTabularCalendar, IslamicUmalquraCalendar } from "./date/calendars/IslamicCalendar.js";
12
+ import { HebrewCalendar } from "./date/calendars/HebrewCalendar.js";
13
+ import { CopticCalendar, EthiopicAmeteAlemCalendar, EthiopicCalendar } from "./date/calendars/EthiopicCalendar.js";
14
+ import { createCalendar } from "./date/createCalendar.js";
15
+ import { DateFormatter } from "./date/DateFormatter.js";
16
+ export { BuddhistCalendar, CalendarDate, CalendarDateTime, CopticCalendar, DateFormatter, EthiopicAmeteAlemCalendar, EthiopicCalendar, GregorianCalendar, HebrewCalendar, IndianCalendar, IslamicCivilCalendar, IslamicTabularCalendar, IslamicUmalquraCalendar, JapaneseCalendar, PersianCalendar, TaiwanCalendar, Time, ZonedDateTime, createCalendar, endOfMonth, endOfWeek, endOfYear, fromAbsolute, fromDate, fromDateToLocal, getDayOfWeek, getHoursInDay, getLocalTimeZone, getMinimumDayInMonth, getMinimumMonthInYear, getWeeksInMonth, isEqualCalendar, isEqualDay, isEqualMonth, isEqualYear, isSameDay, isSameMonth, isSameYear, isToday, isWeekday, isWeekend, maxDate, minDate, now, parseAbsolute, parseAbsoluteToLocal, parseDate, parseDateTime, parseDuration, parseTime, parseZonedDateTime, resetLocalTimeZone, setLocalTimeZone, startOfMonth, startOfWeek, startOfYear, toCalendar, toCalendarDate, toCalendarDateTime, toLocalTimeZone, toTime, toTimeZone, toZoned, today };
@@ -0,0 +1,17 @@
1
+ import { LocalizedStrings } from "../string/LocalizedStringDictionary.js";
2
+ import { TextDirection } from "./utils.js";
3
+ import * as _$react from "react";
4
+
5
+ //#region src/i18n/context.d.ts
6
+ /** The locale, resolved direction, and string dictionary shared with every i18n hook. */
7
+ interface LocaleContextValue {
8
+ locale: string;
9
+ direction: TextDirection;
10
+ dictionary: LocalizedStrings<string, string>;
11
+ }
12
+ /** No implicit fallback — a missing provider is an error, surfaced by {@link useLocaleContext}. */
13
+ declare const LocaleContext: _$react.Context<LocaleContextValue | null>;
14
+ /** Read the locale context, throwing a named error when used outside a `NoctisProvider`. */
15
+ declare function useLocaleContext(hook: string): LocaleContextValue;
16
+ //#endregion
17
+ export { LocaleContext, LocaleContextValue, useLocaleContext };
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { createContext, use } from "react";
3
+ //#region src/i18n/context.ts
4
+ /** No implicit fallback — a missing provider is an error, surfaced by {@link useLocaleContext}. */
5
+ const LocaleContext = createContext(null);
6
+ /** Read the locale context, throwing a named error when used outside a `NoctisProvider`. */
7
+ function useLocaleContext(hook) {
8
+ const context = use(LocaleContext);
9
+ if (!context) throw new Error(`${hook} must be used within a NoctisProvider.`);
10
+ return context;
11
+ }
12
+ //#endregion
13
+ export { LocaleContext, useLocaleContext };
@@ -0,0 +1,8 @@
1
+ //#region src/i18n/use-collator.d.ts
2
+ /**
3
+ * Provides a locale-aware `Intl.Collator` for the active locale, cached across renders by locale and
4
+ * options.
5
+ */
6
+ declare function useCollator(options?: Intl.CollatorOptions): Intl.Collator;
7
+ //#endregion
8
+ export { useCollator };
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ import { useLocale } from "./use-locale.js";
3
+ //#region src/i18n/use-collator.ts
4
+ const cache = /* @__PURE__ */ new Map();
5
+ /**
6
+ * Provides a locale-aware `Intl.Collator` for the active locale, cached across renders by locale and
7
+ * options.
8
+ */
9
+ function useCollator(options) {
10
+ const { locale } = useLocale();
11
+ const cacheKey = locale + (options ? Object.entries(options).sort((a, b) => a[0] < b[0] ? -1 : 1).join() : "");
12
+ const cached = cache.get(cacheKey);
13
+ if (cached) return cached;
14
+ const collator = new Intl.Collator(locale, options);
15
+ cache.set(cacheKey, collator);
16
+ return collator;
17
+ }
18
+ //#endregion
19
+ export { useCollator };
@@ -0,0 +1,14 @@
1
+ import { DateFormatter } from "../date/DateFormatter.js";
2
+
3
+ //#region src/i18n/use-date-formatter.d.ts
4
+ /** `Intl.DateTimeFormatOptions` plus an optional calendar override. */
5
+ interface DateFormatterOptions extends Intl.DateTimeFormatOptions {
6
+ calendar?: string;
7
+ }
8
+ /**
9
+ * Provides a locale-aware date formatter for the active locale. Shallowly-equal options reuse the
10
+ * same formatter, so a fresh options object each render does not rebuild it.
11
+ */
12
+ declare function useDateFormatter(options?: DateFormatterOptions): DateFormatter;
13
+ //#endregion
14
+ export { DateFormatterOptions, useDateFormatter };
@@ -0,0 +1,25 @@
1
+ "use client";
2
+ import { DateFormatter } from "../date/DateFormatter.js";
3
+ import { useLocale } from "./use-locale.js";
4
+ import { useDeepMemo } from "./use-deep-memo.js";
5
+ import { useMemo } from "react";
6
+ //#region src/i18n/use-date-formatter.ts
7
+ /**
8
+ * Provides a locale-aware date formatter for the active locale. Shallowly-equal options reuse the
9
+ * same formatter, so a fresh options object each render does not rebuild it.
10
+ */
11
+ function useDateFormatter(options) {
12
+ const memoOptions = useDeepMemo(options ?? {}, isEqualOptions);
13
+ const { locale } = useLocale();
14
+ return useMemo(() => new DateFormatter(locale, memoOptions), [locale, memoOptions]);
15
+ }
16
+ function isEqualOptions(a, b) {
17
+ if (a === b) return true;
18
+ const aKeys = Object.keys(a);
19
+ const bKeys = Object.keys(b);
20
+ if (aKeys.length !== bKeys.length) return false;
21
+ for (const key of aKeys) if (b[key] !== a[key]) return false;
22
+ return true;
23
+ }
24
+ //#endregion
25
+ export { useDateFormatter };
@@ -0,0 +1,8 @@
1
+ //#region src/i18n/use-deep-memo.d.ts
2
+ /**
3
+ * Returns the previous value when it is deeply equal to the current one, so a downstream `useMemo`
4
+ * keyed on it can reuse its result. Re-implemented from Adobe's react-aria (Apache-2.0; see NOTICE.txt).
5
+ */
6
+ declare function useDeepMemo<T>(value: T, isEqual: (a: T, b: T) => boolean): T;
7
+ //#endregion
8
+ export { useDeepMemo };
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { useRef } from "react";
3
+ //#region src/i18n/use-deep-memo.ts
4
+ /**
5
+ * Returns the previous value when it is deeply equal to the current one, so a downstream `useMemo`
6
+ * keyed on it can reuse its result. Re-implemented from Adobe's react-aria (Apache-2.0; see NOTICE.txt).
7
+ */
8
+ function useDeepMemo(value, isEqual) {
9
+ let lastValue = useRef(null);
10
+ if (value && lastValue.current && isEqual(value, lastValue.current)) value = lastValue.current;
11
+ lastValue.current = value;
12
+ return value;
13
+ }
14
+ //#endregion
15
+ export { useDeepMemo };
@@ -0,0 +1,17 @@
1
+ //#region src/i18n/use-filter.d.ts
2
+ /** Locale-aware substring matchers for filtering and searching. */
3
+ interface Filter {
4
+ /** Returns whether a string starts with a given substring. */
5
+ startsWith: (string: string, substring: string) => boolean;
6
+ /** Returns whether a string ends with a given substring. */
7
+ endsWith: (string: string, substring: string) => boolean;
8
+ /** Returns whether a string contains a given substring. */
9
+ contains: (string: string, substring: string) => boolean;
10
+ }
11
+ /**
12
+ * Provides locale-aware string search for filtering or matching list items. Options adjust
13
+ * sensitivity to case, diacritics, and so on. Inputs are NFC-normalized before comparison.
14
+ */
15
+ declare function useFilter(options?: Intl.CollatorOptions): Filter;
16
+ //#endregion
17
+ export { Filter, useFilter };
@@ -0,0 +1,49 @@
1
+ "use client";
2
+ import { useCollator } from "./use-collator.js";
3
+ import { useCallback, useMemo } from "react";
4
+ //#region src/i18n/use-filter.ts
5
+ /**
6
+ * Provides locale-aware string search for filtering or matching list items. Options adjust
7
+ * sensitivity to case, diacritics, and so on. Inputs are NFC-normalized before comparison.
8
+ */
9
+ function useFilter(options) {
10
+ const collator = useCollator({
11
+ usage: "search",
12
+ ...options
13
+ });
14
+ const startsWith = useCallback((string, substring) => {
15
+ if (substring.length === 0) return true;
16
+ string = string.normalize("NFC");
17
+ substring = substring.normalize("NFC");
18
+ return collator.compare(string.slice(0, substring.length), substring) === 0;
19
+ }, [collator]);
20
+ const endsWith = useCallback((string, substring) => {
21
+ if (substring.length === 0) return true;
22
+ string = string.normalize("NFC");
23
+ substring = substring.normalize("NFC");
24
+ return collator.compare(string.slice(-substring.length), substring) === 0;
25
+ }, [collator]);
26
+ const contains = useCallback((string, substring) => {
27
+ if (substring.length === 0) return true;
28
+ string = string.normalize("NFC");
29
+ substring = substring.normalize("NFC");
30
+ let scan = 0;
31
+ const sliceLen = substring.length;
32
+ for (; scan + sliceLen <= string.length; scan++) {
33
+ const slice = string.slice(scan, scan + sliceLen);
34
+ if (collator.compare(substring, slice) === 0) return true;
35
+ }
36
+ return false;
37
+ }, [collator]);
38
+ return useMemo(() => ({
39
+ startsWith,
40
+ endsWith,
41
+ contains
42
+ }), [
43
+ startsWith,
44
+ endsWith,
45
+ contains
46
+ ]);
47
+ }
48
+ //#endregion
49
+ export { useFilter };
@@ -0,0 +1,5 @@
1
+ //#region src/i18n/use-list-formatter.d.ts
2
+ /** Provides a locale-aware `Intl.ListFormat` for the active locale, memoized across renders. */
3
+ declare function useListFormatter(options?: Intl.ListFormatOptions): Intl.ListFormat;
4
+ //#endregion
5
+ export { useListFormatter };
@@ -0,0 +1,11 @@
1
+ "use client";
2
+ import { useLocale } from "./use-locale.js";
3
+ import { useMemo } from "react";
4
+ //#region src/i18n/use-list-formatter.ts
5
+ /** Provides a locale-aware `Intl.ListFormat` for the active locale, memoized across renders. */
6
+ function useListFormatter(options = {}) {
7
+ const { locale } = useLocale();
8
+ return useMemo(() => new Intl.ListFormat(locale, options), [locale, options]);
9
+ }
10
+ //#endregion
11
+ export { useListFormatter };
@@ -0,0 +1,7 @@
1
+ import { Locale } from "./utils.js";
2
+
3
+ //#region src/i18n/use-locale.d.ts
4
+ /** Returns the active locale and its resolved reading direction from the nearest `NoctisProvider`. */
5
+ declare function useLocale(): Locale;
6
+ //#endregion
7
+ export { useLocale };
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { useLocaleContext } from "./context.js";
3
+ //#region src/i18n/use-locale.ts
4
+ /** Returns the active locale and its resolved reading direction from the nearest `NoctisProvider`. */
5
+ function useLocale() {
6
+ const { locale, direction } = useLocaleContext("useLocale");
7
+ return {
8
+ locale,
9
+ direction
10
+ };
11
+ }
12
+ //#endregion
13
+ export { useLocale };
@@ -0,0 +1,13 @@
1
+ import { LocalizedStringDictionary, LocalizedStrings } from "../string/LocalizedStringDictionary.js";
2
+ import { LocalizedString, LocalizedStringFormatter } from "../string/LocalizedStringFormatter.js";
3
+
4
+ //#region src/i18n/use-localized-string-formatter.d.ts
5
+ /** Returns a cached `LocalizedStringDictionary` for the given strings, keyed by the strings object. */
6
+ declare function useLocalizedStringDictionary<K extends string = string, T extends LocalizedString = string>(strings: LocalizedStrings<K, T>): LocalizedStringDictionary<K, T>;
7
+ /**
8
+ * Provides a `LocalizedStringFormatter` for the active locale and the given strings — interpolates
9
+ * variables, selects pluralization, and formats numbers, updating when the locale changes.
10
+ */
11
+ declare function useLocalizedStringFormatter<K extends string = string, T extends LocalizedString = string>(strings: LocalizedStrings<K, T>): LocalizedStringFormatter<K, T>;
12
+ //#endregion
13
+ export { useLocalizedStringDictionary, useLocalizedStringFormatter };
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import { LocalizedStringDictionary } from "../string/LocalizedStringDictionary.js";
3
+ import { LocalizedStringFormatter } from "../string/LocalizedStringFormatter.js";
4
+ import { useLocale } from "./use-locale.js";
5
+ import { useMemo } from "react";
6
+ //#region src/i18n/use-localized-string-formatter.ts
7
+ const cache = /* @__PURE__ */ new WeakMap();
8
+ function getCachedDictionary(strings) {
9
+ let dictionary = cache.get(strings);
10
+ if (!dictionary) {
11
+ dictionary = new LocalizedStringDictionary(strings);
12
+ cache.set(strings, dictionary);
13
+ }
14
+ return dictionary;
15
+ }
16
+ /** Returns a cached `LocalizedStringDictionary` for the given strings, keyed by the strings object. */
17
+ function useLocalizedStringDictionary(strings) {
18
+ return getCachedDictionary(strings);
19
+ }
20
+ /**
21
+ * Provides a `LocalizedStringFormatter` for the active locale and the given strings — interpolates
22
+ * variables, selects pluralization, and formats numbers, updating when the locale changes.
23
+ */
24
+ function useLocalizedStringFormatter(strings) {
25
+ const { locale } = useLocale();
26
+ const dictionary = useLocalizedStringDictionary(strings);
27
+ return useMemo(() => new LocalizedStringFormatter(locale, dictionary), [locale, dictionary]);
28
+ }
29
+ //#endregion
30
+ export { useLocalizedStringDictionary, useLocalizedStringFormatter };
@@ -0,0 +1,14 @@
1
+ import { NumberFormatter } from "../number/NumberFormatter.js";
2
+
3
+ //#region src/i18n/use-number-formatter.d.ts
4
+ /** `Intl.NumberFormatOptions` plus an optional numbering-system override. */
5
+ interface NumberFormatOptions extends Intl.NumberFormatOptions {
6
+ numberingSystem?: string;
7
+ }
8
+ /**
9
+ * Provides a locale-aware number formatter for the active locale, memoized so the same options
10
+ * object reuses one formatter.
11
+ */
12
+ declare function useNumberFormatter(options?: NumberFormatOptions): NumberFormatter;
13
+ //#endregion
14
+ export { NumberFormatOptions, useNumberFormatter };
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { NumberFormatter } from "../number/NumberFormatter.js";
3
+ import { useLocale } from "./use-locale.js";
4
+ import { useMemo } from "react";
5
+ //#region src/i18n/use-number-formatter.ts
6
+ /**
7
+ * Provides a locale-aware number formatter for the active locale, memoized so the same options
8
+ * object reuses one formatter.
9
+ */
10
+ function useNumberFormatter(options = {}) {
11
+ const { locale } = useLocale();
12
+ return useMemo(() => new NumberFormatter(locale, options), [locale, options]);
13
+ }
14
+ //#endregion
15
+ export { useNumberFormatter };
@@ -0,0 +1,15 @@
1
+ //#region src/i18n/utils.d.ts
2
+ /** A resolved reading direction. */
3
+ type TextDirection = "ltr" | "rtl";
4
+ /** A locale paired with its resolved reading direction. */
5
+ interface Locale {
6
+ locale: string;
7
+ direction: TextDirection;
8
+ }
9
+ /**
10
+ * Determines whether a locale is read right-to-left, using `Intl.Locale` text info when available
11
+ * and falling back to the locale's script, then its language.
12
+ */
13
+ declare function isRTL(localeString: string): boolean;
14
+ //#endregion
15
+ export { Locale, TextDirection, isRTL };
@@ -0,0 +1,50 @@
1
+ //#region src/i18n/utils.ts
2
+ const RTL_SCRIPTS = new Set([
3
+ "Arab",
4
+ "Syrc",
5
+ "Samr",
6
+ "Mand",
7
+ "Thaa",
8
+ "Mend",
9
+ "Nkoo",
10
+ "Adlm",
11
+ "Rohg",
12
+ "Hebr"
13
+ ]);
14
+ const RTL_LANGS = new Set([
15
+ "ae",
16
+ "ar",
17
+ "arc",
18
+ "bcc",
19
+ "bqi",
20
+ "ckb",
21
+ "dv",
22
+ "fa",
23
+ "glk",
24
+ "he",
25
+ "ku",
26
+ "mzn",
27
+ "nqo",
28
+ "pnb",
29
+ "ps",
30
+ "sd",
31
+ "ug",
32
+ "ur",
33
+ "yi"
34
+ ]);
35
+ /**
36
+ * Determines whether a locale is read right-to-left, using `Intl.Locale` text info when available
37
+ * and falling back to the locale's script, then its language.
38
+ */
39
+ function isRTL(localeString) {
40
+ if (Intl.Locale) {
41
+ let locale = new Intl.Locale(localeString).maximize();
42
+ let textInfo = typeof locale.getTextInfo === "function" ? locale.getTextInfo() : locale.textInfo;
43
+ if (textInfo) return textInfo.direction === "rtl";
44
+ if (locale.script) return RTL_SCRIPTS.has(locale.script);
45
+ }
46
+ let lang = localeString.split("-")[0];
47
+ return RTL_LANGS.has(lang);
48
+ }
49
+ //#endregion
50
+ export { isRTL };
@@ -0,0 +1,22 @@
1
+ import { CalendarDate, CalendarDateTime, DateValue, Time, ZonedDateTime } from "./date/CalendarDate.js";
2
+ import { AnyCalendarDate, AnyDateTime, AnyTime, Calendar, CalendarIdentifier, CycleOptions, CycleTimeOptions, DateDuration, DateField, DateFields, DateTimeDuration, Disambiguation, TimeDuration, TimeField, TimeFields } from "./date/types.js";
3
+ import { GregorianCalendar } from "./date/calendars/GregorianCalendar.js";
4
+ import { JapaneseCalendar } from "./date/calendars/JapaneseCalendar.js";
5
+ import { BuddhistCalendar } from "./date/calendars/BuddhistCalendar.js";
6
+ import { TaiwanCalendar } from "./date/calendars/TaiwanCalendar.js";
7
+ import { PersianCalendar } from "./date/calendars/PersianCalendar.js";
8
+ import { IndianCalendar } from "./date/calendars/IndianCalendar.js";
9
+ import { IslamicCivilCalendar, IslamicTabularCalendar, IslamicUmalquraCalendar } from "./date/calendars/IslamicCalendar.js";
10
+ import { HebrewCalendar } from "./date/calendars/HebrewCalendar.js";
11
+ import { CopticCalendar, EthiopicAmeteAlemCalendar, EthiopicCalendar } from "./date/calendars/EthiopicCalendar.js";
12
+ import { createCalendar } from "./date/createCalendar.js";
13
+ import { fromAbsolute, fromDate, fromDateToLocal, toCalendar, toCalendarDate, toCalendarDateTime, toLocalTimeZone, toTime, toTimeZone, toZoned } from "./date/conversion.js";
14
+ import { endOfMonth, endOfWeek, endOfYear, getDayOfWeek, getHoursInDay, getLocalTimeZone, getMinimumDayInMonth, getMinimumMonthInYear, getWeeksInMonth, isEqualCalendar, isEqualDay, isEqualMonth, isEqualYear, isSameDay, isSameMonth, isSameYear, isToday, isWeekday, isWeekend, maxDate, minDate, now, resetLocalTimeZone, setLocalTimeZone, startOfMonth, startOfWeek, startOfYear, today } from "./date/queries.js";
15
+ import { parseAbsolute, parseAbsoluteToLocal, parseDate, parseDateTime, parseDuration, parseTime, parseZonedDateTime } from "./date/string.js";
16
+ import { DateFormatter } from "./date/DateFormatter.js";
17
+ import { LocalizedStringDictionary, LocalizedStrings } from "./string/LocalizedStringDictionary.js";
18
+ import { LocalizedString, LocalizedStringFormatter, Variables } from "./string/LocalizedStringFormatter.js";
19
+ import { Locale, TextDirection, isRTL } from "./i18n/utils.js";
20
+ import { NumberFormatOptions, NumberFormatter } from "./number/NumberFormatter.js";
21
+ import { NumberParser } from "./number/NumberParser.js";
22
+ export { AnyCalendarDate, AnyDateTime, AnyTime, BuddhistCalendar, Calendar, CalendarDate, CalendarDateTime, CalendarIdentifier, CopticCalendar, CycleOptions, CycleTimeOptions, DateDuration, DateField, DateFields, DateFormatter, DateTimeDuration, DateValue, Disambiguation, EthiopicAmeteAlemCalendar, EthiopicCalendar, GregorianCalendar, HebrewCalendar, IndianCalendar, IslamicCivilCalendar, IslamicTabularCalendar, IslamicUmalquraCalendar, JapaneseCalendar, type Locale, LocalizedString, LocalizedStringDictionary, LocalizedStringFormatter, LocalizedStrings, NumberFormatOptions, NumberFormatter, NumberParser, PersianCalendar, TaiwanCalendar, type TextDirection, Time, TimeDuration, TimeField, TimeFields, Variables, ZonedDateTime, createCalendar, endOfMonth, endOfWeek, endOfYear, fromAbsolute, fromDate, fromDateToLocal, getDayOfWeek, getHoursInDay, getLocalTimeZone, getMinimumDayInMonth, getMinimumMonthInYear, getWeeksInMonth, isEqualCalendar, isEqualDay, isEqualMonth, isEqualYear, isRTL, isSameDay, isSameMonth, isSameYear, isToday, isWeekday, isWeekend, maxDate, minDate, now, parseAbsolute, parseAbsoluteToLocal, parseDate, parseDateTime, parseDuration, parseTime, parseZonedDateTime, resetLocalTimeZone, setLocalTimeZone, startOfMonth, startOfWeek, startOfYear, toCalendar, toCalendarDate, toCalendarDateTime, toLocalTimeZone, toTime, toTimeZone, toZoned, today };
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ import { GregorianCalendar } from "./date/calendars/GregorianCalendar.js";
2
+ import { endOfMonth, endOfWeek, endOfYear, getDayOfWeek, getHoursInDay, getLocalTimeZone, getMinimumDayInMonth, getMinimumMonthInYear, getWeeksInMonth, isEqualCalendar, isEqualDay, isEqualMonth, isEqualYear, isSameDay, isSameMonth, isSameYear, isToday, isWeekday, isWeekend, maxDate, minDate, now, resetLocalTimeZone, setLocalTimeZone, startOfMonth, startOfWeek, startOfYear, today } from "./date/queries.js";
3
+ import { fromAbsolute, fromDate, fromDateToLocal, toCalendar, toCalendarDate, toCalendarDateTime, toLocalTimeZone, toTime, toTimeZone, toZoned } from "./date/conversion.js";
4
+ import { parseAbsolute, parseAbsoluteToLocal, parseDate, parseDateTime, parseDuration, parseTime, parseZonedDateTime } from "./date/string.js";
5
+ import { CalendarDate, CalendarDateTime, Time, ZonedDateTime } from "./date/CalendarDate.js";
6
+ import { JapaneseCalendar } from "./date/calendars/JapaneseCalendar.js";
7
+ import { BuddhistCalendar } from "./date/calendars/BuddhistCalendar.js";
8
+ import { TaiwanCalendar } from "./date/calendars/TaiwanCalendar.js";
9
+ import { PersianCalendar } from "./date/calendars/PersianCalendar.js";
10
+ import { IndianCalendar } from "./date/calendars/IndianCalendar.js";
11
+ import { IslamicCivilCalendar, IslamicTabularCalendar, IslamicUmalquraCalendar } from "./date/calendars/IslamicCalendar.js";
12
+ import { HebrewCalendar } from "./date/calendars/HebrewCalendar.js";
13
+ import { CopticCalendar, EthiopicAmeteAlemCalendar, EthiopicCalendar } from "./date/calendars/EthiopicCalendar.js";
14
+ import { createCalendar } from "./date/createCalendar.js";
15
+ import { DateFormatter } from "./date/DateFormatter.js";
16
+ import { NumberFormatter } from "./number/NumberFormatter.js";
17
+ import { NumberParser } from "./number/NumberParser.js";
18
+ import { LocalizedStringDictionary } from "./string/LocalizedStringDictionary.js";
19
+ import { LocalizedStringFormatter } from "./string/LocalizedStringFormatter.js";
20
+ import { isRTL } from "./i18n/utils.js";
21
+ export { BuddhistCalendar, CalendarDate, CalendarDateTime, CopticCalendar, DateFormatter, EthiopicAmeteAlemCalendar, EthiopicCalendar, GregorianCalendar, HebrewCalendar, IndianCalendar, IslamicCivilCalendar, IslamicTabularCalendar, IslamicUmalquraCalendar, JapaneseCalendar, LocalizedStringDictionary, LocalizedStringFormatter, NumberFormatter, NumberParser, PersianCalendar, TaiwanCalendar, Time, ZonedDateTime, createCalendar, endOfMonth, endOfWeek, endOfYear, fromAbsolute, fromDate, fromDateToLocal, getDayOfWeek, getHoursInDay, getLocalTimeZone, getMinimumDayInMonth, getMinimumMonthInYear, getWeeksInMonth, isEqualCalendar, isEqualDay, isEqualMonth, isEqualYear, isRTL, isSameDay, isSameMonth, isSameYear, isToday, isWeekday, isWeekend, maxDate, minDate, now, parseAbsolute, parseAbsoluteToLocal, parseDate, parseDateTime, parseDuration, parseTime, parseZonedDateTime, resetLocalTimeZone, setLocalTimeZone, startOfMonth, startOfWeek, startOfYear, toCalendar, toCalendarDate, toCalendarDateTime, toLocalTimeZone, toTime, toTimeZone, toZoned, today };
@@ -0,0 +1,6 @@
1
+ import { LocalizedString } from "../string/LocalizedStringFormatter.js";
2
+
3
+ //#region src/messages/en.d.ts
4
+ declare const messages: Record<string, LocalizedString>;
5
+ //#endregion
6
+ export { messages as default };
@@ -0,0 +1,68 @@
1
+ //#region src/messages/en.ts
2
+ const messages = {
3
+ "numberField.increase": `Increase`,
4
+ "numberField.decrease": `Decrease`,
5
+ "numberField.numberField": `Number field`,
6
+ "field.charactersRemaining": (args, formatter) => `${formatter.plural(args.count, {
7
+ one: () => `${formatter.number(args.count)} character remaining`,
8
+ other: () => `${formatter.number(args.count)} characters remaining`
9
+ })}`,
10
+ "combobox.loadingLabel": `Loading…`,
11
+ "select.selectedCount": (args, formatter) => `${formatter.plural(args.count, { other: () => `${formatter.number(args.count)} selected` })}`,
12
+ "autocomplete.clear": `Clear`,
13
+ "autocomplete.loading": `Loading…`,
14
+ "autocomplete.searching": `Searching…`,
15
+ "autocomplete.noResults": `No results for`,
16
+ "autocomplete.create": `Use`,
17
+ "toast.close": `Close`,
18
+ "toast.loading": `Loading`,
19
+ "toast.notifications": (args, formatter) => `${formatter.plural(args.count, {
20
+ one: () => `${formatter.number(args.count)} notification`,
21
+ other: () => `${formatter.number(args.count)} notifications`
22
+ })}.`,
23
+ "toast.viewport": `Notifications`,
24
+ "slider.minimum": `Minimum`,
25
+ "slider.maximum": `Maximum`,
26
+ "slider.startRange": `start range`,
27
+ "slider.endRange": `end range`,
28
+ "colorPicker.field": `Saturation and brightness`,
29
+ "colorPicker.hue": `Hue`,
30
+ "colorPicker.alpha": `Alpha`,
31
+ "colorPicker.swatch": `Selected color`,
32
+ "colorPicker.eyeDropper": `Pick a color from the screen`,
33
+ "colorPicker.format": `Color format`,
34
+ "colorPicker.value": `Color value`,
35
+ "searchDialog.title": `Search`,
36
+ "searchDialog.placeholder": `Search…`,
37
+ "searchDialog.emptyLabel": `Type to search…`,
38
+ "searchDialog.loadingLabel": `Loading search…`,
39
+ "searchDialog.searchingLabel": `Searching…`,
40
+ "searchDialog.noResultsLabel": `No results for`,
41
+ "searchDialog.navigateLabel": `Navigate`,
42
+ "searchDialog.openLabel": `Open`,
43
+ "searchDialog.closeLabel": `Close`,
44
+ "code.copy": `Copy`,
45
+ "code.copied": `Copied`,
46
+ "code.packageManager": `Package manager`,
47
+ "meter.valueText": (args, formatter) => `${args.value} — ${formatter.select({
48
+ success: `healthy`,
49
+ warning: `warning`,
50
+ danger: `critical`,
51
+ other: ``
52
+ }, args.status)}`,
53
+ "menubar.moreMenus": `More menus`,
54
+ "dialog.closeLabel": `Close`,
55
+ "sheet.closeLabel": `Close`,
56
+ "rail.closeLabel": `Close`,
57
+ "avatar.presence.online": `Online`,
58
+ "avatar.presence.busy": `Busy`,
59
+ "avatar.presence.focus": `In focus`,
60
+ "avatar.presence.away": `Away`,
61
+ "avatar.presence.offline": `Offline`,
62
+ "avatar.status.approved": `Approved`,
63
+ "avatar.status.declined": `Declined`,
64
+ "avatar.status.locked": `Locked`,
65
+ "avatar.overflowLabel": (args, formatter) => `${formatter.plural(args.count, { other: () => `${formatter.number(args.count)} more members` })}`
66
+ };
67
+ //#endregion
68
+ export { messages as default };
@@ -0,0 +1,6 @@
1
+ import { LocalizedString } from "../string/LocalizedStringFormatter.js";
2
+
3
+ //#region src/messages/fa.d.ts
4
+ declare const messages: Record<string, LocalizedString>;
5
+ //#endregion
6
+ export { messages as default };
@@ -0,0 +1,68 @@
1
+ //#region src/messages/fa.ts
2
+ const messages = {
3
+ "numberField.increase": `افزایش`,
4
+ "numberField.decrease": `کاهش`,
5
+ "numberField.numberField": `فیلد عددی`,
6
+ "field.charactersRemaining": (args, formatter) => `${formatter.plural(args.count, {
7
+ one: () => `${formatter.number(args.count)} نویسه باقی‌مانده`,
8
+ other: () => `${formatter.number(args.count)} نویسه باقی‌مانده`
9
+ })}`,
10
+ "combobox.loadingLabel": `در حال بارگذاری…`,
11
+ "select.selectedCount": (args, formatter) => `${formatter.plural(args.count, { other: () => `${formatter.number(args.count)} انتخاب‌شده` })}`,
12
+ "autocomplete.clear": `پاک کردن`,
13
+ "autocomplete.loading": `در حال بارگذاری…`,
14
+ "autocomplete.searching": `در حال جستجو…`,
15
+ "autocomplete.noResults": `نتیجه‌ای یافت نشد برای`,
16
+ "autocomplete.create": `استفاده از`,
17
+ "toast.close": `بستن`,
18
+ "toast.loading": `در حال بارگذاری`,
19
+ "toast.notifications": (args, formatter) => `${formatter.plural(args.count, {
20
+ one: () => `${formatter.number(args.count)} اعلان`,
21
+ other: () => `${formatter.number(args.count)} اعلان`
22
+ })}.`,
23
+ "toast.viewport": `اعلان‌ها`,
24
+ "slider.minimum": `کمینه`,
25
+ "slider.maximum": `بیشینه`,
26
+ "slider.startRange": `شروع محدوده`,
27
+ "slider.endRange": `پایان محدوده`,
28
+ "colorPicker.field": `اشباع و روشنایی`,
29
+ "colorPicker.hue": `رنگ‌مایه`,
30
+ "colorPicker.alpha": `شفافیت`,
31
+ "colorPicker.swatch": `رنگ انتخاب‌شده`,
32
+ "colorPicker.eyeDropper": `انتخاب رنگ از صفحه`,
33
+ "colorPicker.format": `قالب رنگ`,
34
+ "colorPicker.value": `مقدار رنگ`,
35
+ "searchDialog.title": `جستجو`,
36
+ "searchDialog.placeholder": `جستجو…`,
37
+ "searchDialog.emptyLabel": `برای جستجوی مستندات تایپ کنید.`,
38
+ "searchDialog.loadingLabel": `در حال بارگذاری جستجو…`,
39
+ "searchDialog.searchingLabel": `در حال جستجو…`,
40
+ "searchDialog.noResultsLabel": `نتیجه‌ای یافت نشد:`,
41
+ "searchDialog.navigateLabel": `جابجایی`,
42
+ "searchDialog.openLabel": `باز کردن`,
43
+ "searchDialog.closeLabel": `بستن`,
44
+ "code.copy": `کپی`,
45
+ "code.copied": `کپی شد`,
46
+ "code.packageManager": `پکیج منیجر`,
47
+ "meter.valueText": (args, formatter) => `${args.value} — ${formatter.select({
48
+ success: `سالم`,
49
+ warning: `هشدار`,
50
+ danger: `بحرانی`,
51
+ other: ``
52
+ }, args.status)}`,
53
+ "menubar.moreMenus": `منوهای بیشتر`,
54
+ "dialog.closeLabel": `بستن`,
55
+ "sheet.closeLabel": `بستن`,
56
+ "rail.closeLabel": `بستن`,
57
+ "avatar.presence.online": `آنلاین`,
58
+ "avatar.presence.busy": `مشغول`,
59
+ "avatar.presence.focus": `در حال تمرکز`,
60
+ "avatar.presence.away": `غایب`,
61
+ "avatar.presence.offline": `آفلاین`,
62
+ "avatar.status.approved": `تأییدشده`,
63
+ "avatar.status.declined": `ردشده`,
64
+ "avatar.status.locked": `قفل‌شده`,
65
+ "avatar.overflowLabel": (args, formatter) => `${formatter.plural(args.count, { other: () => `${formatter.number(args.count)} عضو دیگر` })}`
66
+ };
67
+ //#endregion
68
+ export { messages as default };