Skip to content

Commit 7726af0

Browse files
committed
Add I18n and locale to validation
1 parent 2195538 commit 7726af0

File tree

8 files changed

+142
-23
lines changed

8 files changed

+142
-23
lines changed

src/main/java/graphql/ExecutionInput.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ public static class Builder {
225225
//
226226
private DataLoaderRegistry dataLoaderRegistry = DataLoaderDispatcherInstrumentationState.EMPTY_DATALOADER_REGISTRY;
227227
private CacheControl cacheControl = CacheControl.newCacheControl();
228-
private Locale locale;
228+
private Locale locale = Locale.getDefault();
229229
private ExecutionId executionId;
230230

231231
public Builder query(String query) {

src/main/java/graphql/GraphQL.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ private List<ValidationError> validate(ExecutionInput executionInput, Document d
623623
validationCtx.onDispatched(cf);
624624

625625
Predicate<Class<?>> validationRulePredicate = executionInput.getGraphQLContext().getOrDefault(ParseAndValidate.INTERNAL_VALIDATION_PREDICATE_HINT, r -> true);
626-
List<ValidationError> validationErrors = ParseAndValidate.validate(graphQLSchema, document, validationRulePredicate);
626+
List<ValidationError> validationErrors = ParseAndValidate.validate(graphQLSchema, document, validationRulePredicate, executionInput.getLocale());
627627

628628
validationCtx.onCompleted(validationErrors, null);
629629
cf.complete(validationErrors);

src/main/java/graphql/ParseAndValidate.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import graphql.validation.Validator;
1010

1111
import java.util.List;
12+
import java.util.Locale;
1213
import java.util.function.Predicate;
1314

1415
/**
@@ -40,7 +41,7 @@ public class ParseAndValidate {
4041
public static ParseAndValidateResult parseAndValidate(GraphQLSchema graphQLSchema, ExecutionInput executionInput) {
4142
ParseAndValidateResult result = parse(executionInput);
4243
if (!result.isFailure()) {
43-
List<ValidationError> errors = validate(graphQLSchema, result.getDocument());
44+
List<ValidationError> errors = validate(graphQLSchema, result.getDocument(), executionInput.getLocale());
4445
return result.transform(builder -> builder.validationErrors(errors));
4546
}
4647
return result;
@@ -74,8 +75,8 @@ public static ParseAndValidateResult parse(ExecutionInput executionInput) {
7475
*
7576
* @return a result object that indicates how this operation went
7677
*/
77-
public static List<ValidationError> validate(GraphQLSchema graphQLSchema, Document parsedDocument) {
78-
return validate(graphQLSchema, parsedDocument, ruleClass -> true);
78+
public static List<ValidationError> validate(GraphQLSchema graphQLSchema, Document parsedDocument, Locale locale) {
79+
return validate(graphQLSchema, parsedDocument, ruleClass -> true, locale);
7980
}
8081

8182
/**
@@ -87,8 +88,8 @@ public static List<ValidationError> validate(GraphQLSchema graphQLSchema, Docume
8788
*
8889
* @return a result object that indicates how this operation went
8990
*/
90-
public static List<ValidationError> validate(GraphQLSchema graphQLSchema, Document parsedDocument, Predicate<Class<?>> rulePredicate) {
91+
public static List<ValidationError> validate(GraphQLSchema graphQLSchema, Document parsedDocument, Predicate<Class<?>> rulePredicate, Locale locale) {
9192
Validator validator = new Validator();
92-
return validator.validateDocument(graphQLSchema, parsedDocument, rulePredicate);
93+
return validator.validateDocument(graphQLSchema, parsedDocument, rulePredicate, locale);
9394
}
9495
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package graphql.i18n;
2+
3+
import graphql.Internal;
4+
import graphql.VisibleForTesting;
5+
6+
import java.text.MessageFormat;
7+
import java.util.Locale;
8+
import java.util.MissingResourceException;
9+
import java.util.ResourceBundle;
10+
11+
import static graphql.Assert.assertNotNull;
12+
import static graphql.Assert.assertShouldNeverHappen;
13+
14+
@Internal
15+
public class I18n {
16+
17+
/**
18+
* This enum is a type safe way to control what resource bundle to load from
19+
*/
20+
public enum BundleType {
21+
Validation,
22+
Execution,
23+
General;
24+
25+
private final String baseName;
26+
27+
BundleType() {
28+
this.baseName = "i18n." + this.name();
29+
}
30+
}
31+
32+
private final ResourceBundle resourceBundle;
33+
34+
@VisibleForTesting
35+
protected I18n(BundleType bundleType, Locale locale) {
36+
assertNotNull(bundleType);
37+
assertNotNull(locale);
38+
this.resourceBundle = ResourceBundle.getBundle(bundleType.baseName, locale);
39+
}
40+
41+
public ResourceBundle getResourceBundle() {
42+
return resourceBundle;
43+
}
44+
45+
public static I18n i18n(BundleType bundleType, Locale locale) {
46+
return new I18n(bundleType, locale);
47+
}
48+
49+
50+
/**
51+
* Creates an I18N message using the key and arguments
52+
*
53+
* @param msgKey the key in the underlying message bundle
54+
* @param msgArgs the message arguments
55+
*
56+
* @return the formatted I18N message
57+
*/
58+
@SuppressWarnings("UnnecessaryLocalVariable")
59+
public String msg(String msgKey, Object... msgArgs) {
60+
String msgPattern = null;
61+
try {
62+
msgPattern = resourceBundle.getString(msgKey);
63+
} catch (MissingResourceException e) {
64+
assertShouldNeverHappen("There must be a resource bundle key called %s", msgKey);
65+
}
66+
67+
String formattedMsg = new MessageFormat(msgPattern).format(msgArgs);
68+
return formattedMsg;
69+
}
70+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package graphql.i18n;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
import static java.util.Arrays.asList;
7+
8+
/**
9+
* A class that represents the intention to create a I18n message
10+
*/
11+
public class I18nMsg {
12+
private final String msgKey;
13+
private final List<Object> msgArguments;
14+
15+
public I18nMsg(String msgKey, List<Object> msgArguments) {
16+
this.msgKey = msgKey;
17+
this.msgArguments = msgArguments;
18+
}
19+
20+
public I18nMsg(String msgKey, Object... msgArguments) {
21+
this.msgKey = msgKey;
22+
this.msgArguments = asList(msgArguments);
23+
}
24+
25+
public String getMsgKey() {
26+
return msgKey;
27+
}
28+
29+
public Object[] getMsgArguments() {
30+
return msgArguments.toArray();
31+
}
32+
33+
public I18nMsg argumentAt(int index, Object argument) {
34+
List<Object> newArgs = new ArrayList<>(this.msgArguments);
35+
newArgs.add(index, argument);
36+
return new I18nMsg(this.msgKey, newArgs);
37+
}
38+
39+
public String toI18n(I18n i18n) {
40+
return i18n.msg(msgKey, msgArguments);
41+
}
42+
}

src/main/java/graphql/nextgen/GraphQL.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ private List<ValidationError> validate(ExecutionInput executionInput, Document d
265265
validationCtx.onDispatched(cf);
266266

267267
Predicate<Class<?>> validationRulePredicate = executionInput.getGraphQLContext().getOrDefault(ParseAndValidate.INTERNAL_VALIDATION_PREDICATE_HINT, r -> true);
268-
List<ValidationError> validationErrors = ParseAndValidate.validate(graphQLSchema, document, validationRulePredicate);
268+
List<ValidationError> validationErrors = ParseAndValidate.validate(graphQLSchema, document, validationRulePredicate, executionInput.getLocale());
269269

270270
validationCtx.onCompleted(validationErrors, null);
271271
cf.complete(validationErrors);

src/main/java/graphql/validation/ValidationContext.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33

44
import graphql.Internal;
5+
import graphql.i18n.I18n;
56
import graphql.language.Definition;
67
import graphql.language.Document;
78
import graphql.language.FragmentDefinition;
@@ -25,12 +26,13 @@ public class ValidationContext {
2526

2627
private final TraversalContext traversalContext;
2728
private final Map<String, FragmentDefinition> fragmentDefinitionMap = new LinkedHashMap<>();
29+
private final I18n i18n;
2830

29-
30-
public ValidationContext(GraphQLSchema schema, Document document) {
31+
public ValidationContext(GraphQLSchema schema, Document document, I18n i18n) {
3132
this.schema = schema;
3233
this.document = document;
3334
this.traversalContext = new TraversalContext(schema);
35+
this.i18n = i18n;
3436
buildFragmentMap();
3537
}
3638

@@ -82,11 +84,26 @@ public GraphQLOutputType getOutputType() {
8284
return traversalContext.getOutputType();
8385
}
8486

85-
8687
public List<String> getQueryPath() {
8788
return traversalContext.getQueryPath();
8889
}
8990

91+
public I18n getI18n() {
92+
return i18n;
93+
}
94+
95+
/**
96+
* Creates an I18N message using the key and arguments
97+
*
98+
* @param msgKey the key in the underlying message bundle
99+
* @param msgArgs the message arguments
100+
*
101+
* @return the formatted I18N message
102+
*/
103+
public String i18n(String msgKey, Object... msgArgs) {
104+
return i18n.msg(msgKey, msgArgs);
105+
}
106+
90107
@Override
91108
public String toString() {
92109
return "ValidationContext{" + getQueryPath() + "}";

src/main/java/graphql/validation/ValidationError.java

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,22 +63,11 @@ private ValidationError(Builder builder) {
6363
this.locations.addAll(builder.sourceLocations);
6464
}
6565
this.description = builder.description;
66-
this.message = mkMessage(builder.validationErrorType, builder.description, builder.queryPath);
66+
this.message = builder.description;
6767
this.queryPath = builder.queryPath;
6868
this.extensions = builder.extensions;
6969
}
7070

71-
private String mkMessage(ValidationErrorClassification validationErrorType, String description, List<String> queryPath) {
72-
return String.format("Validation error of type %s: %s%s", validationErrorType, description, toPath(queryPath));
73-
}
74-
75-
private String toPath(List<String> queryPath) {
76-
if (queryPath == null) {
77-
return "";
78-
}
79-
return String.format(" @ '%s'", String.join("/", queryPath));
80-
}
81-
8271
public ValidationErrorClassification getValidationErrorType() {
8372
return validationErrorType;
8473
}

0 commit comments

Comments
 (0)