|
|
@@ -0,0 +1,409 @@
|
|
|
+# 后端泰语提示支持实施计划
|
|
|
+
|
|
|
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
|
+
|
|
|
+**Goal:** 为所有后端系统提示增加完整泰语资源和安全的泰语 Locale 解析,同时保持台湾繁体中文为默认语言。
|
|
|
+
|
|
|
+**Architecture:** Spring MessageSource 继续从 `i18n/messages` 读取资源,新增 `messages_th_TH.properties` 提供完整泰语值;同步请求继续由 `lang` 参数切换 Locale,异步消息通过修复后的 `LocaleUtils.parseLocale(String)` 解析用户语言。业务数据的数字语言映射保持不变,避免把尚不存在的泰语商品或门店数据纳入本阶段。
|
|
|
+
|
|
|
+**Tech Stack:** Java 21、Spring Boot MessageSource、Spring MVC LocaleResolver、JUnit 5、Maven、UTF-8 properties。
|
|
|
+
|
|
|
+## Global Constraints
|
|
|
+
|
|
|
+- 默认 Locale 必须继续是台湾繁体中文 `zh_TW`。
|
|
|
+- 泰语标准代码为 `th_TH`,并兼容 `th-TH` 和 `th`。
|
|
|
+- `messages_th_TH.properties` 必须与现有四个本地化语言包拥有完全一致且非空的消息 key。
|
|
|
+- 占位符集合必须逐 key 保持一致,例如 `{0}`、`{1}` 不得遗漏。
|
|
|
+- 不修改 `toLangCode()`、`getUserLanguageCode()`、数据库字段或业务数据语言映射。
|
|
|
+- 不修改平台管理端、商家管理端和 App 前端语言资源。
|
|
|
+- 现有工作区中的闪送请求 DTO/Controller 注释修改属于另一项工作,不得在泰语功能提交中丢失或误暂存。
|
|
|
+- 按用户要求,先完成全部生产代码和测试源码,再统一运行测试与构建;中途不执行 Maven。
|
|
|
+- Git 提交标题和正文使用中文,不添加英文 Conventional Commits 前缀。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Task 1: 定义 Locale 解析契约并修复解析器
|
|
|
+
|
|
|
+**Files:**
|
|
|
+- Create: `ruoyi-admin/src/test/java/com/ruoyi/common/utils/LocaleUtilsTest.java`
|
|
|
+- Modify: `ruoyi-common/src/main/java/com/ruoyi/common/utils/LocaleUtils.java`
|
|
|
+
|
|
|
+**Interfaces:**
|
|
|
+- Consumes: Redis 中已保存的字符串语言代码,以及直接调用 `LocaleUtils.parseLocale(String)` 的代码。
|
|
|
+- Produces: `public static Locale parseLocale(String language)`;支持白名单语言代码并对空值、未知值回退 `zh_TW`。
|
|
|
+
|
|
|
+- [ ] **Step 1: 编写 Locale 白名单解析测试源码**
|
|
|
+
|
|
|
+创建参数化测试,锁定所有受支持别名与默认回退:
|
|
|
+
|
|
|
+```java
|
|
|
+package com.ruoyi.common.utils;
|
|
|
+
|
|
|
+import org.junit.jupiter.api.Test;
|
|
|
+import org.junit.jupiter.params.ParameterizedTest;
|
|
|
+import org.junit.jupiter.params.provider.CsvSource;
|
|
|
+
|
|
|
+import java.util.Locale;
|
|
|
+
|
|
|
+import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
|
+
|
|
|
+class LocaleUtilsTest {
|
|
|
+ @ParameterizedTest
|
|
|
+ @CsvSource({
|
|
|
+ "zh_CN,zh,CN", "zh-CN,zh,CN", "zh,zh,CN",
|
|
|
+ "zh_TW,zh,TW", "zh-TW,zh,TW", "tw,zh,TW",
|
|
|
+ "en_US,en,US", "en-US,en,US", "en,en,US",
|
|
|
+ "vi_VN,vi,VN", "vi-VN,vi,VN", "vi,vi,VN",
|
|
|
+ "th_TH,th,TH", "th-TH,th,TH", "th,th,TH"
|
|
|
+ })
|
|
|
+ void parsesSupportedLanguageAliases(String input, String language, String country) {
|
|
|
+ assertEquals(new Locale(language, country), LocaleUtils.parseLocale(input));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void fallsBackToTraditionalChineseForMissingOrUnknownLanguage() {
|
|
|
+ Locale expected = new Locale("zh", "TW");
|
|
|
+ assertEquals(expected, LocaleUtils.parseLocale(null));
|
|
|
+ assertEquals(expected, LocaleUtils.parseLocale(" "));
|
|
|
+ assertEquals(expected, LocaleUtils.parseLocale("fr-FR"));
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **Step 2: 实现白名单 Locale 解析**
|
|
|
+
|
|
|
+保留 `DEFAULT_LOCALE`,新增明确的 Locale 常量并只修改 `parseLocale`。先 `trim()`,再把 `-` 转为 `_` 并使用 `Locale.ROOT` 转小写,最后使用 switch 返回白名单 Locale:
|
|
|
+
|
|
|
+```java
|
|
|
+private static final Locale SIMPLIFIED_CHINESE = new Locale("zh", "CN");
|
|
|
+private static final Locale ENGLISH = new Locale("en", "US");
|
|
|
+private static final Locale VIETNAMESE = new Locale("vi", "VN");
|
|
|
+private static final Locale THAI = new Locale("th", "TH");
|
|
|
+
|
|
|
+public static Locale parseLocale(String language)
|
|
|
+{
|
|
|
+ if (StringUtils.isEmpty(language) || language.trim().isEmpty())
|
|
|
+ {
|
|
|
+ return DEFAULT_LOCALE;
|
|
|
+ }
|
|
|
+ String normalized = language.trim().replace('-', '_').toLowerCase(Locale.ROOT);
|
|
|
+ return switch (normalized)
|
|
|
+ {
|
|
|
+ case "zh", "zh_cn" -> SIMPLIFIED_CHINESE;
|
|
|
+ case "zh_tw", "tw" -> DEFAULT_LOCALE;
|
|
|
+ case "en", "en_us" -> ENGLISH;
|
|
|
+ case "vi", "vi_vn" -> VIETNAMESE;
|
|
|
+ case "th", "th_th" -> THAI;
|
|
|
+ default -> DEFAULT_LOCALE;
|
|
|
+ };
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+不得修改 `toLangCode()` 和 `getUserLanguageCode()`。
|
|
|
+
|
|
|
+- [ ] **Step 3: 静态检查本任务差异,暂不运行 Maven**
|
|
|
+
|
|
|
+运行:
|
|
|
+
|
|
|
+```powershell
|
|
|
+git diff --check -- ruoyi-common/src/main/java/com/ruoyi/common/utils/LocaleUtils.java ruoyi-admin/src/test/java/com/ruoyi/common/utils/LocaleUtilsTest.java
|
|
|
+```
|
|
|
+
|
|
|
+预期:无错误输出。按全局约束,将测试执行延后到 Task 4。
|
|
|
+
|
|
|
+- [ ] **Step 4: 提交 Locale 解析改动**
|
|
|
+
|
|
|
+```powershell
|
|
|
+git add -- ruoyi-common/src/main/java/com/ruoyi/common/utils/LocaleUtils.java ruoyi-admin/src/test/java/com/ruoyi/common/utils/LocaleUtilsTest.java
|
|
|
+git diff --cached --name-only
|
|
|
+git diff --cached --check
|
|
|
+git commit -m "支持后端泰语语言解析" -m "兼容 th_TH、th-TH 和 th,并为现有受支持语言建立白名单解析;空值和未知语言继续回退台湾繁体。"
|
|
|
+```
|
|
|
+
|
|
|
+### Task 2: 新增完整泰语消息资源和语言包契约
|
|
|
+
|
|
|
+**Files:**
|
|
|
+- Create: `ruoyi-admin/src/main/resources/i18n/messages_th_TH.properties`
|
|
|
+- Create: `ruoyi-admin/src/test/java/com/ruoyi/common/utils/BackendI18nBundleContractTest.java`
|
|
|
+- Modify: `ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/service/FlashDeliveryI18nContractTest.java`
|
|
|
+
|
|
|
+**Interfaces:**
|
|
|
+- Consumes: `ResourceBundleMessageSource` 的 basename `i18n/messages` 和现有 319 个本地化消息 key。
|
|
|
+- Produces: 完整的泰语资源包 `messages_th_TH.properties`,由 `Locale("th", "TH")` 自动加载。
|
|
|
+
|
|
|
+- [ ] **Step 1: 编写语言包完整性和占位符契约测试源码**
|
|
|
+
|
|
|
+创建 `BackendI18nBundleContractTest`,使用 UTF-8 Reader 加载资源;以繁体中文包作为 key 与占位符参考,逐一比较英文、简中、越南语和泰语:
|
|
|
+
|
|
|
+```java
|
|
|
+package com.ruoyi.common.utils;
|
|
|
+
|
|
|
+import org.junit.jupiter.api.Test;
|
|
|
+import org.springframework.context.support.ResourceBundleMessageSource;
|
|
|
+
|
|
|
+import java.io.InputStream;
|
|
|
+import java.io.InputStreamReader;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Locale;
|
|
|
+import java.util.Properties;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
+
|
|
|
+import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
|
+import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
|
+import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
|
+
|
|
|
+class BackendI18nBundleContractTest {
|
|
|
+ private static final List<String> LOCALIZED_BUNDLES = List.of(
|
|
|
+ "messages_zh_CN.properties", "messages_zh_TW.properties",
|
|
|
+ "messages_en_US.properties", "messages_vi.properties",
|
|
|
+ "messages_th_TH.properties");
|
|
|
+ private static final Pattern PLACEHOLDER = Pattern.compile("\\{\\d+}");
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void everyLocalizedBundleHasTheSameNonBlankKeysAndPlaceholders() throws Exception {
|
|
|
+ Properties reference = load("messages_zh_TW.properties");
|
|
|
+ for (String bundle : LOCALIZED_BUNDLES) {
|
|
|
+ Properties candidate = load(bundle);
|
|
|
+ assertEquals(reference.stringPropertyNames(), candidate.stringPropertyNames(), bundle);
|
|
|
+ for (String key : reference.stringPropertyNames()) {
|
|
|
+ assertFalse(candidate.getProperty(key).isBlank(), bundle + " blank " + key);
|
|
|
+ assertEquals(placeholders(reference.getProperty(key)),
|
|
|
+ placeholders(candidate.getProperty(key)), bundle + " placeholders " + key);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void messageSourceLoadsThaiMessagesAndFormatsArguments() {
|
|
|
+ ResourceBundleMessageSource source = new ResourceBundleMessageSource();
|
|
|
+ source.setBasename("i18n/messages");
|
|
|
+ source.setDefaultEncoding(StandardCharsets.UTF_8.name());
|
|
|
+ Locale thai = new Locale("th", "TH");
|
|
|
+ assertEquals("ราคาเสนอมีการเปลี่ยนแปลง โปรดยืนยันค่าบริการล่าสุดอีกครั้ง",
|
|
|
+ source.getMessage("flash.delivery.quote.changed", null, thai));
|
|
|
+ assertEquals("ป้อนรหัสผ่านผิด 3 ครั้ง บัญชีถูกล็อก 10 นาที",
|
|
|
+ source.getMessage("user.password.retry.limit.exceed", new Object[]{3, 10}, thai));
|
|
|
+ }
|
|
|
+
|
|
|
+ private Properties load(String file) throws Exception {
|
|
|
+ Properties properties = new Properties();
|
|
|
+ try (InputStream input = getClass().getClassLoader().getResourceAsStream("i18n/" + file)) {
|
|
|
+ assertNotNull(input, file);
|
|
|
+ properties.load(new InputStreamReader(input, StandardCharsets.UTF_8));
|
|
|
+ }
|
|
|
+ return properties;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<String> placeholders(String value) {
|
|
|
+ List<String> result = new ArrayList<>();
|
|
|
+ Matcher matcher = PLACEHOLDER.matcher(value);
|
|
|
+ while (matcher.find()) result.add(matcher.group());
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **Step 2: 将泰语文件纳入闪送消息契约**
|
|
|
+
|
|
|
+在 `FlashDeliveryI18nContractTest.FILES` 末尾增加:
|
|
|
+
|
|
|
+```java
|
|
|
+"messages_th_TH.properties"
|
|
|
+```
|
|
|
+
|
|
|
+保留现有全部闪送与地址消息 key。
|
|
|
+
|
|
|
+- [ ] **Step 3: 创建完整泰语语言包**
|
|
|
+
|
|
|
+以 `messages_zh_TW.properties` 的 key 和顺序为基准创建 `messages_th_TH.properties`:
|
|
|
+
|
|
|
+- 复制全部 319 个 key,不复制繁体中文值。
|
|
|
+- 将每个值翻译为自然、简洁的泰语系统提示。
|
|
|
+- 保持 `{0}`、`{1}`、`{min}`、`{max}` 等占位符原样。
|
|
|
+- 保持 URL、HTTP(S)、PIN、TWD、LINE、Google、Apple、OMG、ATM、CVS 等技术或品牌标识原样。
|
|
|
+- 文件使用 UTF-8,不使用 `\uXXXX` 转义泰文。
|
|
|
+- 关键值必须精确包含:
|
|
|
+
|
|
|
+```properties
|
|
|
+not.null=* จำเป็นต้องกรอก
|
|
|
+user.login.success=เข้าสู่ระบบสำเร็จ
|
|
|
+no.action.success=ดำเนินการสำเร็จ
|
|
|
+flash.delivery.item.invalid=ข้อมูลจำนวน น้ำหนักรวม หรือรายละเอียดสิ่งของไม่ถูกต้อง
|
|
|
+flash.delivery.quote.changed=ราคาเสนอมีการเปลี่ยนแปลง โปรดยืนยันค่าบริการล่าสุดอีกครั้ง
|
|
|
+user.password.retry.limit.exceed=ป้อนรหัสผ่านผิด {0} ครั้ง บัญชีถูกล็อก {1} นาที
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **Step 4: 静态检查资源和测试差异,暂不运行 Maven**
|
|
|
+
|
|
|
+运行:
|
|
|
+
|
|
|
+```powershell
|
|
|
+git diff --check -- ruoyi-admin/src/main/resources/i18n/messages_th_TH.properties ruoyi-admin/src/test/java/com/ruoyi/common/utils/BackendI18nBundleContractTest.java ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/service/FlashDeliveryI18nContractTest.java
|
|
|
+```
|
|
|
+
|
|
|
+预期:无错误输出。按全局约束,将测试执行延后到 Task 4。
|
|
|
+
|
|
|
+- [ ] **Step 5: 提交泰语消息资源**
|
|
|
+
|
|
|
+```powershell
|
|
|
+$paths=@(
|
|
|
+ 'ruoyi-admin/src/main/resources/i18n/messages_th_TH.properties',
|
|
|
+ 'ruoyi-admin/src/test/java/com/ruoyi/common/utils/BackendI18nBundleContractTest.java',
|
|
|
+ 'ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/service/FlashDeliveryI18nContractTest.java'
|
|
|
+)
|
|
|
+git add -- $paths
|
|
|
+git diff --cached --name-only
|
|
|
+git diff --cached --check
|
|
|
+git commit -m "新增完整后端泰语提示" -m "补齐全部后端消息的泰语翻译,并通过键集合、占位符和典型消息契约防止语言包缺失或格式错误。"
|
|
|
+```
|
|
|
+
|
|
|
+### Task 3: 锁定台湾繁体默认语言和 HTTP 泰语切换
|
|
|
+
|
|
|
+**Files:**
|
|
|
+- Create: `ruoyi-admin/src/test/java/com/ruoyi/framework/config/BackendI18nConfigTest.java`
|
|
|
+- Modify: `ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java`
|
|
|
+
|
|
|
+**Interfaces:**
|
|
|
+- Consumes: `I18nConfig.localeResolver()` 和 `I18nConfig.localeChangeInterceptor()`。
|
|
|
+- Produces: 统一使用 `LocaleUtils.parseLocale(String)` 的 HTTP 语言切换,确保无 `lang` 时为 `zh_TW`,三种泰语代码都切换为 `th_TH`。
|
|
|
+
|
|
|
+- [ ] **Step 1: 编写默认语言与 HTTP 切换测试源码**
|
|
|
+
|
|
|
+```java
|
|
|
+package com.ruoyi.framework.config;
|
|
|
+
|
|
|
+import org.junit.jupiter.api.Test;
|
|
|
+import org.springframework.mock.web.MockHttpServletRequest;
|
|
|
+import org.springframework.mock.web.MockHttpServletResponse;
|
|
|
+import org.springframework.web.servlet.DispatcherServlet;
|
|
|
+import org.springframework.web.servlet.LocaleResolver;
|
|
|
+import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
|
|
+
|
|
|
+import java.util.Locale;
|
|
|
+
|
|
|
+import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
|
+
|
|
|
+class BackendI18nConfigTest {
|
|
|
+ @Test
|
|
|
+ void defaultsToTraditionalChinese() {
|
|
|
+ LocaleResolver resolver = new I18nConfig().localeResolver();
|
|
|
+ assertEquals(new Locale("zh", "TW"),
|
|
|
+ resolver.resolveLocale(new MockHttpServletRequest()));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void switchesAllThaiAliasesThroughExistingLangParameter() throws Exception {
|
|
|
+ for (String language : new String[]{"th_TH", "th-TH", "th"}) {
|
|
|
+ I18nConfig config = new I18nConfig();
|
|
|
+ LocaleResolver resolver = config.localeResolver();
|
|
|
+ LocaleChangeInterceptor interceptor = config.localeChangeInterceptor();
|
|
|
+ MockHttpServletRequest request = new MockHttpServletRequest();
|
|
|
+ request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, resolver);
|
|
|
+ request.setParameter("lang", language);
|
|
|
+ interceptor.preHandle(request, new MockHttpServletResponse(), new Object());
|
|
|
+ assertEquals(new Locale("th", "TH"), resolver.resolveLocale(request), language);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **Step 2: 让 HTTP 拦截器复用白名单解析器**
|
|
|
+
|
|
|
+在 `I18nConfig` 导入 `LocaleUtils`,并只覆盖拦截器的 Locale 值解析;参数名继续使用 `lang`:
|
|
|
+
|
|
|
+```java
|
|
|
+import com.ruoyi.common.utils.LocaleUtils;
|
|
|
+
|
|
|
+@Bean
|
|
|
+public LocaleChangeInterceptor localeChangeInterceptor()
|
|
|
+{
|
|
|
+ LocaleChangeInterceptor lci = new LocaleChangeInterceptor()
|
|
|
+ {
|
|
|
+ @Override
|
|
|
+ protected Locale parseLocaleValue(String localeValue)
|
|
|
+ {
|
|
|
+ return LocaleUtils.parseLocale(localeValue);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ lci.setParamName("lang");
|
|
|
+ return lci;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+`localeResolver()` 保持 `slr.setDefaultLocale(Locale.TRADITIONAL_CHINESE)`,不得修改默认语言。
|
|
|
+
|
|
|
+- [ ] **Step 3: 静态检查配置和测试,暂不运行 Maven**
|
|
|
+
|
|
|
+```powershell
|
|
|
+git diff --check -- ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java ruoyi-admin/src/test/java/com/ruoyi/framework/config/BackendI18nConfigTest.java
|
|
|
+```
|
|
|
+
|
|
|
+预期:无错误输出。
|
|
|
+
|
|
|
+- [ ] **Step 4: 提交默认语言和 HTTP 切换契约**
|
|
|
+
|
|
|
+```powershell
|
|
|
+git add -- ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java ruoyi-admin/src/test/java/com/ruoyi/framework/config/BackendI18nConfigTest.java
|
|
|
+git diff --cached --name-only
|
|
|
+git diff --cached --check
|
|
|
+git commit -m "锁定后端默认语言与泰语切换" -m "让 lang 参数复用受支持语言白名单解析,兼容三种泰语代码,并增加台湾繁体默认语言回归契约。"
|
|
|
+```
|
|
|
+
|
|
|
+### Task 4: 统一验证和交付检查
|
|
|
+
|
|
|
+**Files:**
|
|
|
+- Verify: `ruoyi-common/src/main/java/com/ruoyi/common/utils/LocaleUtils.java`
|
|
|
+- Verify: `ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java`
|
|
|
+- Verify: `ruoyi-admin/src/main/resources/i18n/messages_th_TH.properties`
|
|
|
+- Verify: `ruoyi-admin/src/test/java/com/ruoyi/common/utils/LocaleUtilsTest.java`
|
|
|
+- Verify: `ruoyi-admin/src/test/java/com/ruoyi/common/utils/BackendI18nBundleContractTest.java`
|
|
|
+- Verify: `ruoyi-admin/src/test/java/com/ruoyi/framework/config/BackendI18nConfigTest.java`
|
|
|
+- Verify: `ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/service/FlashDeliveryI18nContractTest.java`
|
|
|
+
|
|
|
+**Interfaces:**
|
|
|
+- Consumes: Tasks 1 至 3 的全部生产代码、资源和测试源码。
|
|
|
+- Produces: JDK 21 下可验证的完整后端泰语提示支持。
|
|
|
+
|
|
|
+- [ ] **Step 1: 使用 JDK 21 运行全部相关定向测试**
|
|
|
+
|
|
|
+```powershell
|
|
|
+$env:JAVA_HOME='C:\Users\qmj\.jdks\graalvm-jdk-21.0.7'
|
|
|
+$env:PATH="$env:JAVA_HOME\bin;$env:PATH"
|
|
|
+mvn -pl ruoyi-admin -am "-Dtest=LocaleUtilsTest,BackendI18nBundleContractTest,BackendI18nConfigTest,FlashDeliveryI18nContractTest" "-Dsurefire.failIfNoSpecifiedTests=false" test
|
|
|
+```
|
|
|
+
|
|
|
+预期:四个测试类全部通过,Maven 输出 `BUILD SUCCESS`。
|
|
|
+
|
|
|
+- [ ] **Step 2: 使用 JDK 21 执行后端模块构建**
|
|
|
+
|
|
|
+```powershell
|
|
|
+$env:JAVA_HOME='C:\Users\qmj\.jdks\graalvm-jdk-21.0.7'
|
|
|
+$env:PATH="$env:JAVA_HOME\bin;$env:PATH"
|
|
|
+mvn -pl ruoyi-admin -am -DskipTests package
|
|
|
+```
|
|
|
+
|
|
|
+预期:`ruoyi-common`、`ruoyi-system`、`ruoyi-framework`、`ruoyi-quartz`、`ruoyi-generator` 和 `ruoyi-admin` 均为 `SUCCESS`。
|
|
|
+
|
|
|
+- [ ] **Step 3: 检查最终差异和未混入文件**
|
|
|
+
|
|
|
+```powershell
|
|
|
+git diff --check
|
|
|
+git status --short
|
|
|
+git log --oneline -4
|
|
|
+```
|
|
|
+
|
|
|
+确认泰语功能提交没有包含 `.claude/homunculus/observations.jsonl`,也没有包含此前未提交的闪送请求 DTO/Controller 注释修改。
|
|
|
+
|
|
|
+- [ ] **Step 4: 报告验证结果和提交 SHA**
|
|
|
+
|
|
|
+交付内容必须列出:
|
|
|
+
|
|
|
+- Locale 解析提交 SHA。
|
|
|
+- 泰语语言包提交 SHA。
|
|
|
+- 默认语言回归测试提交 SHA。
|
|
|
+- 实际执行的测试数量和 Maven 构建结果。
|
|
|
+- 明确说明默认语言仍是 `zh_TW`。
|
|
|
+- 明确说明未修改前端和业务数据多语言映射。
|