@uxf/localize 11.122.2 → 11.122.4

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 (2) hide show
  1. package/README.md +175 -66
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,53 +1,90 @@
1
1
  # @uxf/localize
2
+
2
3
  [![npm](https://img.shields.io/npm/v/@uxf/localize)](https://www.npmjs.com/package/@uxf/localize)
3
4
  [![size](https://img.shields.io/bundlephobia/min/@uxf/localize)](https://www.npmjs.com/package/@uxf/localize)
4
5
  [![quality](https://img.shields.io/npms-io/quality-score/@uxf/localize)](https://www.npmjs.com/package/@uxf/localize)
5
6
  [![license](https://img.shields.io/npm/l/@uxf/localize)](https://www.npmjs.com/package/@uxf/localize)
6
7
 
8
+ Locale-aware formatting of numbers, currency amounts, percentages, dates and times, driven by per-locale config objects. Date/time handling is built on [dayjs](https://day.js.org/) (UTC + timezone plugins); number/currency formatting on [currency.js](https://currency.js.org/).
9
+
10
+ ## When to use
11
+
12
+ Reach for `@uxf/localize` when an app needs consistent, config-driven formatting across locales. You call `createLocalize` once with your locale map and get back a provider, hooks, components and standalone functions — all sharing a single locale context.
13
+
14
+ `@uxf/ui` uses the same context internally: its `UiContextProvider` mounts the shared provider with the app locale, so if you already wrap your app in `@uxf/ui`'s provider you do **not** need to mount `LocalizeProvider` again — the formatters from your `createLocalize` will read the locale set by `@uxf/ui`. Mount `LocalizeProvider` yourself only when using `@uxf/localize` standalone.
15
+
7
16
  ## Installation
8
17
 
9
18
  ```bash
10
19
  yarn add @uxf/localize
11
20
  ```
12
21
 
13
- ```bash
14
- npm install @uxf/localize
15
- ```
22
+ Peer dependencies (must be installed by the consumer):
16
23
 
17
- ## Initialize and configure package
24
+ - `@uxf/core`, `@uxf/core-react`
25
+ - `dayjs` `^1.11.19`
26
+ - `react` / `react-dom` `>=18.2.0`
18
27
 
19
- ### Configure package
28
+ `currency.js` ships as a direct dependency.
29
+
30
+ ## Quick start
31
+
32
+ Create the localize instance once, re-export its members, then use them across the app.
20
33
 
21
34
  ```ts
22
35
  // localize.ts
23
36
  import { createLocalize } from "@uxf/localize";
24
- import cs from "@uxf/localize/locale/cs"; // LocalizeConfig
25
- import en from "@uxf/localize/locale/en"; // LocalizeConfig
37
+ import cs from "@uxf/localize/locale/cs";
38
+ import en from "@uxf/localize/locale/en";
26
39
 
27
- export const {
40
+ export const {
28
41
  LocalizeProvider,
29
- formatDateTime,
30
- formatTime,
31
- formatMoney,
42
+ useLocaleConfig,
32
43
  formatNumber,
44
+ formatMoney,
33
45
  formatPercentage,
34
- useFormatDateTime,
35
- useFormatTime,
36
- useFormatMoney,
46
+ formatDateTime,
47
+ formatTime,
37
48
  useFormatNumber,
49
+ useFormatMoney,
38
50
  useFormatPercentage,
39
- FormatDateTime,
40
- FormatTime,
51
+ useFormatDateTime,
52
+ useFormatTime,
41
53
  FormatNumber,
42
54
  FormatMoney,
43
55
  FormatPercentage,
44
- } = createLocale({ cs, en });
56
+ FormatDateTime,
57
+ FormatTime,
58
+ } = createLocalize({ cs, en });
59
+ ```
60
+
61
+ `LocalizeProvider` is a plain React context provider whose `value` is the active locale key:
62
+
63
+ ```tsx
64
+ // _app.tsx
65
+ import { LocalizeProvider } from "./localize";
66
+
67
+ <LocalizeProvider value="cs">{props.children}</LocalizeProvider>;
68
+ ```
69
+
70
+ Use the hooks (they read the locale from context):
71
+
72
+ ```tsx
73
+ import { useFormatMoney } from "./localize";
74
+
75
+ function Price() {
76
+ const formatMoney = useFormatMoney();
77
+
78
+ return <>{formatMoney({ amount: "2000.78", currency: "CZK" })}</>; // 2 001 Kč
79
+ }
45
80
  ```
46
81
 
47
- ### Localize config examples
82
+ ## Configuration
83
+
84
+ Each locale is a `LocalizeConfig` describing number/currency separators, currency patterns, and dayjs format strings. Seven ready-made configs ship with the package and can be imported by locale key: `cs`, `de`, `en`, `es`, `fr`, `pl`, `sk` (e.g. `import cs from "@uxf/localize/locale/cs"`). Spread a bundled config to extend or override it.
48
85
 
49
86
  ```ts
50
- import {DateTimes, Times, LocalizeConfig} from "@uxf/localize";
87
+ import { DateTimes, LocalizeConfig, Times } from "@uxf/localize";
51
88
 
52
89
  const en: LocalizeConfig<DateTimes, Times> = {
53
90
  number: {
@@ -57,6 +94,7 @@ const en: LocalizeConfig<DateTimes, Times> = {
57
94
  currency: {
58
95
  thousandsSeparator: ",",
59
96
  decimalSeparator: ".",
97
+ // per-currency override; `#` = amount, `!` = symbol (see Gotchas)
60
98
  specialCases: {
61
99
  USD: {
62
100
  pattern: "#\xa0$",
@@ -65,16 +103,16 @@ const en: LocalizeConfig<DateTimes, Times> = {
65
103
  },
66
104
  },
67
105
  dateTime: {
68
- timeShort: "H:mm A",
69
- timeFull: "H:mm:ss A",
106
+ timeShort: "h:mm A",
107
+ timeFull: "h:mm:ss A",
70
108
  dateShort: "M/D/YY",
71
109
  dateMedium: "M/D/YYYY",
72
110
  dateLong: "MMMM D. YYYY",
73
111
  dateShortNoYear: "M/D",
74
112
  dateLongNoYear: "MMMM D.",
75
- dateTimeShort: "M/D/YY H:mm A",
76
- dateTimeMedium: "M/D/YYYY H:mm A",
77
- dateTimeLong: "MMMM D. YYYY H:mm:ss A",
113
+ dateTimeShort: "M/D/YY h:mm A",
114
+ dateTimeMedium: "M/D/YYYY h:mm A",
115
+ dateTimeLong: "MMMM D. YYYY h:mm:ss A",
78
116
  },
79
117
  time: {
80
118
  short: "h:mm A",
@@ -112,93 +150,164 @@ const cs: LocalizeConfig<DateTimes, Times> = {
112
150
  time: {
113
151
  short: "H:mm",
114
152
  long: "H:mm:ss",
115
- }
153
+ },
116
154
  };
117
155
  ```
118
156
 
119
- ### Add LocalizeProvider to _app.tsx
157
+ Custom `dateTime` / `time` keys are supported by widening the generics: `createLocalize<DateTimes | "custom", Times>({ ... })`.
120
158
 
121
- ```tsx
122
- // _app.tsx
159
+ ## Formatters
123
160
 
124
- <LocalizeProvider locale="cs">{props.children}</LocalizeProvider>
125
- ```
161
+ All examples below assume the `cs` locale is active (via the provider). Outputs use a non-breaking space as the thousands separator, shown here as a normal space.
162
+
163
+ ### Number
126
164
 
127
- ## Format number
128
165
  ```tsx
129
- const { useFormatNumber, FormatNumber } from "./localize";
166
+ import { useFormatNumber, FormatNumber } from "./localize";
130
167
 
131
168
  const formatNumber = useFormatNumber();
132
169
 
133
- formatNumber(1000.23); // 1 000
134
- formatNumber(1000.23, { precision: 2 }); // 1 000,23
170
+ formatNumber(2000.78); // 2 001 (default precision 0)
171
+ formatNumber(2000.78, { precision: 2 }); // 2 000,78
135
172
 
136
- <FormatNumber value={1000.23}/>
173
+ <FormatNumber value={2000.78} />;
137
174
  ```
138
175
 
139
- ## Format datetime
176
+ ### Date and time
177
+
140
178
  ```tsx
141
- const { useFormatDateTime, FormatDateTime } from "./localize";
179
+ import { useFormatDateTime, FormatDateTime } from "./localize";
142
180
 
143
181
  const formatDateTime = useFormatDateTime();
182
+ const date = new Date("2023-07-21T07:58:35+02:00");
144
183
 
145
- formatDateTime(new Date('2000-01-01'), "dateShort"); // 1. 1. 20
146
- formatDateTime(new Date('2000-01-01'), "dateTimeMedium"); // 1. 1. 2000 00:00
147
- formatDateTime(new Date('2000-01-01'), "timeFull"); // 00:00:00
184
+ formatDateTime(date, "dateShort"); // 21. 7. 23
185
+ formatDateTime(date, "dateTimeMedium"); // 21. 7. 2023, 7:58
186
+ formatDateTime(date, "timeFull"); // 7:58:35
148
187
 
149
- <FormatDateTime value={new Date('2000-01-01')} format="dateShort"/>
188
+ <FormatDateTime format="dateShort" value={date} />;
189
+ // the component (and the standalone function) also accept a `timeZone` prop/arg
190
+ <FormatDateTime format="dateTimeShort" timeZone="America/New_York" value={date} />;
150
191
  ```
151
192
 
152
- ## Format time
193
+ ### Time
194
+
195
+ Formats a `TimeString` (`"HH:mm:ss"`).
196
+
153
197
  ```tsx
154
- const { useFormatTime, FormatTime } from "./localize";
198
+ import { useFormatTime, FormatTime } from "./localize";
155
199
 
156
200
  const formatTime = useFormatTime();
157
201
 
158
202
  formatTime("07:58:35", "short"); // 7:58
159
- formatTime("07:58:35", "short"); // 7:58:35
203
+ formatTime("07:58:35", "long"); // 7:58:35
160
204
 
161
- <FormatTime value="07:58:35" format="short"/>
205
+ <FormatTime format="short" value="07:58:35" />;
162
206
  ```
163
207
 
164
- ## Format money
208
+ ### Money
209
+
210
+ Takes a `Money` object (`{ amount: string; currency: Currency }`).
211
+
165
212
  ```tsx
166
- const { useFormatMoney, FormatMoney } from "./localize";
213
+ import { useFormatMoney, FormatMoney } from "./localize";
167
214
 
168
215
  const formatMoney = useFormatMoney();
169
216
 
170
- formatMoney({amount: 1000, currency: "CZK"}); // 1 000
171
- formatMoney({amount: 1000, currency: "USD"}); // 1 000 $
172
- formatMoney({amount: 1000.23, currency: "CZK"}, { precision: 1 }); // 1 000,2
173
- formatMoney({amount: 1000.23, currency: "CZK"}, { preferIsoCode: true }); // 1 000,23 CZK
174
- formatMoney({amount: 1000.23, currency: "CZK"}, { hideSymbol: true }); // 1 000,23
217
+ formatMoney({ amount: "2000.78", currency: "CZK" }); // 2 001 (default precision 0)
218
+ formatMoney({ amount: "2000.78", currency: "USD" }); // 2 001 $
219
+ formatMoney({ amount: "2000.78", currency: "CZK" }, { precision: 1 }); // 2 000,8
220
+ formatMoney({ amount: "2000.78", currency: "CZK" }, { precision: 1, preferIsoCode: true }); // 2 000,8 CZK
221
+ formatMoney({ amount: "2000.78", currency: "CZK" }, { precision: 1, hideSymbol: true }); // 2 000,8
175
222
 
176
- <FormatMoney money={{amount: 1000, currency: "CZK"}}/>
223
+ <FormatMoney money={{ amount: "2000.78", currency: "CZK" }} />;
177
224
  ```
178
225
 
179
- ## Format percentage
226
+ ### Percentage
227
+
228
+ Expects a ratio and multiplies it by 100. An optional `roundingType` rounds to a whole percent (`"nearest"` → `Math.round`, `"up"` → `Math.ceil`, `"down"` → `Math.floor`); pass `null` to skip rounding and control precision via options.
180
229
 
181
230
  ```tsx
182
- const { useFormatPercentage, FormatPercentage } from "./localize";
231
+ import { useFormatPercentage, FormatPercentage } from "./localize";
183
232
 
184
233
  const formatPercentage = useFormatPercentage();
185
234
 
186
- formatPercentage(0.782); // 78,2 %
187
- formatPercentage(0.782, "nearest"); // 78,2 %
188
- formatPercentage(0.782, "up"); // 78,2 %
189
- formatPercentage(0.782, "down"); // 78,2 %
235
+ formatPercentage(0.782); // 78 % (default precision 0)
236
+ formatPercentage(0.782, null, { precision: 2 }); // 78,20 %
237
+ formatPercentage(0.782, "up"); // 79 %
238
+ formatPercentage(0.788, "down"); // 78 %
190
239
 
191
- <FormatPercentage value={0.782} roundingType="up" />
240
+ <FormatPercentage roundingType="up" value={0.782} />;
192
241
  ```
193
242
 
194
- ## Format another locale
243
+ ## Formatting for an explicit locale
244
+
245
+ The standalone functions take the locale as their first argument and ignore the provider context. Use them for server-side or multi-locale output.
195
246
 
196
247
  ```tsx
197
- const { formatNumber, formatDateTime, formatMoney, formatPercentage } from "./localize";
248
+ import { formatNumber, formatDateTime, formatMoney, formatPercentage, formatTime } from "./localize";
249
+
250
+ formatNumber("cs", 2000.78); // 2 001
251
+ formatDateTime("cs", new Date("2023-07-21T07:58:35+02:00"), "dateMedium"); // 21. 7. 2023
252
+ formatMoney("cs", { amount: "2000.78", currency: "CZK" }); // 2 001 Kč
253
+ formatPercentage("cs", 0.782); // 78 %
254
+ formatTime("cs", "07:58:35", "short"); // 7:58
255
+ ```
256
+
257
+ ## API
198
258
 
199
- formatNumber("cs", 1000.23); // 1 000
200
- formatDateTime("cs", new Date('2000-01-01'), "dateMedium") // 1. 1. 2000
201
- formatMoney("cs", 1000, "CZK") // 1 000 Kč
202
- formatPercentage("cs", 0.782) // 78,2 %
259
+ Import everything from the package root: `import { createLocalize } from "@uxf/localize"`. Locale configs are deep imports: `import cs from "@uxf/localize/locale/<code>"`.
260
+
261
+ ### `createLocalize(config)`
262
+
263
+ ```ts
264
+ createLocalize<DT extends string = DateTimes, T extends string = Times, Locales extends string = string>(
265
+ config: LocalizeConfigMap<DT, T, Locales>,
266
+ ): CreateLocalizeReturn<DT, T, Locales>;
203
267
  ```
204
268
 
269
+ Returns an object with the following members:
270
+
271
+ | Member | Signature | Notes |
272
+ | --- | --- | --- |
273
+ | `LocalizeProvider` | `Provider<string>` | React context provider; `value` is the active locale key. |
274
+ | `useLocaleConfig` | `() => LocalizeConfig<DT, T>` | Returns the config for the current locale. |
275
+ | `formatNumber` | `(locale, value, options?) => string` | `options: { precision? }`. |
276
+ | `useFormatNumber` | `() => (value, options?) => string` | Locale from context. |
277
+ | `FormatNumber` | `FC<{ value; options? }>` | |
278
+ | `formatMoney` | `(locale, money, options?) => string` | `options: { hideSymbol?, precision?, preferIsoCode? }`. |
279
+ | `useFormatMoney` | `() => (money, options?) => string` | Locale from context. |
280
+ | `FormatMoney` | `FC<{ money; options? }>` | |
281
+ | `formatPercentage` | `(locale, value, roundingType?, options?) => string` | `roundingType: "nearest" \| "up" \| "down" \| null`. |
282
+ | `useFormatPercentage` | `() => (value, roundingType?, options?) => string` | Locale from context. |
283
+ | `FormatPercentage` | `FC<{ value; roundingType?; options? }>` | |
284
+ | `formatDateTime` | `(locale, value, format, timeZone?) => string` | `value: DateValue`; default `timeZone` is `Europe/Prague`. |
285
+ | `useFormatDateTime` | `() => (value, format) => string` | No `timeZone` param (fixed to default). |
286
+ | `FormatDateTime` | `FC<{ value; format; timeZone? }>` | |
287
+ | `formatTime` | `(locale, value, format) => string` | `value: TimeString`. |
288
+ | `useFormatTime` | `() => (value, format) => string` | Locale from context. |
289
+ | `FormatTime` | `FC<{ value; format }>` | |
290
+
291
+ ### Exported types
292
+
293
+ `export type * from "./src/types"` exposes, among others: `LocalizeConfig`, `LocalizeConfigMap`, `CreateLocalizeReturn`, `DateTimes`, `Times`, `Currency`, `Money`, `TimeZone`, `RoundingType`, `FormatMoneyPattern`, and the per-formatter `*Options` / `*Function` / `*Component` types.
294
+
295
+ ### `_LocalizeProvider` (internal)
296
+
297
+ `_LocalizeProvider` is exported from the package root but is **internal** — it is the shared global locale context, consumed by `@uxf/ui`'s `UiContextProvider`. Application code should use the `LocalizeProvider` returned by `createLocalize` (it is the same context object). The two provide into the same context, so mounting either sets the locale for all formatters.
298
+
299
+ ## Gotchas
300
+
301
+ - **Provider prop is `value`, not `locale`** — `LocalizeProvider` is a raw React context provider: `<LocalizeProvider value="cs">`.
302
+ - **Default precision is `0`** for number, money and percentage. Pass `{ precision }` to show decimals; values are rounded (via currency.js), not truncated.
303
+ - **`Money.amount` is a string** (`{ amount: "2000.78", currency: "CZK" }`), not a number.
304
+ - **`formatPercentage` takes a ratio** (`0.782` → `78 %`); it multiplies by 100. A `roundingType` rounds to a whole percent before formatting, so decimals only appear when `roundingType` is `null`/omitted and `precision` is set.
305
+ - **Time zone defaults to `Europe/Prague`** for date/time formatting. The `useFormatDateTime` hook is fixed to that default; to override, use the standalone `formatDateTime(locale, value, format, timeZone)` or the `FormatDateTime` component's `timeZone` prop.
306
+ - **Date-only strings** (`"YYYY-MM-DD"`) are parsed as midnight in the target time zone, while `Date` instances represent a concrete instant and are shifted into that zone — the same wall-clock string can render differently depending on the input form.
307
+ - **Currency patterns** use currency.js placeholders: `#` = amount, `!` = symbol. Built-in defaults exist for `EUR` and `USD`; `specialCases` in the config override per currency; otherwise a plain `# <symbol>` pattern is used, and `preferIsoCode` forces the ISO code instead of the symbol.
308
+ - **Separators are non-breaking spaces** in some locales (e.g. `cs`), so `"2 001"` contains ` `, not a regular space.
309
+
310
+ ## Links
311
+
312
+ - [npm package](https://www.npmjs.com/package/@uxf/localize)
313
+ - Related: `@uxf/core` (`Money`, `Currency`, date types), `@uxf/core-react` (global context), `@uxf/ui` (mounts the shared locale provider).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxf/localize",
3
- "version": "11.122.2",
3
+ "version": "11.122.4",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {