@form-engine-ts/react 4.7.0 → 4.8.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
@@ -81,7 +81,10 @@ schema-driven pre-submit confirmation controls in the builder.
81
81
 
82
82
  `useTranslationWorkspace` validates added locales against `policy.allowedLocales` and `policy.maxLocales` and returns
83
83
  a structured `{ success, error }` result from `addLocale`. Built-in BCP 47, duplicate, and policy checks always run
84
- before the optional `validateLocale` callback, which receives the locale, default locale, current locales, and policy.
84
+ before the optional `validateLocale` callback, which receives the canonical locale and a plain context object containing
85
+ the canonical default locale, current locales, and policy.
86
+ Locale input is normalized to its canonical BCP 47 form before duplicate, policy, custom-validation, and schema updates;
87
+ underscore-separated values such as `EN_us` are accepted as compatibility input.
85
88
  Use `isAddLocaleAllowed` to disable locale controls before submission. Removing a locale also clears its
86
89
  localized values and metadata; the default locale remains protected.
87
90
 
package/dist/index.cjs CHANGED
@@ -3282,20 +3282,9 @@ function asAsyncAdapter(adapter) {
3282
3282
  )
3283
3283
  };
3284
3284
  }
3285
- function isValidBcp47Locale(locale) {
3286
- const language = locale.split("-")[0];
3287
- if (language === void 0 || !/^[a-z]{2,3}$/iu.test(language)) return false;
3288
- try {
3289
- Intl.getCanonicalLocales(locale);
3290
- return true;
3291
- } catch {
3292
- return false;
3293
- }
3294
- }
3295
3285
  var validateLocalePipeline = (locale, schema, policy, customValidator) => {
3296
- const currentLocales = schema.supportedLocales ?? [];
3297
- const defaultLocale = schema.defaultLocale ?? "";
3298
- if (!isValidBcp47Locale(locale)) {
3286
+ const canonicalLocale = (0, import_core4.normalizeLocale)(locale);
3287
+ if (canonicalLocale === null) {
3299
3288
  return {
3300
3289
  valid: false,
3301
3290
  error: {
@@ -3304,21 +3293,23 @@ var validateLocalePipeline = (locale, schema, policy, customValidator) => {
3304
3293
  }
3305
3294
  };
3306
3295
  }
3307
- if (locale === defaultLocale || currentLocales.includes(locale)) {
3296
+ const currentLocales = (schema.supportedLocales ?? []).map((candidate) => (0, import_core4.normalizeLocale)(candidate) ?? candidate);
3297
+ const defaultLocale = schema.defaultLocale === void 0 ? "" : (0, import_core4.normalizeLocale)(schema.defaultLocale) ?? schema.defaultLocale;
3298
+ if (canonicalLocale === defaultLocale || currentLocales.includes(canonicalLocale)) {
3308
3299
  return {
3309
3300
  valid: false,
3310
3301
  error: {
3311
3302
  type: "locale_already_exists",
3312
- message: `Locale "${locale}" is already registered.`
3303
+ message: `Locale "${canonicalLocale}" is already registered.`
3313
3304
  }
3314
3305
  };
3315
3306
  }
3316
- if (policy?.allowedLocales !== void 0 && !policy.allowedLocales.includes(locale)) {
3307
+ if (policy?.allowedLocales !== void 0 && !policy.allowedLocales.some((candidate) => (0, import_core4.normalizeLocale)(candidate) === canonicalLocale)) {
3317
3308
  return {
3318
3309
  valid: false,
3319
3310
  error: {
3320
3311
  type: "locale_not_allowed",
3321
- message: `Locale "${locale}" is not allowed by policy.`
3312
+ message: `Locale "${canonicalLocale}" is not allowed by policy.`
3322
3313
  }
3323
3314
  };
3324
3315
  }
@@ -3333,8 +3324,13 @@ var validateLocalePipeline = (locale, schema, policy, customValidator) => {
3333
3324
  };
3334
3325
  }
3335
3326
  if (customValidator !== void 0) {
3336
- const customContext = policy === void 0 ? Object.assign([...currentLocales], { locale, defaultLocale, currentLocales }) : Object.assign([...currentLocales], { locale, defaultLocale, currentLocales, policy });
3337
- const customResult = customValidator(locale, customContext);
3327
+ const context = {
3328
+ locale: canonicalLocale,
3329
+ defaultLocale,
3330
+ currentLocales: Object.freeze([...currentLocales]),
3331
+ ...policy === void 0 ? {} : { policy }
3332
+ };
3333
+ const customResult = Reflect.apply(customValidator, void 0, [canonicalLocale, context]);
3338
3334
  if (customResult === false) {
3339
3335
  return {
3340
3336
  valid: false,
@@ -3487,7 +3483,13 @@ function useTranslationWorkspace({
3487
3483
  const addLocale = (0, import_react4.useCallback)(
3488
3484
  (locale) => {
3489
3485
  if (readOnly) return { success: false, error: "Workspace is read-only." };
3490
- const normalized = locale.trim();
3486
+ const normalized = (0, import_core4.normalizeLocale)(locale);
3487
+ if (normalized === null) {
3488
+ return {
3489
+ success: false,
3490
+ error: workspaceLocaleValidationMessage(validateLocalePipeline(locale, currentSchema, policy, validateLocale))
3491
+ };
3492
+ }
3491
3493
  const validation = validateLocalePipeline(normalized, currentSchema, policy, validateLocale);
3492
3494
  if (!validation.valid) return { success: false, error: workspaceLocaleValidationMessage(validation) };
3493
3495
  commit({
@@ -3502,7 +3504,8 @@ function useTranslationWorkspace({
3502
3504
  const isAddLocaleAllowed = (0, import_react4.useCallback)(
3503
3505
  (locale) => {
3504
3506
  if (readOnly) return false;
3505
- const normalized = locale.trim();
3507
+ const normalized = (0, import_core4.normalizeLocale)(locale);
3508
+ if (normalized === null) return false;
3506
3509
  return validateLocalePipeline(normalized, currentSchema, policy, validateLocale).valid;
3507
3510
  },
3508
3511
  [currentSchema, policy, readOnly, validateLocale]
package/dist/index.js CHANGED
@@ -3238,6 +3238,7 @@ import {
3238
3238
  collectSchemaLocales as collectSchemaLocales2,
3239
3239
  collectTranslationSlots,
3240
3240
  computeSourceTextHash,
3241
+ normalizeLocale,
3241
3242
  populateSchemaTranslations as populateSchemaTranslations2,
3242
3243
  removeLocaleFromSchema
3243
3244
  } from "@form-engine-ts/core";
@@ -3257,20 +3258,9 @@ function asAsyncAdapter(adapter) {
3257
3258
  )
3258
3259
  };
3259
3260
  }
3260
- function isValidBcp47Locale(locale) {
3261
- const language = locale.split("-")[0];
3262
- if (language === void 0 || !/^[a-z]{2,3}$/iu.test(language)) return false;
3263
- try {
3264
- Intl.getCanonicalLocales(locale);
3265
- return true;
3266
- } catch {
3267
- return false;
3268
- }
3269
- }
3270
3261
  var validateLocalePipeline = (locale, schema, policy, customValidator) => {
3271
- const currentLocales = schema.supportedLocales ?? [];
3272
- const defaultLocale = schema.defaultLocale ?? "";
3273
- if (!isValidBcp47Locale(locale)) {
3262
+ const canonicalLocale = normalizeLocale(locale);
3263
+ if (canonicalLocale === null) {
3274
3264
  return {
3275
3265
  valid: false,
3276
3266
  error: {
@@ -3279,21 +3269,23 @@ var validateLocalePipeline = (locale, schema, policy, customValidator) => {
3279
3269
  }
3280
3270
  };
3281
3271
  }
3282
- if (locale === defaultLocale || currentLocales.includes(locale)) {
3272
+ const currentLocales = (schema.supportedLocales ?? []).map((candidate) => normalizeLocale(candidate) ?? candidate);
3273
+ const defaultLocale = schema.defaultLocale === void 0 ? "" : normalizeLocale(schema.defaultLocale) ?? schema.defaultLocale;
3274
+ if (canonicalLocale === defaultLocale || currentLocales.includes(canonicalLocale)) {
3283
3275
  return {
3284
3276
  valid: false,
3285
3277
  error: {
3286
3278
  type: "locale_already_exists",
3287
- message: `Locale "${locale}" is already registered.`
3279
+ message: `Locale "${canonicalLocale}" is already registered.`
3288
3280
  }
3289
3281
  };
3290
3282
  }
3291
- if (policy?.allowedLocales !== void 0 && !policy.allowedLocales.includes(locale)) {
3283
+ if (policy?.allowedLocales !== void 0 && !policy.allowedLocales.some((candidate) => normalizeLocale(candidate) === canonicalLocale)) {
3292
3284
  return {
3293
3285
  valid: false,
3294
3286
  error: {
3295
3287
  type: "locale_not_allowed",
3296
- message: `Locale "${locale}" is not allowed by policy.`
3288
+ message: `Locale "${canonicalLocale}" is not allowed by policy.`
3297
3289
  }
3298
3290
  };
3299
3291
  }
@@ -3308,8 +3300,13 @@ var validateLocalePipeline = (locale, schema, policy, customValidator) => {
3308
3300
  };
3309
3301
  }
3310
3302
  if (customValidator !== void 0) {
3311
- const customContext = policy === void 0 ? Object.assign([...currentLocales], { locale, defaultLocale, currentLocales }) : Object.assign([...currentLocales], { locale, defaultLocale, currentLocales, policy });
3312
- const customResult = customValidator(locale, customContext);
3303
+ const context = {
3304
+ locale: canonicalLocale,
3305
+ defaultLocale,
3306
+ currentLocales: Object.freeze([...currentLocales]),
3307
+ ...policy === void 0 ? {} : { policy }
3308
+ };
3309
+ const customResult = Reflect.apply(customValidator, void 0, [canonicalLocale, context]);
3313
3310
  if (customResult === false) {
3314
3311
  return {
3315
3312
  valid: false,
@@ -3462,7 +3459,13 @@ function useTranslationWorkspace({
3462
3459
  const addLocale = useCallback3(
3463
3460
  (locale) => {
3464
3461
  if (readOnly) return { success: false, error: "Workspace is read-only." };
3465
- const normalized = locale.trim();
3462
+ const normalized = normalizeLocale(locale);
3463
+ if (normalized === null) {
3464
+ return {
3465
+ success: false,
3466
+ error: workspaceLocaleValidationMessage(validateLocalePipeline(locale, currentSchema, policy, validateLocale))
3467
+ };
3468
+ }
3466
3469
  const validation = validateLocalePipeline(normalized, currentSchema, policy, validateLocale);
3467
3470
  if (!validation.valid) return { success: false, error: workspaceLocaleValidationMessage(validation) };
3468
3471
  commit({
@@ -3477,7 +3480,8 @@ function useTranslationWorkspace({
3477
3480
  const isAddLocaleAllowed = useCallback3(
3478
3481
  (locale) => {
3479
3482
  if (readOnly) return false;
3480
- const normalized = locale.trim();
3483
+ const normalized = normalizeLocale(locale);
3484
+ if (normalized === null) return false;
3481
3485
  return validateLocalePipeline(normalized, currentSchema, policy, validateLocale).valid;
3482
3486
  },
3483
3487
  [currentSchema, policy, readOnly, validateLocale]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@form-engine-ts/react",
3
- "version": "4.7.0",
3
+ "version": "4.8.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -42,8 +42,8 @@
42
42
  "typescript"
43
43
  ],
44
44
  "dependencies": {
45
- "@form-engine-ts/core": "4.7.0",
46
- "@form-engine-ts/privacy": "4.7.0"
45
+ "@form-engine-ts/privacy": "4.8.0",
46
+ "@form-engine-ts/core": "4.8.0"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "react": ">=18.2 <20",