ivanhofer/typesafe-i18n-demo-sveltekit

Load Dictionaries inside +page.server.ts to use with SvelteKit's FormActions?

Closed this issue · 5 comments

Hi there,

first of all, thanks for your amazing work. This library saves us a lot of time and I appreciate your help!

Our current SvelteKit project uses SK's FormActions to progessively enhance our contact form. With this setup and the tooling you provide, is it currently possible to access dictionaries outside of the PageServerLoad Interface that the load() function provides? I couldn't find an example for this and it seems like we can only access the dictionaries with the locals parameter.

Have I missed something here?

I don't fully understand what you are trying to achive. Can you please give me more details?

@ivanhofer Sure, take a look at the following example of a FormAction that lives inside our page.server.ts. This example shows how the FormAction receives and validates the form data, and passing validation, POSTS the data.

If validation of the formData fails, an invalid() response is sent back to the front-end. In this case, here is where we would like to localize the message that informs the user that validation has failed. Sure, we could just capture the status in the front end, but in this case, we would still have yup's schema validation messages to worry about: yup.string().required("Validation error for someField")

// +page.server.ts

const formSchema = yup.object().shape({
    firstName: yup.string().required('Please provide a first name'), // Would like to localize this message that displays on validation error
    email: yup.string().email().required('Please provide an email address') // Would like to localize this message that displays on validation error
})

export const actions: Actions = {
    default: async ({ request }: RequestEvent) => {
        const formData = await request.formData()
        const data = Object.fromEntries(formData.entries())

        // FormData validation
        try {
            await formSchema.validate({ ...data }) // Validation of form data with yup
		} catch (err) { // err is filled by yup if validation fails and contains details on which field failed validation
            return invalid(400, {
                values: {...data},
                status: 400,
                message: 'Invalid form data. Please fill out all required fields.', // Would like to localize this message too
				validationError: {
					path: err.path,
                    type: err.type,
                    message: err.errors[0], 
				}
            })
        }

		// Fetch if not returned at this point
		// const res = await fetch("https://example.com", { method: "POST", body: data })
		
    },
}

You can do it like this:

// +page.server.ts
import type { TranslationFunctions } from '$i18n'

const initFormSchema = (LL: TranslationFunctions) => yup.object().shape({
    firstName: yup.string().required(LL.validation.firstName()), // Would like to localize this message that displays on validation error
    email: yup.string().email().required(LL.validation.email()) // Would like to localize this message that displays on validation error
})

export const actions: Actions = {
    default: async ({ request, locals }: RequestEvent) => {
        const formData = await request.formData()
        const data = Object.fromEntries(formData.entries())

        // FormData validation
        try {
            await initFormSchema(locals.LL).validate({ ...data }) // Validation of form data with yup
		} catch (err) { // err is filled by yup if validation fails and contains details on which field failed validation
            return invalid(400, {
                values: {...data},
                status: 400,
                message: 'Invalid form data. Please fill out all required fields.', // Would like to localize this message too
				validationError: {
					path: err.path,
                    type: err.type,
                    message: err.errors[0], 
				}
            })
        }

		// Fetch if not returned at this point
		// const res = await fetch("https://example.com", { method: "POST", body: data })
		
    },
}

@ivanhofer Works like a charm. I just wasn't aware that custom data from the handle hook is also available inside Actions. Thanks a lot for your help!

you're welcome