@chipmobilesdk/rn-i18n 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,27 +1,27 @@
1
- import type { InvalidFormatPolicy } from '../config/types';
2
- import { applyInvalidFormatPolicy } from './invalid';
3
-
4
- /**
5
- * Locale-aware currency formatting. The locale's configured default currency
6
- * applies unless the caller passes an explicit currency override (FR-021).
7
- */
8
- export function formatCurrencyValue(
9
- value: number,
10
- localeCode: string,
11
- defaultCurrency: string,
12
- currencyOverride: string | undefined,
13
- options: Intl.NumberFormatOptions | undefined,
14
- invalidFormat: InvalidFormatPolicy,
15
- ): string {
16
- if (typeof value !== 'number' || !Number.isFinite(value)) {
17
- return applyInvalidFormatPolicy(
18
- invalidFormat,
19
- `Cannot format invalid currency value "${String(value)}" for locale "${localeCode}".`,
20
- );
21
- }
22
- return new Intl.NumberFormat(localeCode, {
23
- ...options,
24
- style: 'currency',
25
- currency: currencyOverride ?? defaultCurrency,
26
- }).format(value);
27
- }
1
+ import type { InvalidFormatPolicy } from '../config/types';
2
+ import { applyInvalidFormatPolicy } from './invalid';
3
+
4
+ /**
5
+ * Locale-aware currency formatting. The locale's configured default currency
6
+ * applies unless the caller passes an explicit currency override (FR-021).
7
+ */
8
+ export function formatCurrencyValue(
9
+ value: number,
10
+ localeCode: string,
11
+ defaultCurrency: string,
12
+ currencyOverride: string | undefined,
13
+ options: Intl.NumberFormatOptions | undefined,
14
+ invalidFormat: InvalidFormatPolicy,
15
+ ): string {
16
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
17
+ return applyInvalidFormatPolicy(
18
+ invalidFormat,
19
+ `Cannot format invalid currency value "${String(value)}" for locale "${localeCode}".`,
20
+ );
21
+ }
22
+ return new Intl.NumberFormat(localeCode, {
23
+ ...options,
24
+ style: 'currency',
25
+ currency: currencyOverride ?? defaultCurrency,
26
+ }).format(value);
27
+ }
@@ -1,26 +1,26 @@
1
- import type { InvalidFormatPolicy } from '../config/types';
2
- import { applyInvalidFormatPolicy } from './invalid';
3
-
4
- /**
5
- * Locale-aware date formatting through the Hermes built-in
6
- * Intl.DateTimeFormat. The locale's configured default date format applies
7
- * unless the caller passes explicit overrides (FR-020). Options are limited
8
- * to component options supported by Hermes on both platforms.
9
- */
10
- export function formatDateValue(
11
- value: Date | number,
12
- localeCode: string,
13
- defaults: Intl.DateTimeFormatOptions,
14
- override: Intl.DateTimeFormatOptions | undefined,
15
- invalidFormat: InvalidFormatPolicy,
16
- ): string {
17
- const date = value instanceof Date ? value : new Date(value);
18
- if (Number.isNaN(date.getTime())) {
19
- return applyInvalidFormatPolicy(
20
- invalidFormat,
21
- `Cannot format invalid date value "${String(value)}" for locale "${localeCode}".`,
22
- );
23
- }
24
- const options = override ?? defaults;
25
- return new Intl.DateTimeFormat(localeCode, options).format(date);
26
- }
1
+ import type { InvalidFormatPolicy } from '../config/types';
2
+ import { applyInvalidFormatPolicy } from './invalid';
3
+
4
+ /**
5
+ * Locale-aware date formatting through the Hermes built-in
6
+ * Intl.DateTimeFormat. The locale's configured default date format applies
7
+ * unless the caller passes explicit overrides (FR-020). Options are limited
8
+ * to component options supported by Hermes on both platforms.
9
+ */
10
+ export function formatDateValue(
11
+ value: Date | number,
12
+ localeCode: string,
13
+ defaults: Intl.DateTimeFormatOptions,
14
+ override: Intl.DateTimeFormatOptions | undefined,
15
+ invalidFormat: InvalidFormatPolicy,
16
+ ): string {
17
+ const date = value instanceof Date ? value : new Date(value);
18
+ if (Number.isNaN(date.getTime())) {
19
+ return applyInvalidFormatPolicy(
20
+ invalidFormat,
21
+ `Cannot format invalid date value "${String(value)}" for locale "${localeCode}".`,
22
+ );
23
+ }
24
+ const options = override ?? defaults;
25
+ return new Intl.DateTimeFormat(localeCode, options).format(date);
26
+ }
@@ -1,16 +1,13 @@
1
- import type { InvalidFormatPolicy } from '../config/types';
2
-
3
- /**
4
- * Applies the configured invalid-format behavior: return the placeholder, or
5
- * throw a clear formatting error in `error` mode (FR-037, FR-045).
6
- */
7
- export function applyInvalidFormatPolicy(
8
- policy: InvalidFormatPolicy,
9
- message: string,
10
- ): string {
11
- console.warn(`[rn-i18n] ${message}`);
12
- if (policy.mode === 'error') {
13
- throw new RangeError(`[rn-i18n] ${message}`);
14
- }
15
- return policy.text;
16
- }
1
+ import type { InvalidFormatPolicy } from '../config/types';
2
+
3
+ /**
4
+ * Applies the configured invalid-format behavior: return the placeholder, or
5
+ * throw a clear formatting error in `error` mode (FR-037, FR-045).
6
+ */
7
+ export function applyInvalidFormatPolicy(policy: InvalidFormatPolicy, message: string): string {
8
+ console.warn(`[rn-i18n] ${message}`);
9
+ if (policy.mode === 'error') {
10
+ throw new RangeError(`[rn-i18n] ${message}`);
11
+ }
12
+ return policy.text;
13
+ }
@@ -1,25 +1,23 @@
1
- import type { InvalidFormatPolicy } from '../config/types';
2
- import { applyInvalidFormatPolicy } from './invalid';
3
-
4
- /**
5
- * Locale-aware number formatting through the Hermes built-in
6
- * Intl.NumberFormat. The locale default options apply unless the caller
7
- * passes explicit overrides (FR-019).
8
- */
9
- export function formatNumberValue(
10
- value: number,
11
- localeCode: string,
12
- defaults: Intl.NumberFormatOptions,
13
- override: Intl.NumberFormatOptions | undefined,
14
- invalidFormat: InvalidFormatPolicy,
15
- ): string {
16
- if (typeof value !== 'number' || !Number.isFinite(value)) {
17
- return applyInvalidFormatPolicy(
18
- invalidFormat,
19
- `Cannot format invalid number value "${String(value)}" for locale "${localeCode}".`,
20
- );
21
- }
22
- return new Intl.NumberFormat(localeCode, { ...defaults, ...override }).format(
23
- value,
24
- );
25
- }
1
+ import type { InvalidFormatPolicy } from '../config/types';
2
+ import { applyInvalidFormatPolicy } from './invalid';
3
+
4
+ /**
5
+ * Locale-aware number formatting through the Hermes built-in
6
+ * Intl.NumberFormat. The locale default options apply unless the caller
7
+ * passes explicit overrides (FR-019).
8
+ */
9
+ export function formatNumberValue(
10
+ value: number,
11
+ localeCode: string,
12
+ defaults: Intl.NumberFormatOptions,
13
+ override: Intl.NumberFormatOptions | undefined,
14
+ invalidFormat: InvalidFormatPolicy,
15
+ ): string {
16
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
17
+ return applyInvalidFormatPolicy(
18
+ invalidFormat,
19
+ `Cannot format invalid number value "${String(value)}" for locale "${localeCode}".`,
20
+ );
21
+ }
22
+ return new Intl.NumberFormat(localeCode, { ...defaults, ...override }).format(value);
23
+ }
@@ -1,151 +1,141 @@
1
- import type {
2
- InvalidFormatPolicy,
3
- UnitDimension,
4
- UnitId,
5
- } from '../config/types';
6
- import { applyInvalidFormatPolicy } from './invalid';
7
- import { formatNumberValue } from './number';
8
-
9
- interface UnitDefinition {
10
- dimension: UnitDimension;
11
- /** Factor to the dimension's base unit; unused for temperature. */
12
- factor: number;
13
- symbol: string;
14
- }
15
-
16
- /**
17
- * Package-owned unit registry and conversion tables. Intl.NumberFormat unit
18
- * style is not consistently available under Hermes, so the numeric part is
19
- * formatted through Intl and the unit symbol is appended from this registry
20
- * (research R4). Base units: meter, kilogram, liter, celsius.
21
- */
22
- const UNIT_REGISTRY: Record<UnitId, UnitDefinition> = {
23
- millimeter: { dimension: 'length', factor: 0.001, symbol: 'mm' },
24
- centimeter: { dimension: 'length', factor: 0.01, symbol: 'cm' },
25
- meter: { dimension: 'length', factor: 1, symbol: 'm' },
26
- kilometer: { dimension: 'length', factor: 1000, symbol: 'km' },
27
- inch: { dimension: 'length', factor: 0.0254, symbol: 'in' },
28
- foot: { dimension: 'length', factor: 0.3048, symbol: 'ft' },
29
- mile: { dimension: 'length', factor: 1609.344, symbol: 'mi' },
30
- gram: { dimension: 'mass', factor: 0.001, symbol: 'g' },
31
- kilogram: { dimension: 'mass', factor: 1, symbol: 'kg' },
32
- ounce: { dimension: 'mass', factor: 0.028349523125, symbol: 'oz' },
33
- pound: { dimension: 'mass', factor: 0.45359237, symbol: 'lb' },
34
- milliliter: { dimension: 'volume', factor: 0.001, symbol: 'ml' },
35
- liter: { dimension: 'volume', factor: 1, symbol: 'l' },
36
- gallon: { dimension: 'volume', factor: 3.785411784, symbol: 'gal' },
37
- celsius: { dimension: 'temperature', factor: 1, symbol: '°C' },
38
- fahrenheit: { dimension: 'temperature', factor: 1, symbol: '°F' },
39
- kelvin: { dimension: 'temperature', factor: 1, symbol: 'K' },
40
- };
41
-
42
- export const SUPPORTED_UNITS = Object.keys(UNIT_REGISTRY) as readonly UnitId[];
43
-
44
- export const KNOWN_UNIT_IDS: ReadonlySet<string> = new Set(SUPPORTED_UNITS);
45
-
46
- export class UnitConversionError extends Error {
47
- constructor(message: string) {
48
- super(message);
49
- this.name = 'UnitConversionError';
50
- }
51
- }
52
-
53
- export function getUnitSymbol(unit: UnitId): string {
54
- return UNIT_REGISTRY[unit].symbol;
55
- }
56
-
57
- function toCelsius(value: number, from: UnitId): number {
58
- switch (from) {
59
- case 'fahrenheit':
60
- return ((value - 32) * 5) / 9;
61
- case 'kelvin':
62
- return value - 273.15;
63
- default:
64
- return value;
65
- }
66
- }
67
-
68
- function fromCelsius(value: number, to: UnitId): number {
69
- switch (to) {
70
- case 'fahrenheit':
71
- return (value * 9) / 5 + 32;
72
- case 'kelvin':
73
- return value + 273.15;
74
- default:
75
- return value;
76
- }
77
- }
78
-
79
- /**
80
- * Converts between compatible supported units. Unknown units or conversions
81
- * across dimensions throw a UnitConversionError (FR-044/FR-045).
82
- */
83
- export function convertUnitValue(
84
- value: number,
85
- from: UnitId,
86
- to: UnitId,
87
- ): number {
88
- const fromDef = UNIT_REGISTRY[from];
89
- const toDef = UNIT_REGISTRY[to];
90
- if (!fromDef || !toDef) {
91
- throw new UnitConversionError(
92
- `Unknown unit in conversion "${from}" -> "${to}".`,
93
- );
94
- }
95
- if (fromDef.dimension !== toDef.dimension) {
96
- throw new UnitConversionError(
97
- `Cannot convert between incompatible dimensions "${fromDef.dimension}" (${from}) and "${toDef.dimension}" (${to}).`,
98
- );
99
- }
100
- if (!Number.isFinite(value)) {
101
- throw new UnitConversionError(
102
- `Cannot convert invalid value "${String(value)}" from "${from}" to "${to}".`,
103
- );
104
- }
105
- if (from === to) {
106
- return value;
107
- }
108
- if (fromDef.dimension === 'temperature') {
109
- return fromCelsius(toCelsius(value, from), to);
110
- }
111
- return (value * fromDef.factor) / toDef.factor;
112
- }
113
-
114
- export interface UnitFormatOptions extends Intl.NumberFormatOptions {
115
- /** Unit the value is expressed in. Default: the locale's default unit. */
116
- from?: UnitId;
117
- /** Unit to display. Default: `from` (no conversion). */
118
- to?: UnitId;
119
- }
120
-
121
- /**
122
- * Converts (when requested) and formats a measurement value: locale-aware
123
- * numeric part via Intl.NumberFormat plus the package-owned unit symbol.
124
- */
125
- export function formatUnitValue(
126
- value: number,
127
- localeCode: string,
128
- localeDefaultUnit: UnitId,
129
- numberDefaults: Intl.NumberFormatOptions,
130
- options: UnitFormatOptions | undefined,
131
- invalidFormat: InvalidFormatPolicy,
132
- ): string {
133
- const { from = localeDefaultUnit, to = from, ...numberOptions } = options ?? {};
134
- let converted: number;
135
- try {
136
- converted = convertUnitValue(value, from, to);
137
- } catch (error) {
138
- return applyInvalidFormatPolicy(
139
- invalidFormat,
140
- error instanceof Error ? error.message : String(error),
141
- );
142
- }
143
- const formatted = formatNumberValue(
144
- converted,
145
- localeCode,
146
- numberDefaults,
147
- numberOptions,
148
- invalidFormat,
149
- );
150
- return `${formatted} ${getUnitSymbol(to)}`;
151
- }
1
+ import type { InvalidFormatPolicy, UnitDimension, UnitId } from '../config/types';
2
+ import { applyInvalidFormatPolicy } from './invalid';
3
+ import { formatNumberValue } from './number';
4
+
5
+ interface UnitDefinition {
6
+ dimension: UnitDimension;
7
+ /** Factor to the dimension's base unit; unused for temperature. */
8
+ factor: number;
9
+ symbol: string;
10
+ }
11
+
12
+ /**
13
+ * Package-owned unit registry and conversion tables. Intl.NumberFormat unit
14
+ * style is not consistently available under Hermes, so the numeric part is
15
+ * formatted through Intl and the unit symbol is appended from this registry
16
+ * (research R4). Base units: meter, kilogram, liter, celsius.
17
+ */
18
+ const UNIT_REGISTRY: Record<UnitId, UnitDefinition> = {
19
+ millimeter: { dimension: 'length', factor: 0.001, symbol: 'mm' },
20
+ centimeter: { dimension: 'length', factor: 0.01, symbol: 'cm' },
21
+ meter: { dimension: 'length', factor: 1, symbol: 'm' },
22
+ kilometer: { dimension: 'length', factor: 1000, symbol: 'km' },
23
+ inch: { dimension: 'length', factor: 0.0254, symbol: 'in' },
24
+ foot: { dimension: 'length', factor: 0.3048, symbol: 'ft' },
25
+ mile: { dimension: 'length', factor: 1609.344, symbol: 'mi' },
26
+ gram: { dimension: 'mass', factor: 0.001, symbol: 'g' },
27
+ kilogram: { dimension: 'mass', factor: 1, symbol: 'kg' },
28
+ ounce: { dimension: 'mass', factor: 0.028349523125, symbol: 'oz' },
29
+ pound: { dimension: 'mass', factor: 0.45359237, symbol: 'lb' },
30
+ milliliter: { dimension: 'volume', factor: 0.001, symbol: 'ml' },
31
+ liter: { dimension: 'volume', factor: 1, symbol: 'l' },
32
+ gallon: { dimension: 'volume', factor: 3.785411784, symbol: 'gal' },
33
+ celsius: { dimension: 'temperature', factor: 1, symbol: '°C' },
34
+ fahrenheit: { dimension: 'temperature', factor: 1, symbol: '°F' },
35
+ kelvin: { dimension: 'temperature', factor: 1, symbol: 'K' },
36
+ };
37
+
38
+ export const SUPPORTED_UNITS = Object.keys(UNIT_REGISTRY) as readonly UnitId[];
39
+
40
+ export const KNOWN_UNIT_IDS: ReadonlySet<string> = new Set(SUPPORTED_UNITS);
41
+
42
+ export class UnitConversionError extends Error {
43
+ constructor(message: string) {
44
+ super(message);
45
+ this.name = 'UnitConversionError';
46
+ }
47
+ }
48
+
49
+ export function getUnitSymbol(unit: UnitId): string {
50
+ return UNIT_REGISTRY[unit].symbol;
51
+ }
52
+
53
+ function toCelsius(value: number, from: UnitId): number {
54
+ switch (from) {
55
+ case 'fahrenheit':
56
+ return ((value - 32) * 5) / 9;
57
+ case 'kelvin':
58
+ return value - 273.15;
59
+ default:
60
+ return value;
61
+ }
62
+ }
63
+
64
+ function fromCelsius(value: number, to: UnitId): number {
65
+ switch (to) {
66
+ case 'fahrenheit':
67
+ return (value * 9) / 5 + 32;
68
+ case 'kelvin':
69
+ return value + 273.15;
70
+ default:
71
+ return value;
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Converts between compatible supported units. Unknown units or conversions
77
+ * across dimensions throw a UnitConversionError (FR-044/FR-045).
78
+ */
79
+ export function convertUnitValue(value: number, from: UnitId, to: UnitId): number {
80
+ const fromDef = UNIT_REGISTRY[from];
81
+ const toDef = UNIT_REGISTRY[to];
82
+ if (!fromDef || !toDef) {
83
+ throw new UnitConversionError(`Unknown unit in conversion "${from}" -> "${to}".`);
84
+ }
85
+ if (fromDef.dimension !== toDef.dimension) {
86
+ throw new UnitConversionError(
87
+ `Cannot convert between incompatible dimensions "${fromDef.dimension}" (${from}) and "${toDef.dimension}" (${to}).`,
88
+ );
89
+ }
90
+ if (!Number.isFinite(value)) {
91
+ throw new UnitConversionError(
92
+ `Cannot convert invalid value "${String(value)}" from "${from}" to "${to}".`,
93
+ );
94
+ }
95
+ if (from === to) {
96
+ return value;
97
+ }
98
+ if (fromDef.dimension === 'temperature') {
99
+ return fromCelsius(toCelsius(value, from), to);
100
+ }
101
+ return (value * fromDef.factor) / toDef.factor;
102
+ }
103
+
104
+ export interface UnitFormatOptions extends Intl.NumberFormatOptions {
105
+ /** Unit the value is expressed in. Default: the locale's default unit. */
106
+ from?: UnitId;
107
+ /** Unit to display. Default: `from` (no conversion). */
108
+ to?: UnitId;
109
+ }
110
+
111
+ /**
112
+ * Converts (when requested) and formats a measurement value: locale-aware
113
+ * numeric part via Intl.NumberFormat plus the package-owned unit symbol.
114
+ */
115
+ export function formatUnitValue(
116
+ value: number,
117
+ localeCode: string,
118
+ localeDefaultUnit: UnitId,
119
+ numberDefaults: Intl.NumberFormatOptions,
120
+ options: UnitFormatOptions | undefined,
121
+ invalidFormat: InvalidFormatPolicy,
122
+ ): string {
123
+ const { from = localeDefaultUnit, to = from, ...numberOptions } = options ?? {};
124
+ let converted: number;
125
+ try {
126
+ converted = convertUnitValue(value, from, to);
127
+ } catch (error) {
128
+ return applyInvalidFormatPolicy(
129
+ invalidFormat,
130
+ error instanceof Error ? error.message : String(error),
131
+ );
132
+ }
133
+ const formatted = formatNumberValue(
134
+ converted,
135
+ localeCode,
136
+ numberDefaults,
137
+ numberOptions,
138
+ invalidFormat,
139
+ );
140
+ return `${formatted} ${getUnitSymbol(to)}`;
141
+ }