Skip to content

Add basic i18n and l10n capabilities #111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion jsonschema/_format.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import datetime
import re
import socket
from strings import ErrorStrings as strings

from jsonschema.compat import PY3

Expand Down Expand Up @@ -89,7 +90,7 @@ def check(self, instance, format):
cause = e
if not result:
raise FormatError(
"%r is not a %r" % (instance, format), cause=cause,
strings.is_not_a % (instance, format), cause=cause,
)

def conforms(self, instance, format):
Expand Down
3 changes: 2 additions & 1 deletion jsonschema/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import json
import re
import os
from strings import ErrorStrings as strings

from jsonschema.compat import str_types, MutableMapping, urlsplit

Expand Down Expand Up @@ -126,7 +127,7 @@ def types_msg(instance, types):
reprs.append(repr(type["name"]))
except Exception:
reprs.append(repr(type))
return "%r is not of type %s" % (instance, ", ".join(reprs))
return strings.not_a_type_of % (instance, ", ".join(reprs))


def flatten(suitable_for_isinstance):
Expand Down
34 changes: 34 additions & 0 deletions jsonschema/strings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from __future__ import unicode_literals
try:
from gettext import gettext as _ # python 3
except ImportError:
_ = gettext.translation(my_program_name).ugettext # python 2


class ErrorStrings:
additional_properties_not_allowed = _(
"Additional properties are not allowed (%s %s unexpected)")
additional_items_not_allowed = _(
"Additional items are not allowed (%s %s unexpected)")
minimum_less_than = _("%r is less than the minimum of %r")
minimum_less_than_or_equal = _(
"%r is less than or equal to the minimum of %r")
maximum_more_than = _("%r is more than the maximum of %r")
maximum_more_than_or_equal = _(
"%r is more than or equal to the maximum of %r")
not_multiple_of = _("%r is not a multiple of %r")
too_short = _("%r is too short")
too_long = _("%r is too long")
non_unique_items = _("%r has non-unique elements")
does_not_match = _("%r does not match %r")
is_dependency = _("%r is a dependency of %r")
not_one_of = _("%r is not one of %r")
required_property = _("%r is a required property")
disallowed = _("%r is disallowed for %r")
not_valid_in_any_schema = _(
"%r is not valid under any of the given schemas")
valid_in_all_schemas = _("%r is valid under each of %s")
not_allowed = _("%r is not allowed for %r")
unresolvable_json_pointer = _("Unresolvable JSON pointer: %r")
not_a_type_of = _("%r is not of type %s")
is_not_a = _("%r is not a %r")
87 changes: 51 additions & 36 deletions jsonschema/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pprint
import re
import textwrap
from strings import ErrorStrings as strings

try:
import requests
Expand Down Expand Up @@ -259,8 +260,7 @@ def validate_additionalProperties(self, aP, instance, schema):
for error in self.descend(instance[extra], aP, path=extra):
yield error
elif not aP and extras:
error = "Additional properties are not allowed (%s %s unexpected)"
yield ValidationError(error % _utils.extras_msg(extras))
yield ValidationError(strings.additional_properties_not_allowed % _utils.extras_msg(extras))

def validate_items(self, items, instance, schema):
if not self.is_type(instance, "array"):
Expand Down Expand Up @@ -290,7 +290,7 @@ def validate_additionalItems(self, aI, instance, schema):
for error in self.descend(item, aI, path=index):
yield error
elif not aI and len(instance) > len(schema.get("items", [])):
error = "Additional items are not allowed (%s %s unexpected)"
error = strings.additional_items_not_allowed
yield ValidationError(
error %
_utils.extras_msg(instance[len(schema.get("items", [])):])
Expand All @@ -303,15 +303,16 @@ def validate_minimum(self, minimum, instance, schema):
instance = float(instance)
if schema.get("exclusiveMinimum", False):
failed = instance <= minimum
cmp = "less than or equal to"
if failed:
yield ValidationError(
strings.minimum_less_than_or_equal % (instance, minimum)
)
else:
failed = instance < minimum
cmp = "less than"

if failed:
yield ValidationError(
"%r is %s the minimum of %r" % (instance, cmp, minimum)
)
if failed:
yield ValidationError(
strings.minimum_less_than % (instance, minimum)
)

def validate_maximum(self, maximum, instance, schema):
if not self.is_type(instance, "number"):
Expand All @@ -320,15 +321,16 @@ def validate_maximum(self, maximum, instance, schema):
instance = float(instance)
if schema.get("exclusiveMaximum", False):
failed = instance >= maximum
cmp = "greater than or equal to"
if failed:
yield ValidationError(
strings.maximum_more_than_or_equal % (instance, maximum)
)
else:
failed = instance > maximum
cmp = "greater than"

if failed:
yield ValidationError(
"%r is %s the maximum of %r" % (instance, cmp, maximum)
)
if failed:
yield ValidationError(
strings.maximum_more_than % (instance, maximum)
)

def _validate_multipleOf(self, dB, instance, schema):
if not self.is_type(instance, "number"):
Expand All @@ -342,28 +344,28 @@ def _validate_multipleOf(self, dB, instance, schema):

if failed:
yield ValidationError(
"%r is not a multiple of %r" % (instance, dB)
strings.not_multiple_of % (instance, dB)
)

def validate_minItems(self, mI, instance, schema):
if self.is_type(instance, "array") and len(instance) < mI:
yield ValidationError("%r is too short" % (instance,))
yield ValidationError(strings.too_short % (instance,))

def validate_maxItems(self, mI, instance, schema):
if self.is_type(instance, "array") and len(instance) > mI:
yield ValidationError("%r is too long" % (instance,))
yield ValidationError(strings.too_long % (instance,))

def validate_uniqueItems(self, uI, instance, schema):
if (
uI and
self.is_type(instance, "array") and
not _utils.uniq(instance)
):
yield ValidationError("%r has non-unique elements" % instance)
yield ValidationError(strings.non_unique_items % instance)

def validate_pattern(self, patrn, instance, schema):
if self.is_type(instance, "string") and not re.search(patrn, instance):
yield ValidationError("%r does not match %r" % (instance, patrn))
yield ValidationError(strings.does_not_match % (instance, patrn))

def validate_format(self, format, instance, schema):
if (
Expand All @@ -377,11 +379,11 @@ def validate_format(self, format, instance, schema):

def validate_minLength(self, mL, instance, schema):
if self.is_type(instance, "string") and len(instance) < mL:
yield ValidationError("%r is too short" % (instance,))
yield ValidationError(strings.too_short % (instance,))

def validate_maxLength(self, mL, instance, schema):
if self.is_type(instance, "string") and len(instance) > mL:
yield ValidationError("%r is too long" % (instance,))
yield ValidationError(strings.too_long % (instance,))

def validate_dependencies(self, dependencies, instance, schema):
if not self.is_type(instance, "object"):
Expand All @@ -401,12 +403,12 @@ def validate_dependencies(self, dependencies, instance, schema):
for dependency in dependencies:
if dependency not in instance:
yield ValidationError(
"%r is a dependency of %r" % (dependency, property)
strings.is_dependency % (dependency, property)
)

def validate_enum(self, enums, instance, schema):
if instance not in enums:
yield ValidationError("%r is not one of %r" % (instance, enums))
yield ValidationError(strings.not_one_of % (instance, enums))

def validate_ref(self, ref, instance, schema):
with self.resolver.resolving(ref) as resolved:
Expand Down Expand Up @@ -455,7 +457,7 @@ def validate_properties(self, properties, instance, schema):
):
yield error
elif subschema.get("required", False):
error = ValidationError("%r is a required property" % property)
error = ValidationError(strings.required_property % property)
error._set(
validator="required",
validator_value=subschema["required"],
Expand All @@ -470,7 +472,7 @@ def validate_disallow(self, disallow, instance, schema):
for disallowed in _utils.ensure_list(disallow):
if self.is_valid(instance, {"type" : [disallowed]}):
yield ValidationError(
"%r is disallowed for %r" % (disallowed, instance)
strings.disallowed % (disallowed, instance)
)

def validate_extends(self, extends, instance, schema):
Expand Down Expand Up @@ -519,17 +521,17 @@ def validate_required(self, required, instance, schema):
return
for property in required:
if property not in instance:
yield ValidationError("%r is a required property" % property)
yield ValidationError(strings.required_property % property)

def validate_minProperties(self, mP, instance, schema):
if self.is_type(instance, "object") and len(instance) < mP:
yield ValidationError("%r is too short" % (instance,))
yield ValidationError(strings.too_short % (instance,))

def validate_maxProperties(self, mP, instance, schema):
if not self.is_type(instance, "object"):
return
if self.is_type(instance, "object") and len(instance) > mP:
yield ValidationError("%r is too short" % (instance,))
yield ValidationError(strings.too_long % (instance,))

def validate_allOf(self, allOf, instance, schema):
for index, subschema in enumerate(allOf):
Expand All @@ -547,7 +549,7 @@ def validate_oneOf(self, oneOf, instance, schema):
all_errors.extend(errors)
else:
yield ValidationError(
"%r is not valid under any of the given schemas" % (instance,),
strings.not_valid_in_any_schema % (instance,),
context=all_errors,
)

Expand All @@ -556,7 +558,7 @@ def validate_oneOf(self, oneOf, instance, schema):
more_valid.append(first_valid)
reprs = ", ".join(repr(schema) for schema in more_valid)
yield ValidationError(
"%r is valid under each of %s" % (instance, reprs)
strings.valid_in_all_schemas % (instance, reprs)
)

def validate_anyOf(self, anyOf, instance, schema):
Expand All @@ -568,14 +570,14 @@ def validate_anyOf(self, anyOf, instance, schema):
all_errors.extend(errors)
else:
yield ValidationError(
"%r is not valid under any of the given schemas" % (instance,),
strings.not_valid_in_any_schema % (instance,),
context=all_errors,
)

def validate_not(self, not_schema, instance, schema):
if self.is_valid(instance, not_schema):
yield ValidationError(
"%r is not allowed for %r" % (not_schema, instance)
strings.not_allowed % (not_schema, instance)
)

validate_multipleOf = _Draft34CommonMixin._validate_multipleOf
Expand Down Expand Up @@ -690,7 +692,7 @@ def resolve_fragment(self, document, fragment):
document = document[part]
except (TypeError, LookupError):
raise RefResolutionError(
"Unresolvable JSON pointer: %r" % fragment
strings.unresolvable_json_pointer % fragment
)

return document
Expand Down Expand Up @@ -808,3 +810,16 @@ def validate(instance, schema, cls=None, *args, **kwargs):
cls = meta_schemas.get(schema.get("$schema", ""), Draft4Validator)
cls.check_schema(schema)
cls(schema, *args, **kwargs).validate(instance)


def set_error_strings(error_string_cls):
"""
Set the class containing error strings, so that it can
be changed and local to the application itself.

The class should be a subclass of strings.ErrorStrings
and overwrite any strings that the application owner
finds necessary.
"""
global strings
strings = error_string_cls