generaltranslation 8.2.7 → 8.2.9

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 (60) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/{ApiError-4zIP-twr.cjs → ApiError-CZ45tkW6.cjs} +1 -1
  3. package/dist/{ApiError-4zIP-twr.cjs.map → ApiError-CZ45tkW6.cjs.map} +1 -1
  4. package/dist/{ApiError-Bv7vlzyQ.mjs → ApiError-IYfaOR30.mjs} +1 -1
  5. package/dist/{ApiError-Bv7vlzyQ.mjs.map → ApiError-IYfaOR30.mjs.map} +1 -1
  6. package/dist/IntlCache-Ccg_cQPR.mjs +195 -0
  7. package/dist/IntlCache-Ccg_cQPR.mjs.map +1 -0
  8. package/dist/IntlCache-k2qfrDqB.cjs +212 -0
  9. package/dist/IntlCache-k2qfrDqB.cjs.map +1 -0
  10. package/dist/base64-C1sogiix.mjs +70 -0
  11. package/dist/base64-C1sogiix.mjs.map +1 -0
  12. package/dist/base64-CUcEPEC5.cjs +111 -0
  13. package/dist/base64-CUcEPEC5.cjs.map +1 -0
  14. package/dist/core-CJMv4fMa.d.cts +209 -0
  15. package/dist/core-DOrYXXpO.mjs +1487 -0
  16. package/dist/core-DOrYXXpO.mjs.map +1 -0
  17. package/dist/core-DtPj_ruw.d.mts +209 -0
  18. package/dist/core-LS3Pia40.cjs +1666 -0
  19. package/dist/core-LS3Pia40.cjs.map +1 -0
  20. package/dist/core.cjs +8 -0
  21. package/dist/core.d.cts +2 -0
  22. package/dist/core.d.mts +2 -0
  23. package/dist/core.mjs +2 -0
  24. package/dist/errors.cjs +1 -1
  25. package/dist/errors.mjs +1 -1
  26. package/dist/{id-CPbVYREY.mjs → id-BmOyfaug.mjs} +2 -2
  27. package/dist/{id-CPbVYREY.mjs.map → id-BmOyfaug.mjs.map} +1 -1
  28. package/dist/{id-VXBgyXu2.cjs → id-COlX5v3V.cjs} +6 -6
  29. package/dist/{id-VXBgyXu2.cjs.map → id-COlX5v3V.cjs.map} +1 -1
  30. package/dist/id.cjs +1 -1
  31. package/dist/id.d.cts +1 -1
  32. package/dist/id.d.mts +1 -1
  33. package/dist/id.mjs +1 -1
  34. package/dist/index.cjs +91 -1413
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +7 -103
  37. package/dist/index.d.mts +7 -103
  38. package/dist/index.mjs +43 -1342
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/internal.cjs +602 -42
  41. package/dist/internal.cjs.map +1 -0
  42. package/dist/internal.d.cts +23 -2
  43. package/dist/internal.d.mts +23 -2
  44. package/dist/internal.mjs +563 -3
  45. package/dist/internal.mjs.map +1 -0
  46. package/dist/{sha2-DKowBr6H.cjs → isVariable-B08mggBy.cjs} +18 -18
  47. package/dist/isVariable-B08mggBy.cjs.map +1 -0
  48. package/dist/{stableStringify-DgDlE_pD.mjs → isVariable-CYsKFHvR.mjs} +19 -19
  49. package/dist/isVariable-CYsKFHvR.mjs.map +1 -0
  50. package/dist/{types-fUW4_Ole.d.mts → types-Dfy_sRLD.d.mts} +6 -2
  51. package/dist/{types-D2fTTTvZ.d.cts → types-mZeu4HS3.d.cts} +6 -2
  52. package/dist/types.d.cts +1 -1
  53. package/dist/types.d.mts +1 -1
  54. package/package.json +17 -1
  55. package/dist/internal-CTeI8uLd.mjs +0 -774
  56. package/dist/internal-CTeI8uLd.mjs.map +0 -1
  57. package/dist/internal-PCKq4YMW.cjs +0 -1012
  58. package/dist/internal-PCKq4YMW.cjs.map +0 -1
  59. package/dist/sha2-DKowBr6H.cjs.map +0 -1
  60. package/dist/stableStringify-DgDlE_pD.mjs.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # generaltranslation
2
2
 
3
+ ## 8.2.9
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1278](https://github.com/generaltranslation/gt/pull/1278) [`ce0933a`](https://github.com/generaltranslation/gt/commit/ce0933ab102d34a0c38634f7c2b0d634c9a620a8) Thanks [@bgub](https://github.com/bgub)! - Add a `generaltranslation/core` entrypoint for locale and formatting helpers, and update `gt-i18n` to consume it where possible.
8
+
9
+ ## 8.2.8
10
+
11
+ ### Patch Changes
12
+
13
+ - [#1248](https://github.com/generaltranslation/gt/pull/1248) [`b12d57d`](https://github.com/generaltranslation/gt/commit/b12d57dab1d5cb1f602c5ac24a702b48cda7f11e) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Add PO/POT file format support and transformFormat plumbing for API uploads and CLI file downloads.
14
+
3
15
  ## 8.2.7
4
16
 
5
17
  ### Patch Changes
@@ -21,4 +21,4 @@ Object.defineProperty(exports, "ApiError", {
21
21
  }
22
22
  });
23
23
 
24
- //# sourceMappingURL=ApiError-4zIP-twr.cjs.map
24
+ //# sourceMappingURL=ApiError-CZ45tkW6.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ApiError-4zIP-twr.cjs","names":[],"sources":["../src/errors/ApiError.ts"],"sourcesContent":["export class ApiError extends Error {\n public code: number;\n public message: string;\n\n constructor(error: string, code: number, message: string) {\n super(error);\n this.name = 'ApiError';\n this.code = code;\n this.message = message;\n }\n\n getCode() {\n return this.code;\n }\n\n getMessage() {\n return this.message;\n }\n}\n"],"mappings":";AAAA,IAAa,WAAb,cAA8B,MAAM;CAIlC,YAAY,OAAe,MAAc,SAAiB;AACxD,QAAM,MAAM;AACZ,OAAK,OAAO;AACZ,OAAK,OAAO;AACZ,OAAK,UAAU;;CAGjB,UAAU;AACR,SAAO,KAAK;;CAGd,aAAa;AACX,SAAO,KAAK"}
1
+ {"version":3,"file":"ApiError-CZ45tkW6.cjs","names":[],"sources":["../src/errors/ApiError.ts"],"sourcesContent":["export class ApiError extends Error {\n public code: number;\n public message: string;\n\n constructor(error: string, code: number, message: string) {\n super(error);\n this.name = 'ApiError';\n this.code = code;\n this.message = message;\n }\n\n getCode() {\n return this.code;\n }\n\n getMessage() {\n return this.message;\n }\n}\n"],"mappings":";AAAA,IAAa,WAAb,cAA8B,MAAM;CAIlC,YAAY,OAAe,MAAc,SAAiB;AACxD,QAAM,MAAM;AACZ,OAAK,OAAO;AACZ,OAAK,OAAO;AACZ,OAAK,UAAU;;CAGjB,UAAU;AACR,SAAO,KAAK;;CAGd,aAAa;AACX,SAAO,KAAK"}
@@ -16,4 +16,4 @@ var ApiError = class extends Error {
16
16
  //#endregion
17
17
  export { ApiError as t };
18
18
 
19
- //# sourceMappingURL=ApiError-Bv7vlzyQ.mjs.map
19
+ //# sourceMappingURL=ApiError-IYfaOR30.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ApiError-Bv7vlzyQ.mjs","names":[],"sources":["../src/errors/ApiError.ts"],"sourcesContent":["export class ApiError extends Error {\n public code: number;\n public message: string;\n\n constructor(error: string, code: number, message: string) {\n super(error);\n this.name = 'ApiError';\n this.code = code;\n this.message = message;\n }\n\n getCode() {\n return this.code;\n }\n\n getMessage() {\n return this.message;\n }\n}\n"],"mappings":";AAAA,IAAa,WAAb,cAA8B,MAAM;CAIlC,YAAY,OAAe,MAAc,SAAiB;AACxD,QAAM,MAAM;AACZ,OAAK,OAAO;AACZ,OAAK,OAAO;AACZ,OAAK,UAAU;;CAGjB,UAAU;AACR,SAAO,KAAK;;CAGd,aAAa;AACX,SAAO,KAAK"}
1
+ {"version":3,"file":"ApiError-IYfaOR30.mjs","names":[],"sources":["../src/errors/ApiError.ts"],"sourcesContent":["export class ApiError extends Error {\n public code: number;\n public message: string;\n\n constructor(error: string, code: number, message: string) {\n super(error);\n this.name = 'ApiError';\n this.code = code;\n this.message = message;\n }\n\n getCode() {\n return this.code;\n }\n\n getMessage() {\n return this.message;\n }\n}\n"],"mappings":";AAAA,IAAa,WAAb,cAA8B,MAAM;CAIlC,YAAY,OAAe,MAAc,SAAiB;AACxD,QAAM,MAAM;AACZ,OAAK,OAAO;AACZ,OAAK,OAAO;AACZ,OAAK,UAAU;;CAGjB,UAAU;AACR,SAAO,KAAK;;CAGd,aAAa;AACX,SAAO,KAAK"}
@@ -0,0 +1,195 @@
1
+ //#region src/settings/settings.ts
2
+ const libraryDefaultLocale = "en";
3
+ const defaultTimeout = 6e4;
4
+ //#endregion
5
+ //#region src/errors/formattingErrors.ts
6
+ const createInvalidCutoffStyleError = (style) => `generaltranslation Formatting Error: Invalid cutoff style: ${style}.`;
7
+ const DEFAULT_TERMINATOR_KEY = "DEFAULT_TERMINATOR_KEY";
8
+ const TERMINATOR_MAP = {
9
+ ellipsis: {
10
+ fr: {
11
+ terminator: "…",
12
+ separator: " "
13
+ },
14
+ zh: {
15
+ terminator: "……",
16
+ separator: void 0
17
+ },
18
+ ja: {
19
+ terminator: "……",
20
+ separator: void 0
21
+ },
22
+ [DEFAULT_TERMINATOR_KEY]: {
23
+ terminator: "…",
24
+ separator: void 0
25
+ }
26
+ },
27
+ none: { [DEFAULT_TERMINATOR_KEY]: {
28
+ terminator: void 0,
29
+ separator: void 0
30
+ } }
31
+ };
32
+ //#endregion
33
+ //#region src/formatting/custom-formats/CutoffFormat/CutoffFormat.ts
34
+ var CutoffFormatConstructor = class {
35
+ /**
36
+ * Constructor
37
+ * @param {string | string[]} locales - The locales to use for formatting.
38
+ * @param {CutoffFormatOptions} options - The options for formatting.
39
+ * @param {number} [option.maxChars] - The maximum number of characters to display.
40
+ * - Undefined values are treated as no cutoff.
41
+ * - Negative values follow .slice() behavior and terminator will be added before the value.
42
+ * - 0 will result in an empty string.
43
+ * - If cutoff results in an empty string, no terminator is added.
44
+ * @param {CutoffFormatStyle} [option.style='ellipsis'] - The style of the terminator.
45
+ * @param {string} [option.terminator] - Optional override the terminator to use.
46
+ * @param {string} [option.separator] - Optional override the separator to use between the terminator and the value.
47
+ * - If no terminator is provided, then separator is ignored.
48
+ *
49
+ * @example
50
+ * const format = new CutoffFormat('en', { maxChars: 5 });
51
+ * format.format('Hello, world!'); // 'Hello...'
52
+ *
53
+ * const format = new CutoffFormat('en', { maxChars: -3 });
54
+ * format.format('Hello, world!'); // '...ld!'
55
+ */
56
+ constructor(locales, options = {}) {
57
+ try {
58
+ const localesList = !locales ? ["en"] : Array.isArray(locales) ? locales.map((l) => String(l)) : [String(locales)];
59
+ const canonicalLocales = Intl.getCanonicalLocales(localesList);
60
+ this.locale = canonicalLocales.length ? canonicalLocales[0] : "en";
61
+ } catch {
62
+ this.locale = "en";
63
+ }
64
+ if (!TERMINATOR_MAP[options.style ?? "ellipsis"]) throw new Error(createInvalidCutoffStyleError(options.style ?? "ellipsis"));
65
+ let style;
66
+ let presetTerminatorOptions;
67
+ if (options.maxChars !== void 0) {
68
+ style = options.style ?? "ellipsis";
69
+ const languageCode = new Intl.Locale(this.locale).language;
70
+ presetTerminatorOptions = TERMINATOR_MAP[style][languageCode] || TERMINATOR_MAP[style]["DEFAULT_TERMINATOR_KEY"];
71
+ }
72
+ let terminator = options.terminator ?? presetTerminatorOptions?.terminator;
73
+ let separator = terminator != null ? options.separator ?? presetTerminatorOptions?.separator : void 0;
74
+ this.additionLength = (terminator?.length ?? 0) + (separator?.length ?? 0);
75
+ if (options.maxChars !== void 0 && Math.abs(options.maxChars) < this.additionLength) {
76
+ terminator = void 0;
77
+ separator = void 0;
78
+ }
79
+ this.options = {
80
+ maxChars: options.maxChars,
81
+ style,
82
+ terminator,
83
+ separator
84
+ };
85
+ }
86
+ /**
87
+ * Format a value according to the cutoff options, returning a formatted string.
88
+ *
89
+ * @param {string} value - The string value to format with cutoff behavior.
90
+ * @returns {string} The formatted string with terminator applied if cutoff occurs.
91
+ *
92
+ * @example
93
+ * const formatter = new CutoffFormatConstructor('en', { maxChars: 8, style: 'ellipsis' });
94
+ * formatter.format('Hello, world!'); // Returns 'Hello, w...'
95
+ */
96
+ format(value) {
97
+ return this.formatToParts(value).join("");
98
+ }
99
+ /**
100
+ * Format a value to parts according to the cutoff options, returning an array of string parts.
101
+ * This method breaks down the formatted result into individual components for more granular control.
102
+ *
103
+ * @param {string} value - The string value to format with cutoff behavior.
104
+ * @returns {PrependedCutoffParts | PostpendedCutoffParts} An array of string parts representing the formatted result.
105
+ * - For positive maxChars: [cutoffValue, separator?, terminator?]
106
+ * - For negative maxChars: [terminator?, separator?, cutoffValue]
107
+ * - For no cutoff: [originalValue]
108
+ *
109
+ * @example
110
+ * const formatter = new CutoffFormatConstructor('en', { maxChars: 5, style: 'ellipsis' });
111
+ * formatter.formatToParts('Hello, world!'); // Returns ['Hello', '...']
112
+ */
113
+ formatToParts(value) {
114
+ const { maxChars, terminator, separator } = this.options;
115
+ const adjustedChars = maxChars === void 0 || Math.abs(maxChars) >= value.length ? maxChars : maxChars >= 0 ? Math.max(0, maxChars - this.additionLength) : Math.min(0, maxChars + this.additionLength);
116
+ const slicedValue = adjustedChars !== void 0 && adjustedChars > -1 ? value.slice(0, adjustedChars) : value.slice(adjustedChars);
117
+ if (maxChars == null || adjustedChars == null || adjustedChars === 0 || terminator == null || value.length <= Math.abs(maxChars)) return [slicedValue];
118
+ if (adjustedChars > 0) return separator != null ? [
119
+ slicedValue,
120
+ separator,
121
+ terminator
122
+ ] : [slicedValue, terminator];
123
+ else return separator != null ? [
124
+ terminator,
125
+ separator,
126
+ slicedValue
127
+ ] : [terminator, slicedValue];
128
+ }
129
+ /**
130
+ * Get the resolved options
131
+ * @returns {ResolvedCutoffFormatOptions} The resolved options.
132
+ */
133
+ resolvedOptions() {
134
+ return this.options;
135
+ }
136
+ };
137
+ //#endregion
138
+ //#region src/cache/IntlCache.ts
139
+ /**
140
+ * Object mapping constructor names to their respective constructor functions
141
+ * Includes all native Intl constructors plus custom ones like CutoffFormat
142
+ */
143
+ const CustomIntl = {
144
+ Collator: Intl.Collator,
145
+ DateTimeFormat: Intl.DateTimeFormat,
146
+ DisplayNames: Intl.DisplayNames,
147
+ ListFormat: Intl.ListFormat,
148
+ Locale: Intl.Locale,
149
+ NumberFormat: Intl.NumberFormat,
150
+ PluralRules: Intl.PluralRules,
151
+ RelativeTimeFormat: Intl.RelativeTimeFormat,
152
+ Segmenter: Intl.Segmenter,
153
+ CutoffFormat: CutoffFormatConstructor
154
+ };
155
+ /**
156
+ * Cache for Intl and custom format instances to avoid repeated instantiation
157
+ * Uses a two-level structure: constructor name -> cache key -> instance
158
+ */
159
+ var IntlCache = class {
160
+ constructor() {
161
+ this.cache = {};
162
+ }
163
+ /**
164
+ * Generates a consistent cache key from locales and options
165
+ * Handles all LocalesArgument types (string, Locale, array, undefined)
166
+ */
167
+ _generateKey(locales, options = {}) {
168
+ return `${!locales ? "undefined" : Array.isArray(locales) ? locales.map((l) => String(l)).join(",") : String(locales)}:${options ? JSON.stringify(options, Object.keys(options).sort()) : "{}"}`;
169
+ }
170
+ /**
171
+ * Gets a cached Intl instance or creates a new one if not found
172
+ * @param constructor The name of the Intl constructor to use
173
+ * @param args Constructor arguments (locales, options)
174
+ * @returns Cached or newly created Intl instance
175
+ */
176
+ get(constructor, ...args) {
177
+ const [locales = "en", options = {}] = args;
178
+ const key = this._generateKey(locales, options);
179
+ let intlObject = this.cache[constructor]?.[key];
180
+ if (intlObject === void 0) {
181
+ intlObject = new CustomIntl[constructor](...args);
182
+ if (!this.cache[constructor]) this.cache[constructor] = {};
183
+ this.cache[constructor][key] = intlObject;
184
+ }
185
+ return intlObject;
186
+ }
187
+ };
188
+ /**
189
+ * Global instance of the Intl cache for use throughout the application
190
+ */
191
+ const intlCache = new IntlCache();
192
+ //#endregion
193
+ export { defaultTimeout as n, libraryDefaultLocale as r, intlCache as t };
194
+
195
+ //# sourceMappingURL=IntlCache-Ccg_cQPR.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IntlCache-Ccg_cQPR.mjs","names":[],"sources":["../src/settings/settings.ts","../src/errors/formattingErrors.ts","../src/formatting/custom-formats/CutoffFormat/constants.ts","../src/formatting/custom-formats/CutoffFormat/CutoffFormat.ts","../src/cache/IntlCache.ts"],"sourcesContent":["export const libraryDefaultLocale = 'en' as const;\nexport const defaultTimeout = 60000;\n","export const createInvalidCutoffStyleError = (style: string) =>\n `generaltranslation Formatting Error: Invalid cutoff style: ${style}.`;\n","import { CutoffFormatStyle, ResolvedTerminatorOptions } from './types';\n\nexport const DEFAULT_CUTOFF_FORMAT_STYLE: CutoffFormatStyle = 'ellipsis';\n\nexport const DEFAULT_TERMINATOR_KEY = 'DEFAULT_TERMINATOR_KEY';\n\nexport const TERMINATOR_MAP: Record<\n CutoffFormatStyle,\n Record<string | typeof DEFAULT_TERMINATOR_KEY, ResolvedTerminatorOptions>\n> = {\n ellipsis: {\n fr: {\n terminator: '…',\n separator: '\\u202F',\n },\n zh: {\n terminator: '……',\n separator: undefined,\n },\n ja: {\n terminator: '……',\n separator: undefined,\n },\n [DEFAULT_TERMINATOR_KEY]: {\n terminator: '…',\n separator: undefined,\n },\n },\n none: {\n [DEFAULT_TERMINATOR_KEY]: {\n terminator: undefined,\n separator: undefined,\n },\n },\n};\n","import { createInvalidCutoffStyleError } from '../../../errors/formattingErrors';\nimport { libraryDefaultLocale } from '../../../settings/settings';\nimport {\n DEFAULT_CUTOFF_FORMAT_STYLE,\n DEFAULT_TERMINATOR_KEY,\n TERMINATOR_MAP,\n} from './constants';\nimport {\n CutoffFormat,\n CutoffFormatOptions,\n CutoffFormatStyle,\n PostpendedCutoffParts,\n PrependedCutoffParts,\n ResolvedCutoffFormatOptions,\n ResolvedTerminatorOptions,\n} from './types';\n\nexport class CutoffFormatConstructor implements CutoffFormat {\n private locale: string;\n private options: ResolvedCutoffFormatOptions;\n private additionLength: number;\n /**\n * Constructor\n * @param {string | string[]} locales - The locales to use for formatting.\n * @param {CutoffFormatOptions} options - The options for formatting.\n * @param {number} [option.maxChars] - The maximum number of characters to display.\n * - Undefined values are treated as no cutoff.\n * - Negative values follow .slice() behavior and terminator will be added before the value.\n * - 0 will result in an empty string.\n * - If cutoff results in an empty string, no terminator is added.\n * @param {CutoffFormatStyle} [option.style='ellipsis'] - The style of the terminator.\n * @param {string} [option.terminator] - Optional override the terminator to use.\n * @param {string} [option.separator] - Optional override the separator to use between the terminator and the value.\n * - If no terminator is provided, then separator is ignored.\n *\n * @example\n * const format = new CutoffFormat('en', { maxChars: 5 });\n * format.format('Hello, world!'); // 'Hello...'\n *\n * const format = new CutoffFormat('en', { maxChars: -3 });\n * format.format('Hello, world!'); // '...ld!'\n */\n constructor(\n locales: Intl.LocalesArgument,\n options: CutoffFormatOptions = {}\n ) {\n // Determine locale (this replicates Intl.NumberFormat behavior including silent failure)\n try {\n // Normalize locales to string\n const localesList = !locales\n ? [libraryDefaultLocale]\n : Array.isArray(locales)\n ? locales.map((l) => String(l))\n : [String(locales)];\n const canonicalLocales = Intl.getCanonicalLocales(localesList);\n this.locale = canonicalLocales.length\n ? canonicalLocales[0]\n : libraryDefaultLocale;\n } catch {\n this.locale = libraryDefaultLocale;\n }\n\n // Follows Intl.NumberFormat behavior of throwing an error when currency is invalid\n if (!TERMINATOR_MAP[options.style ?? DEFAULT_CUTOFF_FORMAT_STYLE]) {\n throw new Error(\n createInvalidCutoffStyleError(\n options.style ?? DEFAULT_CUTOFF_FORMAT_STYLE\n )\n );\n }\n\n // Resolve terminator options\n let style: CutoffFormatStyle | undefined;\n let presetTerminatorOptions: ResolvedTerminatorOptions | undefined;\n if (options.maxChars !== undefined) {\n style = options.style ?? DEFAULT_CUTOFF_FORMAT_STYLE;\n // TODO: need more sophisticated locale negotiation if we want to add support for region/script/etc.-specific terminators in the future\n const languageCode = new Intl.Locale(this.locale).language;\n presetTerminatorOptions =\n TERMINATOR_MAP[style][languageCode] ||\n TERMINATOR_MAP[style][DEFAULT_TERMINATOR_KEY];\n }\n let terminator: ResolvedTerminatorOptions['terminator'] =\n options.terminator ?? presetTerminatorOptions?.terminator;\n let separator: ResolvedTerminatorOptions['separator'] =\n terminator != null\n ? (options.separator ?? presetTerminatorOptions?.separator)\n : undefined;\n // // Remove terminator and separator if maxChars does have enough space\n this.additionLength = (terminator?.length ?? 0) + (separator?.length ?? 0);\n if (\n options.maxChars !== undefined &&\n Math.abs(options.maxChars) < this.additionLength\n ) {\n terminator = undefined;\n separator = undefined;\n }\n\n this.options = {\n maxChars: options.maxChars,\n style,\n terminator,\n separator,\n };\n }\n\n /**\n * Format a value according to the cutoff options, returning a formatted string.\n *\n * @param {string} value - The string value to format with cutoff behavior.\n * @returns {string} The formatted string with terminator applied if cutoff occurs.\n *\n * @example\n * const formatter = new CutoffFormatConstructor('en', { maxChars: 8, style: 'ellipsis' });\n * formatter.format('Hello, world!'); // Returns 'Hello, w...'\n */\n format(value: string): string {\n return this.formatToParts(value).join('');\n }\n\n /**\n * Format a value to parts according to the cutoff options, returning an array of string parts.\n * This method breaks down the formatted result into individual components for more granular control.\n *\n * @param {string} value - The string value to format with cutoff behavior.\n * @returns {PrependedCutoffParts | PostpendedCutoffParts} An array of string parts representing the formatted result.\n * - For positive maxChars: [cutoffValue, separator?, terminator?]\n * - For negative maxChars: [terminator?, separator?, cutoffValue]\n * - For no cutoff: [originalValue]\n *\n * @example\n * const formatter = new CutoffFormatConstructor('en', { maxChars: 5, style: 'ellipsis' });\n * formatter.formatToParts('Hello, world!'); // Returns ['Hello', '...']\n */\n formatToParts(value: string): PrependedCutoffParts | PostpendedCutoffParts {\n const { maxChars, terminator, separator } = this.options;\n\n // Slice our value\n // const additionLength = (terminator?.length ?? 0) + (separator?.length ?? 0);\n const adjustedChars =\n maxChars === undefined || Math.abs(maxChars) >= value.length\n ? maxChars\n : maxChars >= 0\n ? Math.max(0, maxChars - this.additionLength)\n : Math.min(0, maxChars + this.additionLength);\n const slicedValue =\n adjustedChars !== undefined && adjustedChars > -1\n ? value.slice(0, adjustedChars)\n : value.slice(adjustedChars);\n\n // No cutoff, no terminator -> value only\n if (\n maxChars == null ||\n adjustedChars == null ||\n adjustedChars === 0 ||\n terminator == null ||\n value.length <= Math.abs(maxChars)\n ) {\n return [slicedValue];\n }\n\n // Postpended cutoff\n if (adjustedChars > 0) {\n return separator != null\n ? [slicedValue, separator, terminator]\n : [slicedValue, terminator];\n }\n // Prepended cutoff\n else {\n return separator != null\n ? [terminator, separator, slicedValue]\n : [terminator, slicedValue];\n }\n }\n\n /**\n * Get the resolved options\n * @returns {ResolvedCutoffFormatOptions} The resolved options.\n */\n resolvedOptions(): ResolvedCutoffFormatOptions {\n return this.options;\n }\n}\n","import { libraryDefaultLocale } from '../settings/settings';\nimport { CutoffFormatConstructor } from '../formatting/custom-formats/CutoffFormat/CutoffFormat';\nimport {\n ConstructorType,\n CustomIntlConstructors,\n CustomIntlType,\n IntlCacheObject,\n} from './types';\n\n/**\n * Object mapping constructor names to their respective constructor functions\n * Includes all native Intl constructors plus custom ones like CutoffFormat\n */\nconst CustomIntl: CustomIntlType = {\n Collator: Intl.Collator,\n DateTimeFormat: Intl.DateTimeFormat,\n DisplayNames: Intl.DisplayNames,\n ListFormat: Intl.ListFormat,\n Locale: Intl.Locale,\n NumberFormat: Intl.NumberFormat,\n PluralRules: Intl.PluralRules,\n RelativeTimeFormat: Intl.RelativeTimeFormat,\n Segmenter: Intl.Segmenter,\n CutoffFormat: CutoffFormatConstructor,\n};\n\n/**\n * Cache for Intl and custom format instances to avoid repeated instantiation\n * Uses a two-level structure: constructor name -> cache key -> instance\n */\nclass IntlCache {\n private cache: IntlCacheObject;\n\n constructor() {\n this.cache = {};\n }\n\n /**\n * Generates a consistent cache key from locales and options\n * Handles all LocalesArgument types (string, Locale, array, undefined)\n */\n private _generateKey(locales: Intl.LocalesArgument, options = {}) {\n // Normalize locales to string representation\n const localeKey = !locales\n ? 'undefined'\n : Array.isArray(locales)\n ? locales.map((l) => String(l)).join(',')\n : String(locales);\n\n // Sort option keys to ensure consistent key generation regardless of property order\n const sortedOptions = options\n ? JSON.stringify(options, Object.keys(options).sort())\n : '{}';\n return `${localeKey}:${sortedOptions}`;\n }\n\n /**\n * Gets a cached Intl instance or creates a new one if not found\n * @param constructor The name of the Intl constructor to use\n * @param args Constructor arguments (locales, options)\n * @returns Cached or newly created Intl instance\n */\n get<K extends keyof CustomIntlConstructors>(\n constructor: K,\n ...args: ConstructorParameters<CustomIntlConstructors[K]>\n ): InstanceType<ConstructorType<K>> {\n const [locales = libraryDefaultLocale, options = {}] = args;\n const key = this._generateKey(locales, options);\n let intlObject = this.cache[constructor]?.[key];\n\n if (intlObject === undefined) {\n // Create new instance and cache it\n intlObject = new CustomIntl[constructor](...args);\n if (!this.cache[constructor]) this.cache[constructor] = {};\n this.cache[constructor][key] = intlObject;\n }\n\n return intlObject;\n }\n}\n\n/**\n * Global instance of the Intl cache for use throughout the application\n */\nexport const intlCache = new IntlCache();\n"],"mappings":"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"}
@@ -0,0 +1,212 @@
1
+ //#region src/settings/settings.ts
2
+ const libraryDefaultLocale = "en";
3
+ const defaultTimeout = 6e4;
4
+ //#endregion
5
+ //#region src/errors/formattingErrors.ts
6
+ const createInvalidCutoffStyleError = (style) => `generaltranslation Formatting Error: Invalid cutoff style: ${style}.`;
7
+ const DEFAULT_TERMINATOR_KEY = "DEFAULT_TERMINATOR_KEY";
8
+ const TERMINATOR_MAP = {
9
+ ellipsis: {
10
+ fr: {
11
+ terminator: "…",
12
+ separator: " "
13
+ },
14
+ zh: {
15
+ terminator: "……",
16
+ separator: void 0
17
+ },
18
+ ja: {
19
+ terminator: "……",
20
+ separator: void 0
21
+ },
22
+ [DEFAULT_TERMINATOR_KEY]: {
23
+ terminator: "…",
24
+ separator: void 0
25
+ }
26
+ },
27
+ none: { [DEFAULT_TERMINATOR_KEY]: {
28
+ terminator: void 0,
29
+ separator: void 0
30
+ } }
31
+ };
32
+ //#endregion
33
+ //#region src/formatting/custom-formats/CutoffFormat/CutoffFormat.ts
34
+ var CutoffFormatConstructor = class {
35
+ /**
36
+ * Constructor
37
+ * @param {string | string[]} locales - The locales to use for formatting.
38
+ * @param {CutoffFormatOptions} options - The options for formatting.
39
+ * @param {number} [option.maxChars] - The maximum number of characters to display.
40
+ * - Undefined values are treated as no cutoff.
41
+ * - Negative values follow .slice() behavior and terminator will be added before the value.
42
+ * - 0 will result in an empty string.
43
+ * - If cutoff results in an empty string, no terminator is added.
44
+ * @param {CutoffFormatStyle} [option.style='ellipsis'] - The style of the terminator.
45
+ * @param {string} [option.terminator] - Optional override the terminator to use.
46
+ * @param {string} [option.separator] - Optional override the separator to use between the terminator and the value.
47
+ * - If no terminator is provided, then separator is ignored.
48
+ *
49
+ * @example
50
+ * const format = new CutoffFormat('en', { maxChars: 5 });
51
+ * format.format('Hello, world!'); // 'Hello...'
52
+ *
53
+ * const format = new CutoffFormat('en', { maxChars: -3 });
54
+ * format.format('Hello, world!'); // '...ld!'
55
+ */
56
+ constructor(locales, options = {}) {
57
+ try {
58
+ const localesList = !locales ? ["en"] : Array.isArray(locales) ? locales.map((l) => String(l)) : [String(locales)];
59
+ const canonicalLocales = Intl.getCanonicalLocales(localesList);
60
+ this.locale = canonicalLocales.length ? canonicalLocales[0] : "en";
61
+ } catch {
62
+ this.locale = "en";
63
+ }
64
+ if (!TERMINATOR_MAP[options.style ?? "ellipsis"]) throw new Error(createInvalidCutoffStyleError(options.style ?? "ellipsis"));
65
+ let style;
66
+ let presetTerminatorOptions;
67
+ if (options.maxChars !== void 0) {
68
+ style = options.style ?? "ellipsis";
69
+ const languageCode = new Intl.Locale(this.locale).language;
70
+ presetTerminatorOptions = TERMINATOR_MAP[style][languageCode] || TERMINATOR_MAP[style]["DEFAULT_TERMINATOR_KEY"];
71
+ }
72
+ let terminator = options.terminator ?? presetTerminatorOptions?.terminator;
73
+ let separator = terminator != null ? options.separator ?? presetTerminatorOptions?.separator : void 0;
74
+ this.additionLength = (terminator?.length ?? 0) + (separator?.length ?? 0);
75
+ if (options.maxChars !== void 0 && Math.abs(options.maxChars) < this.additionLength) {
76
+ terminator = void 0;
77
+ separator = void 0;
78
+ }
79
+ this.options = {
80
+ maxChars: options.maxChars,
81
+ style,
82
+ terminator,
83
+ separator
84
+ };
85
+ }
86
+ /**
87
+ * Format a value according to the cutoff options, returning a formatted string.
88
+ *
89
+ * @param {string} value - The string value to format with cutoff behavior.
90
+ * @returns {string} The formatted string with terminator applied if cutoff occurs.
91
+ *
92
+ * @example
93
+ * const formatter = new CutoffFormatConstructor('en', { maxChars: 8, style: 'ellipsis' });
94
+ * formatter.format('Hello, world!'); // Returns 'Hello, w...'
95
+ */
96
+ format(value) {
97
+ return this.formatToParts(value).join("");
98
+ }
99
+ /**
100
+ * Format a value to parts according to the cutoff options, returning an array of string parts.
101
+ * This method breaks down the formatted result into individual components for more granular control.
102
+ *
103
+ * @param {string} value - The string value to format with cutoff behavior.
104
+ * @returns {PrependedCutoffParts | PostpendedCutoffParts} An array of string parts representing the formatted result.
105
+ * - For positive maxChars: [cutoffValue, separator?, terminator?]
106
+ * - For negative maxChars: [terminator?, separator?, cutoffValue]
107
+ * - For no cutoff: [originalValue]
108
+ *
109
+ * @example
110
+ * const formatter = new CutoffFormatConstructor('en', { maxChars: 5, style: 'ellipsis' });
111
+ * formatter.formatToParts('Hello, world!'); // Returns ['Hello', '...']
112
+ */
113
+ formatToParts(value) {
114
+ const { maxChars, terminator, separator } = this.options;
115
+ const adjustedChars = maxChars === void 0 || Math.abs(maxChars) >= value.length ? maxChars : maxChars >= 0 ? Math.max(0, maxChars - this.additionLength) : Math.min(0, maxChars + this.additionLength);
116
+ const slicedValue = adjustedChars !== void 0 && adjustedChars > -1 ? value.slice(0, adjustedChars) : value.slice(adjustedChars);
117
+ if (maxChars == null || adjustedChars == null || adjustedChars === 0 || terminator == null || value.length <= Math.abs(maxChars)) return [slicedValue];
118
+ if (adjustedChars > 0) return separator != null ? [
119
+ slicedValue,
120
+ separator,
121
+ terminator
122
+ ] : [slicedValue, terminator];
123
+ else return separator != null ? [
124
+ terminator,
125
+ separator,
126
+ slicedValue
127
+ ] : [terminator, slicedValue];
128
+ }
129
+ /**
130
+ * Get the resolved options
131
+ * @returns {ResolvedCutoffFormatOptions} The resolved options.
132
+ */
133
+ resolvedOptions() {
134
+ return this.options;
135
+ }
136
+ };
137
+ //#endregion
138
+ //#region src/cache/IntlCache.ts
139
+ /**
140
+ * Object mapping constructor names to their respective constructor functions
141
+ * Includes all native Intl constructors plus custom ones like CutoffFormat
142
+ */
143
+ const CustomIntl = {
144
+ Collator: Intl.Collator,
145
+ DateTimeFormat: Intl.DateTimeFormat,
146
+ DisplayNames: Intl.DisplayNames,
147
+ ListFormat: Intl.ListFormat,
148
+ Locale: Intl.Locale,
149
+ NumberFormat: Intl.NumberFormat,
150
+ PluralRules: Intl.PluralRules,
151
+ RelativeTimeFormat: Intl.RelativeTimeFormat,
152
+ Segmenter: Intl.Segmenter,
153
+ CutoffFormat: CutoffFormatConstructor
154
+ };
155
+ /**
156
+ * Cache for Intl and custom format instances to avoid repeated instantiation
157
+ * Uses a two-level structure: constructor name -> cache key -> instance
158
+ */
159
+ var IntlCache = class {
160
+ constructor() {
161
+ this.cache = {};
162
+ }
163
+ /**
164
+ * Generates a consistent cache key from locales and options
165
+ * Handles all LocalesArgument types (string, Locale, array, undefined)
166
+ */
167
+ _generateKey(locales, options = {}) {
168
+ return `${!locales ? "undefined" : Array.isArray(locales) ? locales.map((l) => String(l)).join(",") : String(locales)}:${options ? JSON.stringify(options, Object.keys(options).sort()) : "{}"}`;
169
+ }
170
+ /**
171
+ * Gets a cached Intl instance or creates a new one if not found
172
+ * @param constructor The name of the Intl constructor to use
173
+ * @param args Constructor arguments (locales, options)
174
+ * @returns Cached or newly created Intl instance
175
+ */
176
+ get(constructor, ...args) {
177
+ const [locales = "en", options = {}] = args;
178
+ const key = this._generateKey(locales, options);
179
+ let intlObject = this.cache[constructor]?.[key];
180
+ if (intlObject === void 0) {
181
+ intlObject = new CustomIntl[constructor](...args);
182
+ if (!this.cache[constructor]) this.cache[constructor] = {};
183
+ this.cache[constructor][key] = intlObject;
184
+ }
185
+ return intlObject;
186
+ }
187
+ };
188
+ /**
189
+ * Global instance of the Intl cache for use throughout the application
190
+ */
191
+ const intlCache = new IntlCache();
192
+ //#endregion
193
+ Object.defineProperty(exports, "defaultTimeout", {
194
+ enumerable: true,
195
+ get: function() {
196
+ return defaultTimeout;
197
+ }
198
+ });
199
+ Object.defineProperty(exports, "intlCache", {
200
+ enumerable: true,
201
+ get: function() {
202
+ return intlCache;
203
+ }
204
+ });
205
+ Object.defineProperty(exports, "libraryDefaultLocale", {
206
+ enumerable: true,
207
+ get: function() {
208
+ return libraryDefaultLocale;
209
+ }
210
+ });
211
+
212
+ //# sourceMappingURL=IntlCache-k2qfrDqB.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IntlCache-k2qfrDqB.cjs","names":[],"sources":["../src/settings/settings.ts","../src/errors/formattingErrors.ts","../src/formatting/custom-formats/CutoffFormat/constants.ts","../src/formatting/custom-formats/CutoffFormat/CutoffFormat.ts","../src/cache/IntlCache.ts"],"sourcesContent":["export const libraryDefaultLocale = 'en' as const;\nexport const defaultTimeout = 60000;\n","export const createInvalidCutoffStyleError = (style: string) =>\n `generaltranslation Formatting Error: Invalid cutoff style: ${style}.`;\n","import { CutoffFormatStyle, ResolvedTerminatorOptions } from './types';\n\nexport const DEFAULT_CUTOFF_FORMAT_STYLE: CutoffFormatStyle = 'ellipsis';\n\nexport const DEFAULT_TERMINATOR_KEY = 'DEFAULT_TERMINATOR_KEY';\n\nexport const TERMINATOR_MAP: Record<\n CutoffFormatStyle,\n Record<string | typeof DEFAULT_TERMINATOR_KEY, ResolvedTerminatorOptions>\n> = {\n ellipsis: {\n fr: {\n terminator: '…',\n separator: '\\u202F',\n },\n zh: {\n terminator: '……',\n separator: undefined,\n },\n ja: {\n terminator: '……',\n separator: undefined,\n },\n [DEFAULT_TERMINATOR_KEY]: {\n terminator: '…',\n separator: undefined,\n },\n },\n none: {\n [DEFAULT_TERMINATOR_KEY]: {\n terminator: undefined,\n separator: undefined,\n },\n },\n};\n","import { createInvalidCutoffStyleError } from '../../../errors/formattingErrors';\nimport { libraryDefaultLocale } from '../../../settings/settings';\nimport {\n DEFAULT_CUTOFF_FORMAT_STYLE,\n DEFAULT_TERMINATOR_KEY,\n TERMINATOR_MAP,\n} from './constants';\nimport {\n CutoffFormat,\n CutoffFormatOptions,\n CutoffFormatStyle,\n PostpendedCutoffParts,\n PrependedCutoffParts,\n ResolvedCutoffFormatOptions,\n ResolvedTerminatorOptions,\n} from './types';\n\nexport class CutoffFormatConstructor implements CutoffFormat {\n private locale: string;\n private options: ResolvedCutoffFormatOptions;\n private additionLength: number;\n /**\n * Constructor\n * @param {string | string[]} locales - The locales to use for formatting.\n * @param {CutoffFormatOptions} options - The options for formatting.\n * @param {number} [option.maxChars] - The maximum number of characters to display.\n * - Undefined values are treated as no cutoff.\n * - Negative values follow .slice() behavior and terminator will be added before the value.\n * - 0 will result in an empty string.\n * - If cutoff results in an empty string, no terminator is added.\n * @param {CutoffFormatStyle} [option.style='ellipsis'] - The style of the terminator.\n * @param {string} [option.terminator] - Optional override the terminator to use.\n * @param {string} [option.separator] - Optional override the separator to use between the terminator and the value.\n * - If no terminator is provided, then separator is ignored.\n *\n * @example\n * const format = new CutoffFormat('en', { maxChars: 5 });\n * format.format('Hello, world!'); // 'Hello...'\n *\n * const format = new CutoffFormat('en', { maxChars: -3 });\n * format.format('Hello, world!'); // '...ld!'\n */\n constructor(\n locales: Intl.LocalesArgument,\n options: CutoffFormatOptions = {}\n ) {\n // Determine locale (this replicates Intl.NumberFormat behavior including silent failure)\n try {\n // Normalize locales to string\n const localesList = !locales\n ? [libraryDefaultLocale]\n : Array.isArray(locales)\n ? locales.map((l) => String(l))\n : [String(locales)];\n const canonicalLocales = Intl.getCanonicalLocales(localesList);\n this.locale = canonicalLocales.length\n ? canonicalLocales[0]\n : libraryDefaultLocale;\n } catch {\n this.locale = libraryDefaultLocale;\n }\n\n // Follows Intl.NumberFormat behavior of throwing an error when currency is invalid\n if (!TERMINATOR_MAP[options.style ?? DEFAULT_CUTOFF_FORMAT_STYLE]) {\n throw new Error(\n createInvalidCutoffStyleError(\n options.style ?? DEFAULT_CUTOFF_FORMAT_STYLE\n )\n );\n }\n\n // Resolve terminator options\n let style: CutoffFormatStyle | undefined;\n let presetTerminatorOptions: ResolvedTerminatorOptions | undefined;\n if (options.maxChars !== undefined) {\n style = options.style ?? DEFAULT_CUTOFF_FORMAT_STYLE;\n // TODO: need more sophisticated locale negotiation if we want to add support for region/script/etc.-specific terminators in the future\n const languageCode = new Intl.Locale(this.locale).language;\n presetTerminatorOptions =\n TERMINATOR_MAP[style][languageCode] ||\n TERMINATOR_MAP[style][DEFAULT_TERMINATOR_KEY];\n }\n let terminator: ResolvedTerminatorOptions['terminator'] =\n options.terminator ?? presetTerminatorOptions?.terminator;\n let separator: ResolvedTerminatorOptions['separator'] =\n terminator != null\n ? (options.separator ?? presetTerminatorOptions?.separator)\n : undefined;\n // // Remove terminator and separator if maxChars does have enough space\n this.additionLength = (terminator?.length ?? 0) + (separator?.length ?? 0);\n if (\n options.maxChars !== undefined &&\n Math.abs(options.maxChars) < this.additionLength\n ) {\n terminator = undefined;\n separator = undefined;\n }\n\n this.options = {\n maxChars: options.maxChars,\n style,\n terminator,\n separator,\n };\n }\n\n /**\n * Format a value according to the cutoff options, returning a formatted string.\n *\n * @param {string} value - The string value to format with cutoff behavior.\n * @returns {string} The formatted string with terminator applied if cutoff occurs.\n *\n * @example\n * const formatter = new CutoffFormatConstructor('en', { maxChars: 8, style: 'ellipsis' });\n * formatter.format('Hello, world!'); // Returns 'Hello, w...'\n */\n format(value: string): string {\n return this.formatToParts(value).join('');\n }\n\n /**\n * Format a value to parts according to the cutoff options, returning an array of string parts.\n * This method breaks down the formatted result into individual components for more granular control.\n *\n * @param {string} value - The string value to format with cutoff behavior.\n * @returns {PrependedCutoffParts | PostpendedCutoffParts} An array of string parts representing the formatted result.\n * - For positive maxChars: [cutoffValue, separator?, terminator?]\n * - For negative maxChars: [terminator?, separator?, cutoffValue]\n * - For no cutoff: [originalValue]\n *\n * @example\n * const formatter = new CutoffFormatConstructor('en', { maxChars: 5, style: 'ellipsis' });\n * formatter.formatToParts('Hello, world!'); // Returns ['Hello', '...']\n */\n formatToParts(value: string): PrependedCutoffParts | PostpendedCutoffParts {\n const { maxChars, terminator, separator } = this.options;\n\n // Slice our value\n // const additionLength = (terminator?.length ?? 0) + (separator?.length ?? 0);\n const adjustedChars =\n maxChars === undefined || Math.abs(maxChars) >= value.length\n ? maxChars\n : maxChars >= 0\n ? Math.max(0, maxChars - this.additionLength)\n : Math.min(0, maxChars + this.additionLength);\n const slicedValue =\n adjustedChars !== undefined && adjustedChars > -1\n ? value.slice(0, adjustedChars)\n : value.slice(adjustedChars);\n\n // No cutoff, no terminator -> value only\n if (\n maxChars == null ||\n adjustedChars == null ||\n adjustedChars === 0 ||\n terminator == null ||\n value.length <= Math.abs(maxChars)\n ) {\n return [slicedValue];\n }\n\n // Postpended cutoff\n if (adjustedChars > 0) {\n return separator != null\n ? [slicedValue, separator, terminator]\n : [slicedValue, terminator];\n }\n // Prepended cutoff\n else {\n return separator != null\n ? [terminator, separator, slicedValue]\n : [terminator, slicedValue];\n }\n }\n\n /**\n * Get the resolved options\n * @returns {ResolvedCutoffFormatOptions} The resolved options.\n */\n resolvedOptions(): ResolvedCutoffFormatOptions {\n return this.options;\n }\n}\n","import { libraryDefaultLocale } from '../settings/settings';\nimport { CutoffFormatConstructor } from '../formatting/custom-formats/CutoffFormat/CutoffFormat';\nimport {\n ConstructorType,\n CustomIntlConstructors,\n CustomIntlType,\n IntlCacheObject,\n} from './types';\n\n/**\n * Object mapping constructor names to their respective constructor functions\n * Includes all native Intl constructors plus custom ones like CutoffFormat\n */\nconst CustomIntl: CustomIntlType = {\n Collator: Intl.Collator,\n DateTimeFormat: Intl.DateTimeFormat,\n DisplayNames: Intl.DisplayNames,\n ListFormat: Intl.ListFormat,\n Locale: Intl.Locale,\n NumberFormat: Intl.NumberFormat,\n PluralRules: Intl.PluralRules,\n RelativeTimeFormat: Intl.RelativeTimeFormat,\n Segmenter: Intl.Segmenter,\n CutoffFormat: CutoffFormatConstructor,\n};\n\n/**\n * Cache for Intl and custom format instances to avoid repeated instantiation\n * Uses a two-level structure: constructor name -> cache key -> instance\n */\nclass IntlCache {\n private cache: IntlCacheObject;\n\n constructor() {\n this.cache = {};\n }\n\n /**\n * Generates a consistent cache key from locales and options\n * Handles all LocalesArgument types (string, Locale, array, undefined)\n */\n private _generateKey(locales: Intl.LocalesArgument, options = {}) {\n // Normalize locales to string representation\n const localeKey = !locales\n ? 'undefined'\n : Array.isArray(locales)\n ? locales.map((l) => String(l)).join(',')\n : String(locales);\n\n // Sort option keys to ensure consistent key generation regardless of property order\n const sortedOptions = options\n ? JSON.stringify(options, Object.keys(options).sort())\n : '{}';\n return `${localeKey}:${sortedOptions}`;\n }\n\n /**\n * Gets a cached Intl instance or creates a new one if not found\n * @param constructor The name of the Intl constructor to use\n * @param args Constructor arguments (locales, options)\n * @returns Cached or newly created Intl instance\n */\n get<K extends keyof CustomIntlConstructors>(\n constructor: K,\n ...args: ConstructorParameters<CustomIntlConstructors[K]>\n ): InstanceType<ConstructorType<K>> {\n const [locales = libraryDefaultLocale, options = {}] = args;\n const key = this._generateKey(locales, options);\n let intlObject = this.cache[constructor]?.[key];\n\n if (intlObject === undefined) {\n // Create new instance and cache it\n intlObject = new CustomIntl[constructor](...args);\n if (!this.cache[constructor]) this.cache[constructor] = {};\n this.cache[constructor][key] = intlObject;\n }\n\n return intlObject;\n }\n}\n\n/**\n * Global instance of the Intl cache for use throughout the application\n */\nexport const intlCache = new IntlCache();\n"],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ //#region src/settings/settingsUrls.ts
2
+ const defaultCacheUrl = "https://cdn.gtx.dev";
3
+ const defaultBaseUrl = "https://api2.gtx.dev";
4
+ const defaultRuntimeApiUrl = "https://runtime2.gtx.dev";
5
+ //#endregion
6
+ //#region src/utils/isSupportedFileFormatTransform.ts
7
+ const SUPPORTED_TRANSFORMATIONS = {
8
+ GTJSON: ["GTJSON"],
9
+ JSON: ["JSON"],
10
+ PO: ["PO"],
11
+ POT: ["POT", "PO"],
12
+ YAML: ["YAML"],
13
+ MDX: ["MDX"],
14
+ MD: ["MD"],
15
+ TS: ["TS"],
16
+ JS: ["JS"],
17
+ HTML: ["HTML"],
18
+ TXT: ["TXT"],
19
+ TWILIO_CONTENT_JSON: ["TWILIO_CONTENT_JSON"]
20
+ };
21
+ /**
22
+ * This function checks if a file format transformation is supported during translation
23
+ * @param from - The source file format
24
+ * @param to - The target file format
25
+ * @returns True if the transformation is supported, false otherwise
26
+ */
27
+ function isSupportedFileFormatTransform(from, to) {
28
+ return SUPPORTED_TRANSFORMATIONS[from]?.includes(to) ?? false;
29
+ }
30
+ //#endregion
31
+ //#region src/translate/utils/validateFileFormatTransform.ts
32
+ /**
33
+ * Returns a user-facing validation error when a requested file format transform
34
+ * is missing source format context or is not currently supported.
35
+ */
36
+ function getFileFormatTransformError(file) {
37
+ if (!file.transformFormat) return void 0;
38
+ const fileLabel = file.fileName ?? file.fileId ?? "unknown file";
39
+ if (!file.fileFormat) return `fileFormat is required when transformFormat is provided for ${fileLabel}`;
40
+ if (!isSupportedFileFormatTransform(file.fileFormat, file.transformFormat)) return `Unsupported file format transform: ${file.fileFormat} -> ${file.transformFormat}`;
41
+ }
42
+ /**
43
+ * Validates file format transforms before sending upload/enqueue requests.
44
+ */
45
+ function validateFileFormatTransforms(files) {
46
+ for (const file of files) {
47
+ const error = getFileFormatTransformError(file);
48
+ if (error) throw new Error(error);
49
+ }
50
+ }
51
+ //#endregion
52
+ //#region src/utils/base64.ts
53
+ function encode(data) {
54
+ if (typeof Buffer !== "undefined") return Buffer.from(data, "utf8").toString("base64");
55
+ const bytes = new TextEncoder().encode(data);
56
+ let binary = "";
57
+ for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
58
+ return btoa(binary);
59
+ }
60
+ function decode(base64) {
61
+ if (typeof Buffer !== "undefined") return Buffer.from(base64, "base64").toString("utf8");
62
+ const binary = atob(base64);
63
+ const bytes = new Uint8Array(binary.length);
64
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
65
+ return new TextDecoder().decode(bytes);
66
+ }
67
+ //#endregion
68
+ export { defaultBaseUrl as a, isSupportedFileFormatTransform as i, encode as n, defaultCacheUrl as o, validateFileFormatTransforms as r, defaultRuntimeApiUrl as s, decode as t };
69
+
70
+ //# sourceMappingURL=base64-C1sogiix.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base64-C1sogiix.mjs","names":[],"sources":["../src/settings/settingsUrls.ts","../src/utils/isSupportedFileFormatTransform.ts","../src/translate/utils/validateFileFormatTransform.ts","../src/utils/base64.ts"],"sourcesContent":["export const defaultCacheUrl = 'https://cdn.gtx.dev' as const;\nexport const defaultBaseUrl = 'https://api2.gtx.dev' as const;\nexport const defaultRuntimeApiUrl = 'https://runtime2.gtx.dev' as const;\n","import type { FileFormat } from '../types-dir/api/file';\n\nconst SUPPORTED_TRANSFORMATIONS = {\n GTJSON: ['GTJSON'],\n JSON: ['JSON'],\n PO: ['PO'],\n // POT templates can produce translated PO catalog files.\n POT: ['POT', 'PO'],\n YAML: ['YAML'],\n MDX: ['MDX'],\n MD: ['MD'],\n TS: ['TS'],\n JS: ['JS'],\n HTML: ['HTML'],\n TXT: ['TXT'],\n TWILIO_CONTENT_JSON: ['TWILIO_CONTENT_JSON'],\n} as const satisfies Record<FileFormat, FileFormat[]>;\n\n/**\n * This function checks if a file format transformation is supported during translation\n * @param from - The source file format\n * @param to - The target file format\n * @returns True if the transformation is supported, false otherwise\n */\nexport function isSupportedFileFormatTransform(\n from: FileFormat,\n to: FileFormat\n): boolean {\n const toFormats: FileFormat[] | undefined = SUPPORTED_TRANSFORMATIONS[from];\n return toFormats?.includes(to) ?? false;\n}\n","import type { FileFormat } from '../../types-dir/api/file';\nimport { isSupportedFileFormatTransform } from '../../utils/isSupportedFileFormatTransform';\n\nexport type FileFormatTransformInput = {\n fileFormat?: FileFormat;\n transformFormat?: FileFormat;\n fileName?: string;\n fileId?: string;\n};\n\n/**\n * Returns a user-facing validation error when a requested file format transform\n * is missing source format context or is not currently supported.\n */\nexport function getFileFormatTransformError(\n file: FileFormatTransformInput\n): string | undefined {\n if (!file.transformFormat) return undefined;\n const fileLabel = file.fileName ?? file.fileId ?? 'unknown file';\n if (!file.fileFormat) {\n return `fileFormat is required when transformFormat is provided for ${fileLabel}`;\n }\n if (!isSupportedFileFormatTransform(file.fileFormat, file.transformFormat)) {\n return `Unsupported file format transform: ${file.fileFormat} -> ${file.transformFormat}`;\n }\n return undefined;\n}\n\n/**\n * Validates file format transforms before sending upload/enqueue requests.\n */\nexport function validateFileFormatTransforms(\n files: FileFormatTransformInput[]\n): void {\n for (const file of files) {\n const error = getFileFormatTransformError(file);\n if (error) throw new Error(error);\n }\n}\n","// Encode a string to base64\nexport function encode(data: string): string {\n if (typeof Buffer !== 'undefined') {\n // Node.js path\n return Buffer.from(data, 'utf8').toString('base64');\n }\n // Browser path\n const bytes = new TextEncoder().encode(data);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n// Decode a base64 string to a string\nexport function decode(base64: string): string {\n if (typeof Buffer !== 'undefined') {\n // Node.js path\n return Buffer.from(base64, 'base64').toString('utf8');\n }\n // Browser path\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return new TextDecoder().decode(bytes);\n}\n"],"mappings":";AAAA,MAAa,kBAAkB;AAC/B,MAAa,iBAAiB;AAC9B,MAAa,uBAAuB;;;ACApC,MAAM,4BAA4B;CAChC,QAAQ,CAAC,SAAS;CAClB,MAAM,CAAC,OAAO;CACd,IAAI,CAAC,KAAK;CAEV,KAAK,CAAC,OAAO,KAAK;CAClB,MAAM,CAAC,OAAO;CACd,KAAK,CAAC,MAAM;CACZ,IAAI,CAAC,KAAK;CACV,IAAI,CAAC,KAAK;CACV,IAAI,CAAC,KAAK;CACV,MAAM,CAAC,OAAO;CACd,KAAK,CAAC,MAAM;CACZ,qBAAqB,CAAC,sBAAsB;CAC7C;;;;;;;AAQD,SAAgB,+BACd,MACA,IACS;AAET,QAD4C,0BAA0B,OACpD,SAAS,GAAG,IAAI;;;;;;;;ACfpC,SAAgB,4BACd,MACoB;AACpB,KAAI,CAAC,KAAK,gBAAiB,QAAO,KAAA;CAClC,MAAM,YAAY,KAAK,YAAY,KAAK,UAAU;AAClD,KAAI,CAAC,KAAK,WACR,QAAO,+DAA+D;AAExE,KAAI,CAAC,+BAA+B,KAAK,YAAY,KAAK,gBAAgB,CACxE,QAAO,sCAAsC,KAAK,WAAW,MAAM,KAAK;;;;;AAQ5E,SAAgB,6BACd,OACM;AACN,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,QAAQ,4BAA4B,KAAK;AAC/C,MAAI,MAAO,OAAM,IAAI,MAAM,MAAM;;;;;ACnCrC,SAAgB,OAAO,MAAsB;AAC3C,KAAI,OAAO,WAAW,YAEpB,QAAO,OAAO,KAAK,MAAM,OAAO,CAAC,SAAS,SAAS;CAGrD,MAAM,QAAQ,IAAI,aAAa,CAAC,OAAO,KAAK;CAC5C,IAAI,SAAS;AACb,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,IAChC,WAAU,OAAO,aAAa,MAAM,GAAG;AAEzC,QAAO,KAAK,OAAO;;AAIrB,SAAgB,OAAO,QAAwB;AAC7C,KAAI,OAAO,WAAW,YAEpB,QAAO,OAAO,KAAK,QAAQ,SAAS,CAAC,SAAS,OAAO;CAGvD,MAAM,SAAS,KAAK,OAAO;CAC3B,MAAM,QAAQ,IAAI,WAAW,OAAO,OAAO;AAC3C,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,IACjC,OAAM,KAAK,OAAO,WAAW,EAAE;AAEjC,QAAO,IAAI,aAAa,CAAC,OAAO,MAAM"}