roleplay-data 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -85,6 +85,33 @@ Règles des thèmes :
85
85
 
86
86
  ---
87
87
 
88
+ ## 📏 Unités (i18n des mesures)
89
+
90
+ Les données embarquent des **unités canoniques métriques** (SI) — la conversion
91
+ vers les systèmes locaux (lb/oz…) se fait **à l'affichage**, pas dans les données :
92
+
93
+ | Champ | Unité canonique | Helper d'affichage |
94
+ |---|---|---|
95
+ | `item.weight` | grammes | `formatItemWeight(weight, locale)` |
96
+ | `vehicle.massKg` | kg | `formatVehicleMass(massKg, locale)` |
97
+ | `vehicle.fuelCapacity` | litres | à convertir par le consommateur |
98
+ | `vehicle.maxSpeed` | km/h | à convertir par le consommateur |
99
+ | `cargo.maxWeightKg` | kg | à convertir par le consommateur |
100
+
101
+ ```js
102
+ import { formatItemWeight, formatVehicleMass } from 'roleplay-data';
103
+
104
+ formatItemWeight(950, 'fr'); // "950 g" (métrique)
105
+ formatItemWeight(950, 'en'); // "2 lb 2 oz" (impérial)
106
+ formatItemWeight(950, 'en', { unit: 'metric' }); // "950 g" (forcé)
107
+ formatVehicleMass(1480, 'en'); // "3 263 lb"
108
+ ```
109
+
110
+ Le système retenu dérive de la locale (métrique pour fr/es/de/…, impérial pour
111
+ en/us…) — il peut être **forcé** via `opts.unit`.
112
+
113
+ ---
114
+
88
115
  ## Consumption
89
116
 
90
117
  ### npm
@@ -51,7 +51,7 @@
51
51
  "weight": {
52
52
  "type": "number",
53
53
  "minimum": 0,
54
- "description": "Poids en grammes."
54
+ "description": "Poids en grammes (unité canonique métrique). Convertir à l'affichage selon la locale (lb/oz…) via formatItemWeight."
55
55
  },
56
56
  "food": {
57
57
  "type": "number",
@@ -58,17 +58,17 @@
58
58
  "massKg": {
59
59
  "type": "number",
60
60
  "minimum": 0,
61
- "description": "Masse du véhicule en kg."
61
+ "description": "Masse en kg (unité canonique métrique). Convertir à l'affichage selon la locale (lb…) via formatVehicleMass."
62
62
  },
63
63
  "fuelCapacity": {
64
64
  "type": "number",
65
65
  "minimum": 0,
66
- "description": "Capacité du réservoir (unité projet)."
66
+ "description": "Capacité du réservoir en litres (canonique SI)."
67
67
  },
68
68
  "maxSpeed": {
69
69
  "type": "number",
70
70
  "minimum": 0,
71
- "description": "Vitesse maximale (unité projet)."
71
+ "description": "Vitesse maximale en km/h (canonique SI)."
72
72
  },
73
73
  "cargo": {
74
74
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roleplay-data",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Base de données RP open source : items, véhicules, thèmes (images + renommages) et i18n (fr/en requis). Source de vérité unique, consommable en package npm, seed SQL/MongoDB ou archive d'assets.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -27,6 +27,9 @@ export {
27
27
  itemLocalizedName,
28
28
  itemLocalizedDescription,
29
29
  vehicleLocalizedName,
30
+ unitsForLocale,
31
+ formatItemWeight,
32
+ formatVehicleMass,
30
33
  } from './localize.js';
31
34
 
32
35
  const here = dirname(fileURLToPath(import.meta.url));
package/src/localize.d.ts CHANGED
@@ -28,4 +28,17 @@ export function itemLocalizedDescription(
28
28
  export function vehicleLocalizedName(
29
29
  vehicle: { brand?: LocalizedLike; model?: LocalizedLike } | null | undefined,
30
30
  locale?: string
31
- ): string;
31
+ ): string;
32
+
33
+ export type UnitSystem = 'metric' | 'imperial';
34
+
35
+ export type UnitOptions = { unit?: UnitSystem };
36
+
37
+ /** Résout le système d'unités pour une locale (métrique par défaut). */
38
+ export function unitsForLocale(locale?: string, opts?: UnitOptions): UnitSystem;
39
+
40
+ /** Formate un poids d'item (grammes, canonique) selon la locale : g/kg ou lb/oz. */
41
+ export function formatItemWeight(grams: number, locale?: string, opts?: UnitOptions): string;
42
+
43
+ /** Formate une masse de véhicule (kg, canonique) selon la locale : kg ou lb. */
44
+ export function formatVehicleMass(kg: number, locale?: string, opts?: UnitOptions): string;
package/src/localize.js CHANGED
@@ -25,4 +25,59 @@ export function vehicleLocalizedName(vehicle, locale) {
25
25
  const brand = localize(vehicle.brand, locale);
26
26
  const model = localize(vehicle.model, locale);
27
27
  return `${brand} ${model}`.trim();
28
+ }
29
+
30
+ /* ------------------------------------------------------------------ *
31
+ * Unités (i18n des mesures) — données canoniques en métrique (SI),
32
+ * conversion à l'affichage selon la locale. Le consommateur peut imposer
33
+ * un système via opts.unit.
34
+ * ------------------------------------------------------------------ */
35
+
36
+ /** Locales dont le système usuel de masse est le métrique. */
37
+ const METRIC_LOCALES = new Set([
38
+ 'fr', 'es', 'it', 'de', 'pt', 'nl', 'pl', 'ru', 'tr', 'ar', 'cs', 'hu', 'ro', 'sv', 'fi',
39
+ ]);
40
+
41
+ /** Résout le système d'unités pour une locale (métrique par défaut). */
42
+ export function unitsForLocale(locale, opts = {}) {
43
+ if (opts.unit === 'metric' || opts.unit === 'imperial') return opts.unit;
44
+ const key = (locale || 'en').toLowerCase().slice(0, 2);
45
+ return METRIC_LOCALES.has(key) ? 'metric' : 'imperial';
46
+ }
47
+
48
+ function fmt(n) {
49
+ if (!Number.isFinite(n)) return '0';
50
+ return n.toLocaleString('fr-FR', { maximumFractionDigits: 1 });
51
+ }
52
+
53
+ const GRAMS_PER_LB = 453.59237;
54
+ const GRAMS_PER_OZ = 28.349523;
55
+
56
+ /**
57
+ * Formate un poids d'item (en grammes, canonique) selon la locale :
58
+ * métrique → « 950 g » / « 1,5 kg » ; impérial → « 2 lb » / « 1 lb 8 oz ».
59
+ */
60
+ export function formatItemWeight(grams, locale, opts = {}) {
61
+ const g = Number(grams) || 0;
62
+ if (unitsForLocale(locale, opts) === 'imperial') {
63
+ const lb = g / GRAMS_PER_LB;
64
+ if (lb < 1) return `${fmt(g / GRAMS_PER_OZ)} oz`;
65
+ const wholeLb = Math.floor(lb);
66
+ const oz = Math.round((lb - wholeLb) * 16);
67
+ if (oz >= 16) return `${fmt(wholeLb + 1)} lb`;
68
+ return oz === 0 ? `${fmt(wholeLb)} lb` : `${fmt(wholeLb)} lb ${oz} oz`;
69
+ }
70
+ return g < 1000 ? `${fmt(g)} g` : `${fmt(g / 1000)} kg`;
71
+ }
72
+
73
+ /**
74
+ * Formate une masse de véhicule (kg, canonique) selon la locale :
75
+ * métrique → « 1 480 kg » ; impérial → « 3 263 lb ».
76
+ */
77
+ export function formatVehicleMass(kg, locale, opts = {}) {
78
+ const k = Number(kg) || 0;
79
+ if (unitsForLocale(locale, opts) === 'imperial') {
80
+ return `${fmt(k * 2.2046226)} lb`;
81
+ }
82
+ return `${fmt(k)} kg`;
28
83
  }