fabian-hiller / modular-forms

The modular and type-safe form library for SolidJS, Qwik and Preact
https://modularforms.dev
MIT License
995 stars 53 forks source link

[Valibot/i18n] Client side validation is not translated #190

Open Ashyni opened 6 months ago

Ashyni commented 6 months ago

Hello,

I know i18n is still new on valibot, i open this issue just to think about it.

Client side validation is not translated if globally set by v.setGlobalConfig({ lang: "en" }); and we currently can't pass options to valiForm() to set it locally.

Could be resolved by getting the global config in _parse() or use safeParse() which internally use _parse(input, getGlobalConfig(config));.

fabian-hiller commented 6 months ago

Thank you for creating this issue! You are right. The current implementation does not support i18n. I will improve this.

fabian-hiller commented 6 months ago

There is a small problem. Valibot is currently only a dev dependency of Modular Forms. Therefore I can only import types and not JavaScript functions like safeParse or getGlobalConfig. To be able to import it, I have to add Valibot as a peer dependency, but this would trigger a warning for any user using Modular Forms without Valibot.

The bigger problem is the current structure of Modular Forms packages. Normally I should release the adapters as a separate package. I plan to improve this when I rewrite the entire library, but that will take some time. For now, as a workaround, I recommend adding the updated valiForm adapter to your source code:

import type {
  FieldValues,
  ValidateForm,
  PartialValues,
  FormErrors,
} from '@modular-forms/solid';
import { type BaseSchema, type BaseSchemaAsync, safeParseAsync } from 'valibot';

/**
 * Creates a validation functions that parses the Valibot schema of a form.
 *
 * @param schema A Valibot schema.
 *
 * @returns A validation function.
 */
export function valiForm<TFieldValues extends FieldValues>(
  schema: BaseSchema<TFieldValues, any> | BaseSchemaAsync<TFieldValues, any>
): ValidateForm<TFieldValues> {
  return async (values: PartialValues<TFieldValues>) => {
    const result = await safeParseAsync(schema, values, {
      abortPipeEarly: true,
    });
    return result.issues
      ? result.issues.reduce<FormErrors<TFieldValues>>(
          (errors, issue) => ({
            ...errors,
            [issue.path!.map(({ key }) => key).join('.')]: issue.message,
          }),
          {}
        )
      : {};
  };
}