From 3d47ff607d0e5e61a5fe4f48cbc7d0c95872d76d Mon Sep 17 00:00:00 2001 From: Meemaw Date: Sat, 17 Oct 2026 22:00:04 +0200 Subject: [PATCH] Format i18n message arguments with the message locale I18n.msgImpl created its MessageFormat without a locale, so message arguments such as line and column numbers were formatted with the JVM default locale rather than the locale the message was requested in. On a JVM whose default locale is for example sl_SI, an English message renders -1 with a unicode minus sign and 1234 as "1.234", which also made StringValueParsingUnicodeTest fail on such machines. Co-Authored-By: Claude Opus 5.5 --- src/main/java/graphql/i18n/I18n.java | 3 ++- src/test/groovy/graphql/i18n/I18nTest.groovy | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/i18n/I18n.java b/src/main/java/graphql/i18n/I18n.java index 6898f7be8b..0f6ceed6cd 100644 --- a/src/main/java/graphql/i18n/I18n.java +++ b/src/main/java/graphql/i18n/I18n.java @@ -89,6 +89,7 @@ private String msgImpl(String msgKey, Object[] msgArgs) { } catch (MissingResourceException e) { assertShouldNeverHappen("There must be a resource bundle key called %s", msgKey); } - return new MessageFormat(msgPattern).format(msgArgs); + // format any arguments (eg numbers) with the same locale as the message rather than the JVM default locale + return new MessageFormat(msgPattern, locale).format(msgArgs); } } diff --git a/src/test/groovy/graphql/i18n/I18nTest.groovy b/src/test/groovy/graphql/i18n/I18nTest.groovy index 84165264e7..77d13df5c8 100644 --- a/src/test/groovy/graphql/i18n/I18nTest.groovy +++ b/src/test/groovy/graphql/i18n/I18nTest.groovy @@ -73,6 +73,25 @@ class I18nTest extends Specification { message == "Validierungsfehler ({0}) : Type definition '{1}' ist nicht ausführbar" } + def "message arguments are formatted with the message locale not the JVM default locale"() { + // Slovenian formats -1 with a unicode minus sign and groups thousands with a dot + def originalDefault = Locale.getDefault() + def originalFormatDefault = Locale.getDefault(Locale.Category.FORMAT) + Locale.setDefault(Locale.forLanguageTag("sl-SI")) + + when: + def englishMessage = I18n.i18n(BundleType.Parsing, Locale.ENGLISH).msg("InvalidSyntaxMoreTokens.noMessage", -1, 1234) + def germanMessage = I18n.i18n(BundleType.Parsing, Locale.GERMAN).msg("InvalidSyntaxMoreTokens.noMessage", -1, 1234) + + then: + englishMessage.endsWith("Offending token at line -1 column 1,234") + germanMessage.endsWith("Ungültiges Token in Zeile -1 Spalte 1.234") + + cleanup: + Locale.setDefault(originalDefault) + Locale.setDefault(Locale.Category.FORMAT, originalFormatDefault) + } + def "integration test of valid messages"() { def sdl = """ type Query {