diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java index ea77021c3..2218c4972 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java @@ -5,6 +5,10 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; import org.hswebframework.web.i18n.LocaleUtils; +import reactor.core.publisher.Mono; + +import java.util.Locale; +import java.util.Objects; /** * 支持国际化消息的异常,code为 @@ -45,11 +49,24 @@ public class I18nSupportException extends RuntimeException { @Override public String getMessage() { + if (Objects.equals(super.getMessage(), this.getI18nCode())) { + return getLocalizedMessage(); + } return super.getMessage() != null ? super.getMessage() : getLocalizedMessage(); } @Override - public String getLocalizedMessage() { - return LocaleUtils.resolveMessage(i18nCode, args); + public final String getLocalizedMessage() { + return getLocalizedMessage(LocaleUtils.current()); + } + + public String getLocalizedMessage(Locale locale) { + return LocaleUtils.resolveMessage(i18nCode, locale, getMessage(), args); + } + + public final Mono getLocalizedMessageReactive() { + return LocaleUtils + .currentReactive() + .map(this::getLocalizedMessage); } } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java index fc62966ed..2a1b0ba13 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java @@ -6,10 +6,13 @@ import lombok.Getter; import lombok.Setter; import org.hswebframework.web.i18n.LocaleUtils; import org.springframework.http.HttpStatus; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.ResponseStatus; import javax.validation.ConstraintViolation; import java.util.*; +import java.util.stream.Collectors; @Getter @Setter @@ -31,9 +34,6 @@ public class ValidationException extends I18nSupportException { public ValidationException(String message, List details, Object... args) { super(message, args); this.details = details; - for (Detail detail : this.details) { - detail.translateI18n(args); - } } public ValidationException(Set> violations) { @@ -48,23 +48,44 @@ public class ValidationException extends I18nSupportException { //{0} 属性 ,{1} 验证消息 //property也支持国际化? - String resolveMessage = propertyI18nEnabled ? - LocaleUtils.resolveMessage(first.getRootBeanClass().getName() + "." + property, property) + String propertyI18n = propertyI18nEnabled ? + first.getRootBeanClass().getName() + "." + property : property; - setArgs(new Object[]{resolveMessage, first.getMessage()}); + setArgs(new Object[]{propertyI18n, first.getMessage()}); details = new ArrayList<>(violations.size()); for (ConstraintViolation violation : violations) { - details.add(new Detail(violation.getPropertyPath().toString(), violation.getMessage(), null)); + details.add(new Detail(violation.getPropertyPath().toString(), + violation.getMessage(), + null)); } } + public List getDetails(Locale locale) { + return CollectionUtils.isEmpty(details) + ? Collections.emptyList() + : details + .stream() + .map(detail -> detail.translateI18n(locale)) + .collect(Collectors.toList()); + } + + @Override + public String getLocalizedMessage(Locale locale) { + if (propertyI18nEnabled && "validation.property_validate_failed".equals(getI18nCode()) && getArgs().length > 0) { + Object[] args = getArgs().clone(); + args[0] = LocaleUtils.resolveMessage(String.valueOf(args[0]), locale, String.valueOf(args[0])); + return LocaleUtils.resolveMessage(getI18nCode(), locale, getMessage(), args); + } + return super.getLocalizedMessage(locale); + } @Getter @Setter @AllArgsConstructor public static class Detail { + @Schema(description = "字段") String property; @@ -74,10 +95,11 @@ public class ValidationException extends I18nSupportException { @Schema(description = "详情") Object detail; - public void translateI18n(Object... args) { - if (message.contains(".")) { - message = LocaleUtils.resolveMessage(message, message, args); + public Detail translateI18n(Locale locale) { + if (StringUtils.hasText(message) && message.contains(".")) { + return new Detail(property, LocaleUtils.resolveMessage(message, locale, message), detail); } + return this; } } } diff --git a/hsweb-core/src/test/java/org/hswebframework/web/validator/ValidatorUtilsTest.java b/hsweb-core/src/test/java/org/hswebframework/web/validator/ValidatorUtilsTest.java index 07ac1d5b9..ca8975c58 100644 --- a/hsweb-core/src/test/java/org/hswebframework/web/validator/ValidatorUtilsTest.java +++ b/hsweb-core/src/test/java/org/hswebframework/web/validator/ValidatorUtilsTest.java @@ -4,7 +4,9 @@ import lombok.Getter; import lombok.Setter; import org.hswebframework.web.exception.ValidationException; import org.hswebframework.web.i18n.LocaleUtils; +import org.hswebframework.web.i18n.MessageSourceInitializer; import org.junit.Test; +import org.springframework.context.support.StaticMessageSource; import javax.validation.constraints.NotBlank; @@ -14,27 +16,39 @@ import static org.junit.Assert.*; public class ValidatorUtilsTest { - - @Test - public void test(){ - test(Locale.CHINA,"不能为空"); - test(Locale.ENGLISH,"must not be blank"); + static { + System.setProperty("i18n.validation.property.enabled", "true"); } - public void test(Locale locale,String msg){ + @Test + public void test() { + StaticMessageSource source = new StaticMessageSource(); + source.addMessage("validation.property_validate_failed", Locale.CHINA, "{0} {1}"); + source.addMessage("validation.property_validate_failed", Locale.ENGLISH, "{0} {1}"); + + source.addMessage(TestEntity.class.getName() + ".notBlank", Locale.ENGLISH, "Test"); + source.addMessage(TestEntity.class.getName() + ".notBlank", Locale.CHINA, "测试"); + + MessageSourceInitializer.init(source); + test(Locale.CHINA, "不能为空", "测试 不能为空"); + test(Locale.ENGLISH, "must not be blank", "Test must not be blank"); + } + + public void test(Locale locale, String msg, String msg2) { try { - LocaleUtils.doWith(locale,en->{ + LocaleUtils.doWith(locale, en -> { ValidatorUtils.tryValidate(new TestEntity()); }); throw new IllegalStateException(); - }catch (ValidationException e){ - assertEquals(msg,e.getDetails().get(0).getMessage()); + } catch (ValidationException e) { + assertEquals(msg, e.getDetails().get(0).getMessage()); + assertEquals(msg2, e.getLocalizedMessage(locale)); } } @Getter @Setter - public static class TestEntity{ + public static class TestEntity { @NotBlank private String notBlank;