jonsamwell / angular-auto-validate

An automatic validation module for AngularJS which gets rid of excess html in favour of dynamic element modification to notify the user of validation errors
MIT License
346 stars 76 forks source link

Enable i18n #3

Closed jgoux closed 9 years ago

jgoux commented 10 years ago

Hello, firstly, thanks for this great lib ! Would it be possible to extract the errorMessages object (https://github.com/jonsamwell/angular-auto-validate/blob/master/src/services/defaultErrorMessageResolver.js#L20) to be able to translate it easily, as a separate file from the dist ? Then we could be able to load the right langage at the app initialization or by including the right file. Example : /dist jcs-auto-validate.min.js /lang jcs-auto-validate-en-US.js jcs-auto-validate-fr-FR.js ...

jonsamwell commented 10 years ago

Hey, yeah this is a great idea! I think the errorMessages object in the defaultErrorMessageResolver could be abstracted out and loaded in via a i18n file as you suggest. I would want a default there so a user didn't have to add the jcs-auto-validate-en-US.js file (for example) if they just wanted English.

I think we would also have to provide another method on the validator provider to enable someone to set the culture which would then download the correct file in addition to just being able to include the i18n file.

validator.setCulture('fr-FR');

jgoux commented 10 years ago

This is exactly what I need. :+1: Default langage if no file included : English langage (hardcoded) If the user include one langage file after your lib : Load this langage file as default (so create an options object or something like that) If the user uses the validator.setCulture('some langage') : Load the corresponding file (very useful for international apps where the user can switch the langage)

Last suggestion, maybe you could interact with the excellent http://angular-translate.github.io/ to add this feature.

jonsamwell commented 10 years ago

On second thoughts this might be better achieved with a new ErrorMessageResolver. The user could then just set this error message resolver as the default along with the culture and it would either get the culture file or use the included one.

angular.module('jcs-autoValidate')
.factory('i18nErrorMessageResolver', [
    function () {
        var setCulture = function (culture) {
                // we download the culture file or check if it is loaded
                // the culture file could set and object on the angular window object
                // angular.autoValidate.errorMessages or something?
            },
            resolve = function (errorType, el) {
                // get from loaded i18n file - something like
                // angular.autoValidate.errorMessages[currentCulture][errorType]
            };

        return {
            setCulture: setCulture,
            resolve: resolve
        };
    }
]);

jonsamwell commented 10 years ago

@jgoux Yes the http://angular-translate.github.io/ is awesome. I was going to create a new ErrorMessageResolver to do the interaction with that library.

I'll have a play with those ideas and see what works best.

jgoux commented 10 years ago

Thanks a lot !

jonsamwell commented 10 years ago

@jgoux are you able to provide the French version of the error messages?

jgoux commented 10 years ago

Yes, I'm just waiting for the english file to translate it. :)

jonsamwell commented 10 years ago

Great it will look like this. I had a problem with loading scripts on the fly and knowing when the script has loaded (incase you change culture at any point after all the scripts have loaded) so I had to make the file a json file as I need to know when the file has been loaded which is hard without JQuery and I don't want this module to depend on JQuery. However, I think the solution is nice.

{
    "defaultMsg": "Please add error message for {0}",
    "email": "Please enter a valid email address",
    "minlength": "Please enter at least {0} characters",
    "maxlength": "You have entered more than the maximum {0} characters",
    "min": "Please enter the minimum number of {0}",
    "max": "Please enter the maximum number of {0}",
    "required": "This field is required",
    "date": "Please enter a valid date",
    "pattern": "Please ensure the entered information adheres to this pattern {0}",
    "number": "Please enter a valid number",
    "url": "Please enter a valid URL in the format of http(s)://wwww.google.com"
}
jgoux commented 10 years ago

Here is the french translation :

{
    "defaultMsg": "Veuillez ajouter un message d'erreur pour {0}",
    "email": "Veuillez saisir une adresse email valide",
    "minlength": "Veuillez saisir au moins {0} caractères",
    "maxlength": "Vous avez dépassé la limite de {0} caractères",
    "min": "Veuillez saisir un nombre supérieur ou égal à {0}",
    "max": "Veuillez saisir un nombre inférieur ou égal à {0}",
    "required": "Ce champ est obligatoire",
    "date": "Veuillez saisir une date valide",
    "pattern": "Veuillez vous assurer que les informations saisies correspondent au format {0}",
    "number": "Veuillez saisir un nombre valide",
    "url": "Veuillez saisir une URL valide sous la forme http(s)://wwww.google.com"
}

If it can give you ideas about the validation messages, I really like the way Laravel (PHP framework) write them : https://github.com/laravel/laravel/blob/master/app/lang/en/validation.php

And you can find all the translations here : https://github.com/caouecs/Laravel4-lang (file validation.php in each folder)

jgoux commented 10 years ago

Also, but it's maybe outside of the scope of the module, there is a port of the Laravel validation system in vanilla JS here : https://github.com/skaterdav85/validatorjs Very convenient because it has a lot of custom validations, and you can retrieve the messages easily. I began a validation module to wrap validatorjs with angular by doing something like :

<input type="text" name="userName" ng-model="user.name" validator="required|min:2|max:255">

But then I found your module. I wish I could have the best of the two. ^^

jonsamwell commented 10 years ago

Hi @jgoux Yes I quite like these ideas! Lets get this out of the way and we can have a look into them, :+1:

I've commit to the master branch a first pass of the i18n stuff - it you wouldn't mind giving it a go and see if it works. You can look at the testPage.html in the test folder for an example but effectively all you need to do is set the culture you want (the only cultures we currently have is English and French though).

app.run([
            'defaultErrorMessageResolver',
            function (defaultErrorMessageResolver) {
                 // by default the culture file will be requested from js/angular-auto-validate/lang/jcs-auto-validate_xx-xx.json so setting this will change the path that the file gets requested from
                defaultErrorMessageResolver.setI18nFileRootPath('../src/lang/');

                // set the culture you want here - this returns a promise which is resolved when the culture has been loaded.
                defaultErrorMessageResolver.setCulture('fr-FR');
            }
        ]);
jonsamwell commented 10 years ago

Sorted with release v1.0.7. I'm just about to update the docs now. :-)

jonsamwell commented 10 years ago

Docs have been updated here http://jonsamwell.github.io/angular-auto-validate/#i18n

jgoux commented 10 years ago

Sorry to reopen this issue but I'm having a hard time with the current system. As I minify all my sources, I'd like to avoid to include the .json lang files. I also want to avoid to set the culture directly into my code if I include only one culture. I think it would be better to turn langs files into javascript files as momentjs lib do : https://github.com/moment/moment/blob/develop/locale/en-gb.js With this system, I just have to include the lang file after my moment.js and everything works as expected, I don't have to set anything in my code (even if the function is available if I want to add more than one file). momentjs has also a build including all the langages with its core, so you just drop the file and every langages are available.

What do you think about it @jonsamwell ?

jonsamwell commented 10 years ago

The only trouble with doing this is if you have an application that need to swap cultures during the application lifetime, the module would need to request a javascript file and would have no way of knowing when the file has been loaded to know when it can serve the validation message in the requested culture.

Including all the lang file you need in your application seems wasteful to me in terms of bandwidth especially on a mobile.

I'll have a think, maybe we can support both ways?

jgoux commented 10 years ago

If you look at : https://github.com/moment/moment/blob/develop/moment.js#L1927 You can swap cultures during the application lifetime as well because each culture included is registered in memory in a locales[] array. So you don't even have load time. :) I think we could support both, even if IMO once the langage file is cached, it won't change so often, so having them in memory is acceptable.

EDIT : This is not urgent at all, I'll drop the lang folder into my assets for now. ^^

jonsamwell commented 10 years ago

OK, I'll have a look at this at the weekend :-)