mirror of
https://github.moeyy.xyz/https://github.com/GeWuYou/forgeboot
synced 2025-10-27 13:02:09 +08:00
feat(i18n): Refactored the internationalization module and added Gradle plugin support
- Added I18nKeyGenPlugin Gradle plugin for generating internationalization key files - Refactoring the internationalization module to separate the API and implementation code - Updated the project structure to create new submodules to support internationalization - Modify the build configuration to add the necessary dependencies and properties
This commit is contained in:
parent
48228574be
commit
b44b5a1570
@ -13,3 +13,13 @@ dependencies {
|
||||
// Add a dependency on the Kotlin Gradle plugin, so that convention plugins can apply it.
|
||||
implementation(libs.kotlinGradlePlugin)
|
||||
}
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
register("forgeboot-i18n-key-gen") {
|
||||
id = "i18n-key-gen"
|
||||
implementationClass = "I18nKeyGenPlugin"
|
||||
description =
|
||||
"提供一个用于生成 i18n key文件 的插件"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
184
buildSrc/src/main/kotlin/I18nKeyGenPlugin.kt
Normal file
184
buildSrc/src/main/kotlin/I18nKeyGenPlugin.kt
Normal file
@ -0,0 +1,184 @@
|
||||
/**
|
||||
* 本地化键生成插件
|
||||
*
|
||||
* 该插件用于自动生成本地化键的代码,以简化国际化(i18n)过程
|
||||
* 它通过读取属性文件来生成一个包含所有本地化键的Kotlin文件
|
||||
* 此方法便于集中管理和自动生成代码,避免手动编写易出错的字符串字面量
|
||||
*
|
||||
* @since 2025-05-28 17:11:40
|
||||
* @author gewuyou
|
||||
*/
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* 可缓存的任务类,用于生成本地化键
|
||||
*
|
||||
* 该任务读取输入文件中的属性,并根据这些属性生成一个Kotlin文件
|
||||
* 文件中包含根据属性键生成的常量,这些键按指定的分组深度和级别进行组织
|
||||
*/
|
||||
@CacheableTask
|
||||
abstract class GenerateI18nKeysTask : DefaultTask() {
|
||||
|
||||
/**
|
||||
* 输入文件属性,包含本地化属性
|
||||
* 被注解为@InputFile和@PathSensitive,以确保Gradle可以正确地检测文件路径的变化
|
||||
*/
|
||||
@get:InputFile
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
abstract val inputFile: RegularFileProperty
|
||||
|
||||
/**
|
||||
* 输出文件属性,将生成的代码写入此文件
|
||||
* 被注解为@OutputFile,以告知Gradle该文件是任务的输出
|
||||
*/
|
||||
@get:OutputFile
|
||||
abstract val outputFile: RegularFileProperty
|
||||
|
||||
/**
|
||||
* 根包名属性,用于指定生成代码的包路径
|
||||
* 被注解为@Input,因为包路径的变化应导致任务重新执行
|
||||
*/
|
||||
@get:Input
|
||||
abstract val rootPackage: Property<String>
|
||||
|
||||
/**
|
||||
* 层级属性,决定键的分组深度
|
||||
* 注解为@Input,因为层级变化会影响生成的代码结构
|
||||
*/
|
||||
@get:Input
|
||||
abstract val level: Property<Int>
|
||||
|
||||
/**
|
||||
* 任务的主要执行方法
|
||||
*
|
||||
* 该方法读取输入文件中的属性,然后根据这些属性生成一个Kotlin文件
|
||||
* 它首先加载属性,然后根据指定的包路径、层级和分组深度生成代码
|
||||
*/
|
||||
@TaskAction
|
||||
fun generate() {
|
||||
// 加载属性文件
|
||||
val props = Properties().apply {
|
||||
inputFile.get().asFile.inputStream().use { load(it) }
|
||||
}
|
||||
|
||||
// 准备输出文件
|
||||
val output = outputFile.get().asFile
|
||||
output.parentFile.mkdirs()
|
||||
|
||||
// 处理属性键,按分组深度分组
|
||||
val keys = props.stringPropertyNames().sorted()
|
||||
val levelDepth = level.get()
|
||||
val indentUnit = " "
|
||||
|
||||
fun Appendable.generateObjects(keys: List<String>, depth: Int) {
|
||||
val groups = keys.groupBy { it.split(".").take(depth).joinToString(".") }
|
||||
|
||||
groups.forEach { (groupKey, groupKeys) ->
|
||||
val segments = groupKey.split(".")
|
||||
val indent = indentUnit.repeat(segments.size)
|
||||
val objectName = segments.last().replaceFirstChar(Char::uppercase)
|
||||
|
||||
appendLine("$indent object $objectName {")
|
||||
|
||||
val deeperKeys = groupKeys.filter { it.split(".").size > depth }
|
||||
|
||||
if (depth < levelDepth && deeperKeys.isNotEmpty()) {
|
||||
generateObjects(deeperKeys, depth + 1)
|
||||
} else {
|
||||
groupKeys.forEach { fullKey ->
|
||||
val constName = fullKey
|
||||
.split(".")
|
||||
.drop(levelDepth)
|
||||
.joinToString("_") { it.uppercase() }
|
||||
.ifBlank { fullKey.replace(".", "_").uppercase() }
|
||||
|
||||
appendLine("${indent}$indentUnit const val $constName = \"$fullKey\"")
|
||||
}
|
||||
}
|
||||
|
||||
appendLine("$indent }")
|
||||
}
|
||||
}
|
||||
// 生成代码并写入输出文件
|
||||
output.writeText(buildString {
|
||||
appendLine("package ${rootPackage.get()}")
|
||||
appendLine("// ⚠️ Auto-generated. Do not edit manually.")
|
||||
appendLine("object I18nKeys {")
|
||||
generateObjects(keys, 1)
|
||||
appendLine("}")
|
||||
})
|
||||
|
||||
println("✅ Generated I18nKeys.kt at ${output.absolutePath}")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展类,用于配置插件
|
||||
*
|
||||
* 该扩展定义了插件的可配置属性,包括层级、分组深度和根包名
|
||||
*/
|
||||
interface I18nKeyGenExtension {
|
||||
val level: Property<Int>
|
||||
val rootPackage: Property<String>
|
||||
val inputPath: Property<String>
|
||||
val fileName: Property<String>
|
||||
val readPath: Property<String>
|
||||
val readFileName: Property<String>
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地化键生成插件的实现
|
||||
*
|
||||
* 该插件在项目中添加扩展和任务,以生成本地化键的代码
|
||||
*/
|
||||
// ---- 插件主体 ----
|
||||
class I18nKeyGenPlugin : Plugin<Project> {
|
||||
override fun apply(project: Project) {
|
||||
val ext = project.extensions.create("i18nKeyGen", I18nKeyGenExtension::class.java).apply {
|
||||
level.convention(2)
|
||||
rootPackage.convention("com.gewuyou.i18n")
|
||||
inputPath.convention("generated/i18n") // 子路径
|
||||
fileName.convention("I18nKeys.kt")
|
||||
readPath.convention("src/main/resources/i18n")
|
||||
readFileName.convention("messages.properties")
|
||||
}
|
||||
|
||||
project.afterEvaluate {
|
||||
val propsFile = project.file("${ext.readPath.get()}/${ext.readFileName.get()}")
|
||||
if (!propsFile.exists()) return@afterEvaluate
|
||||
|
||||
// 输出文件路径
|
||||
val outputFile = project.layout.buildDirectory.file("${ext.inputPath.get()}/${ext.fileName.get()}")
|
||||
val outputDir = project.layout.buildDirectory.dir(ext.inputPath)
|
||||
|
||||
// 注册生成任务
|
||||
val generateTask = project.tasks.register("generateI18nKeys", GenerateI18nKeysTask::class.java) {
|
||||
setProperty("inputFile", propsFile)
|
||||
setProperty("outputFile", outputFile)
|
||||
setProperty("level", ext.level)
|
||||
setProperty("rootPackage", ext.rootPackage)
|
||||
}
|
||||
|
||||
// 👇 确保编译前依赖该任务
|
||||
listOf("compileKotlin", "kaptGenerateStubsKotlin").forEach { name ->
|
||||
project.tasks.matching { it.name == name }.configureEach {
|
||||
dependsOn(generateTask)
|
||||
}
|
||||
}
|
||||
|
||||
// 👇 延迟注册源码目录:使用 map 避免提前访问目录
|
||||
project.plugins.withId("org.jetbrains.kotlin.jvm") {
|
||||
val kotlinExt = project.extensions.getByType(KotlinProjectExtension::class.java)
|
||||
kotlinExt.sourceSets.getByName("main").kotlin.srcDir(outputDir.map { it.asFile })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,4 +22,16 @@ object Modules {
|
||||
const val RESULT_IMPL = ":forgeboot-common:forgeboot-common-result:forgeboot-common-result-impl"
|
||||
const val RESULT_API = ":forgeboot-common:forgeboot-common-result:forgeboot-common-result-api"
|
||||
}
|
||||
object I18N {
|
||||
const val STARTER = ":forgeboot-i18n-spring-boot-starter"
|
||||
const val API = ":forgeboot-i18n-spring-boot-starter:forgeboot-i18n-api"
|
||||
const val IMPL = ":forgeboot-i18n-spring-boot-starter:forgeboot-i18n-impl"
|
||||
const val AUTOCONFIGURE = ":forgeboot-i18n-spring-boot-starter:forgeboot-i18n-autoconfigure"
|
||||
}
|
||||
object TRACE{
|
||||
const val STARTER = ":forgeboot-trace-spring-boot-starter"
|
||||
const val API = ":forgeboot-trace-spring-boot-starter:forgeboot-trace-api"
|
||||
const val IMPL = ":forgeboot-trace-spring-boot-starter:forgeboot-trace-impl"
|
||||
const val AUTOCONFIGURE = ":forgeboot-trace-spring-boot-starter:forgeboot-trace-autoconfigure"
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,5 @@
|
||||
object ProjectFlags {
|
||||
const val IS_ROOT_MODULE = "isRootModule"
|
||||
const val IS_PUBLISH_MODULE = "isPublishModule"
|
||||
const val ARTIFACT_ID = "artifactId"
|
||||
}
|
||||
@ -1,8 +1,6 @@
|
||||
dependencies {
|
||||
implementation(project(Modules.Core.EXTENSION))
|
||||
implementation(project(Modules.Common.RESULT_API))
|
||||
|
||||
compileOnly(libs.springBootStarter.web)
|
||||
// Spring Boot WebFlux
|
||||
compileOnly(libs.springBootStarter.webflux)
|
||||
extra{
|
||||
setProperty(ProjectFlags.IS_ROOT_MODULE,true)
|
||||
}
|
||||
dependencies {
|
||||
|
||||
}
|
||||
|
||||
8
forgeboot-i18n/forgeboot-i18n-api/build.gradle.kts
Normal file
8
forgeboot-i18n/forgeboot-i18n-api/build.gradle.kts
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
dependencies {
|
||||
compileOnly(platform(libs.springBootDependencies.bom))
|
||||
// compileOnly(platform(libs.springCloudDependencies.bom))
|
||||
// compileOnly(libs.springBootStarter.web)
|
||||
compileOnly(libs.springBootStarter.webflux)
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gewuyou.forgeboot.i18n.entity
|
||||
package com.gewuyou.forgeboot.i18n.api
|
||||
|
||||
/**
|
||||
* 内部信息(用于扩展项目内的i18n信息)
|
||||
@ -12,4 +12,10 @@ interface InternalInformation {
|
||||
* @return 响应信息 code
|
||||
*/
|
||||
val responseI8nMessageCode: String?
|
||||
|
||||
/**
|
||||
* 获取i18n响应信息参数
|
||||
* @return 响应信息 参数数组
|
||||
*/
|
||||
val responseI8nMessageArgs: Array<Any>?
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gewuyou.forgeboot.common.result.api
|
||||
package com.gewuyou.forgeboot.i18n.api
|
||||
/**
|
||||
* 消息解析器接口
|
||||
*
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gewuyou.forgeboot.common.result.api
|
||||
package com.gewuyou.forgeboot.i18n.api
|
||||
|
||||
/**
|
||||
* 响应信息
|
||||
@ -0,0 +1,5 @@
|
||||
package com.gewuyou.forgeboot.i18n.api
|
||||
|
||||
import org.springframework.web.server.WebFilter
|
||||
|
||||
interface WebFluxLocaleResolver: WebFilter
|
||||
@ -0,0 +1 @@
|
||||
spring.application.name=forgeboot-i18n-api
|
||||
10
forgeboot-i18n/forgeboot-i18n-autoconfigure/build.gradle.kts
Normal file
10
forgeboot-i18n/forgeboot-i18n-autoconfigure/build.gradle.kts
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
dependencies {
|
||||
compileOnly(platform(libs.springBootDependencies.bom))
|
||||
compileOnly(platform(libs.springCloudDependencies.bom))
|
||||
compileOnly(libs.springBootStarter.web)
|
||||
compileOnly(libs.springBootStarter.webflux)
|
||||
compileOnly(project(Modules.I18N.API))
|
||||
compileOnly(project(Modules.I18N.IMPL))
|
||||
implementation(project(Modules.Core.EXTENSION))
|
||||
}
|
||||
@ -1,10 +1,11 @@
|
||||
package com.gewuyou.forgeboot.i18n.config
|
||||
package com.gewuyou.forgeboot.i18n.autoconfigure
|
||||
|
||||
|
||||
import com.gewuyou.forgeboot.common.result.api.MessageResolver
|
||||
import com.gewuyou.forgeboot.i18n.filter.ReactiveLocaleResolver
|
||||
import com.gewuyou.forgeboot.core.extension.log
|
||||
import com.gewuyou.forgeboot.i18n.config.entity.I18nProperties
|
||||
import com.gewuyou.forgeboot.i18n.resolver.I18nMessageResolver
|
||||
import com.gewuyou.forgeboot.i18n.api.MessageResolver
|
||||
import com.gewuyou.forgeboot.i18n.impl.config.I18nProperties
|
||||
import com.gewuyou.forgeboot.i18n.impl.filter.ReactiveLocaleResolver
|
||||
import com.gewuyou.forgeboot.i18n.impl.resolver.I18nMessageResolver
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import org.springframework.beans.factory.annotation.Qualifier
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gewuyou.forgeboot.i18n.config
|
||||
package com.gewuyou.forgeboot.i18n.autoconfigure
|
||||
|
||||
import com.gewuyou.forgeboot.core.extension.log
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
@ -0,0 +1,2 @@
|
||||
com.gewuyou.forgeboot.i18n.autoconfigure.I18nAutoConfiguration
|
||||
com.gewuyou.forgeboot.i18n.autoconfigure.I18nWebConfiguration
|
||||
7
forgeboot-i18n/forgeboot-i18n-impl/build.gradle.kts
Normal file
7
forgeboot-i18n/forgeboot-i18n-impl/build.gradle.kts
Normal file
@ -0,0 +1,7 @@
|
||||
dependencies {
|
||||
compileOnly(platform(libs.springBootDependencies.bom))
|
||||
compileOnly(platform(libs.springCloudDependencies.bom))
|
||||
compileOnly(libs.springBootStarter.web)
|
||||
compileOnly(libs.springBootStarter.webflux)
|
||||
compileOnly(project(Modules.I18N.API))
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.gewuyou.forgeboot.i18n.impl.config
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
|
||||
/**
|
||||
* i18n属性
|
||||
*
|
||||
* @author gewuyou
|
||||
* @since 2025-02-18 23:59:57
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "forgeboot.i18n")
|
||||
class I18nProperties {
|
||||
/**
|
||||
* 默认语言
|
||||
*/
|
||||
var defaultLocale: String = "zh_CN"
|
||||
|
||||
/**
|
||||
* 语言请求参数名
|
||||
*/
|
||||
var langRequestParameter: String = "lang"
|
||||
|
||||
/**
|
||||
* 语言文件路径
|
||||
*/
|
||||
var wildPathForLanguageFiles: String = "classpath*:i18n/**/messages"
|
||||
|
||||
/**
|
||||
* 位置模式后缀
|
||||
*/
|
||||
var locationPatternSuffix: String = ".properties"
|
||||
}
|
||||
@ -1,14 +1,17 @@
|
||||
package com.gewuyou.forgeboot.i18n.exception
|
||||
package com.gewuyou.forgeboot.i18n.impl.exception
|
||||
|
||||
|
||||
import com.gewuyou.forgeboot.i18n.entity.ResponseInformation
|
||||
|
||||
/**
|
||||
* i18n异常
|
||||
*
|
||||
* 该异常类用于处理国际化相关的异常情况,提供了错误代码和国际化消息代码的封装,
|
||||
* 以便于在异常处理时能够方便地获取这些信息
|
||||
*
|
||||
* @author gewuyou
|
||||
* @since 2024-11-12 00:11:32
|
||||
*/
|
||||
class I18nBaseException : RuntimeException {
|
||||
open class I18nBaseException : RuntimeException {
|
||||
/**
|
||||
* 响应信息对象,用于存储错误代码和国际化消息代码
|
||||
*/
|
||||
@ -18,19 +21,25 @@ class I18nBaseException : RuntimeException {
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* 初始化异常对象,用于当只有响应信息可用时
|
||||
*
|
||||
* @param responseInformation 响应信息对象,包含错误代码和国际化消息代码
|
||||
*/
|
||||
constructor(responseInformation: ResponseInformation) : super() {
|
||||
constructor(responseInformation: ResponseInformation)
|
||||
: super(responseInformation.responseI8nMessageCode) {
|
||||
this.responseInformation = responseInformation
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* 初始化异常对象,用于当有响应信息和异常原因时
|
||||
*
|
||||
* @param responseInformation 响应信息对象,包含错误代码和国际化消息代码
|
||||
* @param cause 异常原因
|
||||
*/
|
||||
constructor(responseInformation: ResponseInformation, cause: Throwable?) : super(cause) {
|
||||
constructor(responseInformation: ResponseInformation, cause: Throwable)
|
||||
: super(responseInformation.responseI8nMessageCode, cause) {
|
||||
this.responseInformation = responseInformation
|
||||
}
|
||||
|
||||
@ -49,4 +58,12 @@ class I18nBaseException : RuntimeException {
|
||||
*/
|
||||
val errorI18nMessageCode: String
|
||||
get() = responseInformation.responseI8nMessageCode
|
||||
|
||||
/**
|
||||
* 获取国际化消息参数
|
||||
*
|
||||
* @return 国际化消息参数数组
|
||||
*/
|
||||
val errorI18nMessageArgs: Array<Any>
|
||||
get() = responseInformation.args
|
||||
}
|
||||
@ -1,7 +1,9 @@
|
||||
package com.gewuyou.forgeboot.i18n.filter
|
||||
package com.gewuyou.forgeboot.i18n.impl.filter
|
||||
|
||||
|
||||
import com.gewuyou.forgeboot.i18n.config.entity.I18nProperties
|
||||
import com.gewuyou.forgeboot.i18n.api.WebFluxLocaleResolver
|
||||
import com.gewuyou.forgeboot.i18n.impl.config.I18nProperties
|
||||
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.i18n.LocaleContextHolder
|
||||
import org.springframework.util.StringUtils
|
||||
@ -1,6 +1,7 @@
|
||||
package com.gewuyou.forgeboot.i18n.resolver
|
||||
package com.gewuyou.forgeboot.i18n.impl.resolver
|
||||
|
||||
import com.gewuyou.forgeboot.common.result.api.MessageResolver
|
||||
|
||||
import com.gewuyou.forgeboot.i18n.api.MessageResolver
|
||||
import org.springframework.context.MessageSource
|
||||
import org.springframework.context.i18n.LocaleContextHolder
|
||||
|
||||
@ -0,0 +1 @@
|
||||
spring.application.name=forgeboot-i18n-impl-starter
|
||||
@ -1,63 +0,0 @@
|
||||
package com.gewuyou.forgeboot.i18n.config.entity;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* i18n属性
|
||||
*
|
||||
* @author gewuyou
|
||||
* @since 2025-02-18 23:59:57
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "forgeboot.i18n")
|
||||
public class I18nProperties {
|
||||
/**
|
||||
* 默认语言
|
||||
*/
|
||||
private String defaultLocale = "zh_CN";
|
||||
|
||||
/**
|
||||
* 语言请求参数名
|
||||
*/
|
||||
private String langRequestParameter = "lang";
|
||||
/**
|
||||
* 语言文件路径
|
||||
*/
|
||||
private String wildPathForLanguageFiles = "classpath*:i18n/**/messages";
|
||||
|
||||
/**
|
||||
* 位置模式后缀
|
||||
*/
|
||||
private String locationPatternSuffix = ".properties";
|
||||
|
||||
public String getLocationPatternSuffix() {
|
||||
return locationPatternSuffix;
|
||||
}
|
||||
|
||||
public void setLocationPatternSuffix(String locationPatternSuffix) {
|
||||
this.locationPatternSuffix = locationPatternSuffix;
|
||||
}
|
||||
|
||||
public String getDefaultLocale() {
|
||||
return defaultLocale;
|
||||
}
|
||||
|
||||
public void setDefaultLocale(String defaultLocale) {
|
||||
this.defaultLocale = defaultLocale;
|
||||
}
|
||||
|
||||
public String getLangRequestParameter() {
|
||||
return langRequestParameter;
|
||||
}
|
||||
|
||||
public void setLangRequestParameter(String langRequestParameter) {
|
||||
this.langRequestParameter = langRequestParameter;
|
||||
}
|
||||
|
||||
public String getWildPathForLanguageFiles() {
|
||||
return wildPathForLanguageFiles;
|
||||
}
|
||||
|
||||
public void setWildPathForLanguageFiles(String wildPathForLanguageFiles) {
|
||||
this.wildPathForLanguageFiles = wildPathForLanguageFiles;
|
||||
}
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
package com.gewuyou.forgeboot.i18n.entity
|
||||
|
||||
/**
|
||||
* 响应信息(用于对外提供i18n响应信息)
|
||||
*
|
||||
* @author gewuyou
|
||||
* @since 2024-11-26 15:43:06
|
||||
*/
|
||||
interface ResponseInformation {
|
||||
/**
|
||||
* 获取响应码
|
||||
* @return 响应码
|
||||
*/
|
||||
val responseCode: Int
|
||||
|
||||
/**
|
||||
* 获取i18n响应信息code
|
||||
* @return 响应信息 code
|
||||
*/
|
||||
val responseI8nMessageCode: String
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
package com.gewuyou.forgeboot.i18n.filter
|
||||
|
||||
import org.springframework.web.server.WebFilter
|
||||
|
||||
interface WebFluxLocaleResolver:WebFilter
|
||||
@ -1,2 +0,0 @@
|
||||
com.gewuyou.forgeboot.i18n.config.I18nAutoConfiguration
|
||||
com.gewuyou.forgeboot.i18n.config.I18nWebConfiguration
|
||||
Loading…
x
Reference in New Issue
Block a user