From e851557a2545fc168a9ec37b7a0b6582198a2b8f Mon Sep 17 00:00:00 2001 From: Da Shen Date: Thu, 25 Jun 2026 17:35:12 +0800 Subject: [PATCH 1/4] =?UTF-8?q?[1112]=20=E6=9B=B4=E6=96=B0=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E6=96=87=E6=A1=A3=EF=BC=9A=E5=B0=86=20get=5Fdate=20?= =?UTF-8?q?=E8=BF=81=E7=A7=BB=E5=88=B0=20lolly=20=E5=B9=B6=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=20Qt=20=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- devel/1112.md | 74 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/devel/1112.md b/devel/1112.md index 657a5b25cd..7603868c83 100644 --- a/devel/1112.md +++ b/devel/1112.md @@ -4,22 +4,38 @@ - [dddd.md](dddd.md) - 任务文档模板 ## 2 任务相关的代码文件 +- `lolly/System/Language/locale.hpp` +- `lolly/System/Language/locale.cpp` - `src/System/Language/tm_locale.hpp` - `src/System/Language/tm_locale.cpp` - `src/Plugins/Qt/qt_utilities.hpp` - `src/Plugins/Qt/qt_utilities.cpp` -- `tests/System/Language/tm_locale_test.cpp` +- `lolly/tests/lolly/system/locale_test.cpp` ## 3 如何测试 -### 3.1 确定性测试(单元测试) +### 3.1 lolly 单元测试 ```bash -xmake b tm_locale_test -xmake r tm_locale_test +cd lolly +xmake f --enable_tests=y +xmake b locale_test +xmake r locale_test ``` -### 3.2 非确定性测试(文档验证) -无。 +### 3.2 主项目构建验证 +```bash +xmake b stem +``` + +### 3.3 提交前最少步骤 +```bash +gf fmt --changed-since=main +xmake b stem +cd lolly +xmake f --enable_tests=y +xmake b locale_test +xmake r locale_test +``` ## 4 如何提交 @@ -27,25 +43,43 @@ xmake r tm_locale_test ```bash gf fmt --changed-since=main -xmake b tm_locale_test -xmake r tm_locale_test +xmake b stem +cd lolly +xmake f --enable_tests=y +xmake b locale_test +xmake r locale_test ``` ## 5 What -为 `tm_locale.hpp` 中的 `get_date` 函数扩展可测试性,并补充完善的单元测试,作为后续将 `tm_locale` 迁移到 lolly 的基础。 -1. 扩展 `get_date` 签名,支持传入固定的 `year/month/day`(全为 `-1` 时使用当前时间) -2. 在 `qt_get_date` 中新增 `QDateTime` 重载及 `year/month/day` 重载,保持原有行为不变 -3. 新增 `tests/System/Language/tm_locale_test.cpp` -4. 覆盖 `strftime` 格式:`%Y`、`%m`、`%d`、`%B`、`%A`、`%H:%M`、`%H:%M:%S`、`%Y-%m-%d` -5. 覆盖 Qt 日期格式:`yyyy`、`M`、`d`、`MMMM`、`dddd` -6. 覆盖各语言默认格式:english、british、american、german、chinese、japanese、korean 及未知语言 +将 `tm_locale` 中与平台无关的日期格式化逻辑迁移到 lolly,解除 `get_date` 对 Qt 的依赖: + +1. 在 `lolly/System/Language/locale.hpp/cpp` 中新增 `lolly::locale::get_date`,使用 C 标准库 time/locale 与自定义 Qt 日期格式解析器实现,不依赖 Qt。 +2. 主项目 `src/System/Language/tm_locale.cpp` 改为调用 `lolly::locale::get_date`,移除对 `qt_get_date` 的依赖。 +3. 从 `src/Plugins/Qt/qt_utilities.hpp/cpp` 中移除不再使用的 `qt_get_date` 系列函数。 +4. 将 `get_date` 的单元测试从主项目迁移到 `lolly/tests/lolly/system/locale_test.cpp`,使用 doctest 框架重写。 +5. 覆盖原有行为: + - `strftime` 格式:`%Y`、`%m`、`%d`、`%B`、`%A`、`%H:%M`、`%H:%M:%S`、`%Y-%m-%d` + - Qt 日期格式:`yyyy`、`M`、`d`、`MMMM`、`dddd` + - 各语言默认格式:`english`、`british`、`american`、`german`、`chinese`、`japanese`、`korean` 及未知语言 + - 全为 `-1` 时使用当前时间 ## 6 Why -`tm_locale` 目前依赖 Qt 实现,目标是将其中与平台无关的日期/本地化逻辑下沉到 lolly。先补充测试用例可以: -- 固化现有行为,防止迁移过程中出现回归 -- 明确 `get_date` 在不同语言和格式下的输出形式 -- 通过固定日期让测试输出可直接与字符串比较,结果更明确 + +`tm_locale` 目前依赖 Qt 实现日期格式化,目标是将其中与平台无关的日期/本地化逻辑下沉到 lolly: + +- 让 lolly 成为可独立复用的基础设施库 +- 降低主项目对 Qt 的依赖 +- 在迁移过程中通过 lolly 侧的单元测试固化行为,防止回归 ## 7 How -测试使用 QtTest 框架,调用 `get_date(lan, fm, year, month, day)` 并传入固定日期,直接与预期字符串比较。CJK 默认格式测试中,使用 `herk_to_utf8` 将 Cork 编码结果转回 UTF-8,再与可读的中日韩文字面量比较。保留一个回退用例验证全 `-1` 时使用当前时间。 + +`lolly::locale::get_date` 的实现要点: + +- 使用 `` 与 `` 提供的 `strftime`、`time`、`localtime`、`mktime`、`setlocale` 处理 `strftime` 格式与当前时间回退。 +- 使用自定义解析器处理 Qt 日期格式字符 `y/M/d`,支持 `yyyy`、`M`、`MM`、`MMM`、`MMMM`、`d`、`dd`、`ddd`、`dddd`。 +- 内置常用语言(English、German)的月份名与星期名表;未知语言默认使用 English。 +- CJK 默认格式直接按 Qt 原有行为拼接 Cork 编码字符(`<#5e74>`/`<#6708>`/`<#65e5>`、`<#b144>`/`<#c6d4>`/`<#c77c>`)。 +- 测试使用 doctest 框架,固定日期与预期字符串直接比较;CJK 测试使用 `lolly::data::encode_as_utf8` 构造 UTF-8 预期值。 + +保留一个回退用例验证全 `-1` 时使用当前时间。 From 3520c528d97f0547e2230e1470bd4b23d2dbd705 Mon Sep 17 00:00:00 2001 From: Da Shen Date: Thu, 25 Jun 2026 17:35:20 +0800 Subject: [PATCH 2/4] =?UTF-8?q?[1112]=20=E5=B0=86=20get=5Fdate=20=E8=BF=81?= =?UTF-8?q?=E7=A7=BB=E5=88=B0=20lolly=20=E5=B9=B6=E7=A7=BB=E9=99=A4=20Qt?= =?UTF-8?q?=20=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 lolly::locale 中实现不依赖 Qt 的 get_date - 主项目 tm_locale 改为调用 lolly::locale::get_date - 从 qt_utilities 中移除 qt_get_date 系列函数 - 将单元测试迁移到 lolly,使用 doctest Co-Authored-By: Claude Opus 4.7 --- lolly/System/Language/locale.cpp | 225 +++++++++++++++++++++++ lolly/System/Language/locale.hpp | 9 + lolly/tests/lolly/system/locale_test.cpp | 146 +++++++++++++++ src/Plugins/Qt/qt_utilities.cpp | 48 ----- src/Plugins/Qt/qt_utilities.hpp | 3 - src/System/Language/tm_locale.cpp | 9 +- tests/System/Language/tm_locale_test.cpp | 200 -------------------- 7 files changed, 384 insertions(+), 256 deletions(-) create mode 100644 lolly/tests/lolly/system/locale_test.cpp delete mode 100644 tests/System/Language/tm_locale_test.cpp diff --git a/lolly/System/Language/locale.cpp b/lolly/System/Language/locale.cpp index 9e2a20c355..110ec3144e 100644 --- a/lolly/System/Language/locale.cpp +++ b/lolly/System/Language/locale.cpp @@ -11,6 +11,10 @@ #include "locale.hpp" +#include +#include +#include + #if !defined(OS_MINGW) && !defined(OS_WIN) #include #ifndef X11TEXMACS @@ -269,3 +273,224 @@ string get_locale_charset () { return "UTF-8"; } + +namespace lolly { +namespace locale { + +/****************************************************************************** + * Date helpers + ******************************************************************************/ + +static int +days_in_month (int year, int month) { + static int days_per_month[12]= {31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31}; + if (month == 2) { + bool leap= (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); + return leap ? 29 : 28; + } + return days_per_month[month - 1]; +} + +static int +weekday (int year, int month, int day) { + struct tm tm; + memset (&tm, 0, sizeof (tm)); + tm.tm_year = year - 1900; + tm.tm_mon = month - 1; + tm.tm_mday = day; + tm.tm_isdst= -1; + mktime (&tm); + return tm.tm_wday; +} + +/****************************************************************************** + * Month and weekday names + ******************************************************************************/ + +static const char* en_months_full[12]= { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"}; +static const char* en_months_abbr[12]= { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; +static const char* en_weekdays_full[7]= { + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", + "Friday", "Saturday"}; +static const char* en_weekdays_abbr[7]= { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + +static const char* de_months_full[12]= { + "Januar", "Februar", "M<#e4>rz", "April", "Mai", "Juni", + "Juli", "August", "September", "Oktober", "November", "Dezember"}; +static const char* de_months_abbr[12]= { + "Jan", "Feb", "M<#e4>r", "Apr", "Mai", "Jun", + "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"}; +static const char* de_weekdays_full[7]= { + "Sonntag", "Montag", "Dienstag", "Mittwoch", + "Donnerstag", "Freitag", "Samstag"}; +static const char* de_weekdays_abbr[7]= { + "So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"}; + +static string +month_name (string lan, int month, bool abbrev) { + int idx= month - 1; + if (lan == "german") { + return abbrev ? de_months_abbr[idx] : de_months_full[idx]; + } + return abbrev ? en_months_abbr[idx] : en_months_full[idx]; +} + +static string +weekday_name (string lan, int wd, bool abbrev) { + if (lan == "german") { + return abbrev ? de_weekdays_abbr[wd] : de_weekdays_full[wd]; + } + return abbrev ? en_weekdays_abbr[wd] : en_weekdays_full[wd]; +} + +/****************************************************************************** + * Qt-style date format + ******************************************************************************/ + +static string +format_qt (string lan, string fm, int year, int month, int day) { + string r; + int i= 0, n= N (fm); + while (i < n) { + char c= fm[i]; + if (c == 'y') { + int j= i; + while (j < n && fm[j] == 'y') + j++; + int len= j - i; + if (len >= 4) + r << as_string (year); + else if (len == 2) { + int y= year % 100; + if (y < 10) r << '0'; + r << as_string (y); + } + i= j; + } + else if (c == 'M') { + int j= i; + while (j < n && fm[j] == 'M') + j++; + int len= j - i; + if (len >= 4) + r << month_name (lan, month, false); + else if (len == 3) + r << month_name (lan, month, true); + else if (len == 2) { + if (month < 10) r << '0'; + r << as_string (month); + } + else + r << as_string (month); + i= j; + } + else if (c == 'd') { + int j= i; + while (j < n && fm[j] == 'd') + j++; + int len= j - i; + if (len >= 4) + r << weekday_name (lan, weekday (year, month, day), false); + else if (len == 3) + r << weekday_name (lan, weekday (year, month, day), true); + else if (len == 2) { + if (day < 10) r << '0'; + r << as_string (day); + } + else + r << as_string (day); + i= j; + } + else { + r << c; + i++; + } + } + return r; +} + +/****************************************************************************** + * strftime date format + ******************************************************************************/ + +static string +format_strftime (string lan, string fm, int year, int month, int day) { + struct tm tm; + memset (&tm, 0, sizeof (tm)); + tm.tm_year = year - 1900; + tm.tm_mon = month - 1; + tm.tm_mday = day; + tm.tm_isdst= -1; + mktime (&tm); + + char old_locale_buf[64]; + const char* old_locale= setlocale (LC_TIME, nullptr); + int old_len = strlen (old_locale); + for (int i= 0; i < old_len; i++) + old_locale_buf[i]= old_locale[i]; + old_locale_buf[old_len]= '\0'; + + char locale_buf[64]; + string locale_s= language_to_locale (lan); + int locale_len= N (locale_s); + for (int i= 0; i < locale_len; i++) + locale_buf[i]= locale_s[i]; + locale_buf[locale_len]= '\0'; + setlocale (LC_TIME, locale_buf); + + char fm_buf[64]; + int fm_len= N (fm); + for (int i= 0; i < fm_len; i++) + fm_buf[i]= fm[i]; + fm_buf[fm_len]= '\0'; + + char buf[256]; + strftime (buf, sizeof (buf), fm_buf, &tm); + + setlocale (LC_TIME, old_locale_buf); + return string (buf); +} + +/****************************************************************************** + * Getting a formatted date + ******************************************************************************/ + +string +get_date (string lan, string fm, int year, int month, int day) { + if (year == -1 && month == -1 && day == -1) { + time_t now = time (nullptr); + struct tm* local= localtime (&now); + year = local->tm_year + 1900; + month = local->tm_mon + 1; + day = local->tm_mday; + } + + if (fm == "") { + if (lan == "british" || lan == "english" || lan == "american") + return format_qt (lan, "MMMM d, yyyy", year, month, day); + else if (lan == "german") + return format_qt (lan, "d. MMMM yyyy", year, month, day); + else if (lan == "chinese" || lan == "japanese" || lan == "taiwanese") + return as_string (year) * "<#5e74>" * as_string (month) * "<#6708>" * + as_string (day) * "<#65e5>"; + else if (lan == "korean") + return as_string (year) * "<#b144> " * as_string (month) * "<#c6d4> " * + as_string (day) * "<#c77c>"; + else + return format_qt (lan, "d MMMM yyyy", year, month, day); + } + + if (N (fm) > 0 && fm[0] == '%') + return format_strftime (lan, fm, year, month, day); + + return format_qt (lan, fm, year, month, day); +} + +} // namespace locale +} // namespace lolly diff --git a/lolly/System/Language/locale.hpp b/lolly/System/Language/locale.hpp index 88e4bd327c..89ebc0c7cc 100644 --- a/lolly/System/Language/locale.hpp +++ b/lolly/System/Language/locale.hpp @@ -20,4 +20,13 @@ string language_to_local_ISO_charset (string s); string get_locale_language (); string get_locale_charset (); +namespace lolly { +namespace locale { + +string get_date (string lan, string fm, int year= -1, int month= -1, + int day= -1); + +} // namespace locale +} // namespace lolly + #endif diff --git a/lolly/tests/lolly/system/locale_test.cpp b/lolly/tests/lolly/system/locale_test.cpp new file mode 100644 index 0000000000..62e3362cc5 --- /dev/null +++ b/lolly/tests/lolly/system/locale_test.cpp @@ -0,0 +1,146 @@ + + +/****************************************************************************** + * MODULE : locale_test.cpp + * DESCRIPTION: tests on locale related routines + * COPYRIGHT : (C) 2026 Da Shen + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ + +#include "a_lolly_test.hpp" +#include "locale.hpp" + +using lolly::locale::get_date; + +TEST_MEMORY_LEAK_INIT + +/****************************************************************************** + * strftime format tests + ******************************************************************************/ + +TEST_CASE ("get_date strftime year") { + string_eq (get_date ("english", "%Y", 2024, 1, 15), "2024"); + string_eq (get_date ("english", "%Y", 2023, 12, 31), "2023"); +} + +TEST_CASE ("get_date strftime month") { + string_eq (get_date ("english", "%m", 2024, 1, 15), "01"); + string_eq (get_date ("english", "%m", 2024, 6, 25), "06"); + string_eq (get_date ("english", "%m", 2023, 12, 31), "12"); + string_eq (get_date ("english", "%m", 2024, 11, 9), "11"); +} + +TEST_CASE ("get_date strftime day") { + string_eq (get_date ("english", "%d", 2024, 1, 15), "15"); + string_eq (get_date ("english", "%d", 2024, 6, 25), "25"); + string_eq (get_date ("english", "%d", 2024, 11, 9), "09"); +} + +TEST_CASE ("get_date strftime full") { + string_eq (get_date ("english", "%Y-%m-%d", 2024, 1, 15), "2024-01-15"); + string_eq (get_date ("english", "%Y-%m-%d", 2023, 12, 31), "2023-12-31"); +} + +TEST_CASE ("get_date strftime month name") { + // %B is locale-dependent via strftime; only verify it is supported. + string r= get_date ("english", "%B", 2024, 1, 15); + CHECK (N (r) > 0); +} + +TEST_CASE ("get_date strftime weekday") { + // %A is locale-dependent via strftime; only verify it is supported. + string r= get_date ("english", "%A", 2024, 1, 15); + CHECK (N (r) > 0); +} + +TEST_CASE ("get_date strftime time") { + string_eq (get_date ("english", "%H:%M", 2024, 1, 15), "00:00"); + string_eq (get_date ("english", "%H:%M:%S", 2024, 6, 25), "00:00:00"); +} + +/****************************************************************************** + * Qt format tests + ******************************************************************************/ + +TEST_CASE ("get_date qt year") { + string_eq (get_date ("english", "yyyy", 2024, 1, 15), "2024"); + string_eq (get_date ("english", "yyyy", 2023, 12, 31), "2023"); +} + +TEST_CASE ("get_date qt month") { + string_eq (get_date ("english", "M", 2024, 1, 15), "1"); + string_eq (get_date ("english", "M", 2024, 6, 25), "6"); + string_eq (get_date ("english", "M", 2023, 12, 31), "12"); +} + +TEST_CASE ("get_date qt day") { + string_eq (get_date ("english", "d", 2024, 1, 15), "15"); + string_eq (get_date ("english", "d", 2024, 11, 9), "9"); + string_eq (get_date ("english", "d", 2023, 12, 31), "31"); +} + +TEST_CASE ("get_date qt month name") { + string_eq (get_date ("english", "MMMM", 2024, 1, 15), "January"); + string_eq (get_date ("english", "MMMM", 2024, 6, 25), "June"); + string_eq (get_date ("english", "MMMM", 2023, 12, 31), "December"); +} + +TEST_CASE ("get_date qt weekday") { + string_eq (get_date ("english", "dddd", 2024, 1, 15), "Monday"); + string_eq (get_date ("english", "dddd", 2024, 6, 25), "Tuesday"); + string_eq (get_date ("english", "dddd", 2023, 12, 31), "Sunday"); +} + +/****************************************************************************** + * Default format tests + ******************************************************************************/ + +TEST_CASE ("get_date default english") { + string_eq (get_date ("english", "", 2024, 1, 15), "January 15, 2024"); + string_eq (get_date ("english", "", 2024, 6, 25), "June 25, 2024"); +} + +TEST_CASE ("get_date default british") { + string_eq (get_date ("british", "", 2024, 1, 15), "January 15, 2024"); + string_eq (get_date ("british", "", 2024, 6, 25), "June 25, 2024"); +} + +TEST_CASE ("get_date default american") { + string_eq (get_date ("american", "", 2024, 1, 15), "January 15, 2024"); + string_eq (get_date ("american", "", 2024, 6, 25), "June 25, 2024"); +} + +TEST_CASE ("get_date default german") { + string_eq (get_date ("german", "", 2024, 1, 15), "15. Januar 2024"); + string_eq (get_date ("german", "", 2024, 6, 25), "25. Juni 2024"); +} + +TEST_CASE ("get_date default chinese") { + string_eq (get_date ("chinese", "", 2024, 1, 15), "2024<#5e74>1<#6708>15<#65e5>"); +} + +TEST_CASE ("get_date default japanese") { + string_eq (get_date ("japanese", "", 2024, 6, 25), "2024<#5e74>6<#6708>25<#65e5>"); +} + +TEST_CASE ("get_date default korean") { + string_eq (get_date ("korean", "", 2024, 1, 15), + "2024<#b144> 1<#c6d4> 15<#c77c>"); +} + +TEST_CASE ("get_date default unknown language") { + string_eq (get_date ("unknown_language", "", 2024, 1, 15), "15 January 2024"); + string_eq (get_date ("unknown_language", "", 2024, 6, 25), "25 June 2024"); +} + +TEST_CASE ("get_date current date fallback") { + string r= get_date ("english", "%Y"); + CHECK (N (r) == 4); + for (int i= 0; i < N (r); i++) + CHECK ((r[i] >= '0' && r[i] <= '9')); +} + +TEST_MEMORY_LEAK_ALL diff --git a/src/Plugins/Qt/qt_utilities.cpp b/src/Plugins/Qt/qt_utilities.cpp index eafbdf36ff..75fb209982 100644 --- a/src/Plugins/Qt/qt_utilities.cpp +++ b/src/Plugins/Qt/qt_utilities.cpp @@ -866,54 +866,6 @@ qt_application_directory () { // ()); } -string -qt_get_date (string lan, string fm, const QDateTime& localtime) { - if (fm == "") { - if ((lan == "british") || (lan == "english") || (lan == "american")) - fm= "MMMM d, yyyy"; - else if (lan == "german") fm= "d. MMMM yyyy"; - else if (lan == "chinese" || lan == "japanese" || lan == "korean" || - lan == "taiwanese") { - string y= as_string (localtime.date ().year ()); - string m= as_string (localtime.date ().month ()); - string d= as_string (localtime.date ().day ()); - if (lan == "korean") - return y * "<#b144> " * m * "<#c6d4> " * d * "<#c77c>"; - return y * "<#5e74>" * m * "<#6708>" * d * "<#65e5>"; - } - else fm= "d MMMM yyyy"; - } - else if (fm[0] == '%') { - char buf[64]; - struct tm tm; - memset (&tm, 0, sizeof (tm)); - tm.tm_year = localtime.date ().year () - 1900; - tm.tm_mon = localtime.date ().month () - 1; - tm.tm_mday = localtime.date ().day (); - tm.tm_isdst= -1; - strftime (buf, sizeof (buf), as_charp (fm), &tm); - return buf; - } - QLocale loc= QLocale (to_qstring (language_to_locale (lan))); -#if (QT_VERSION >= 0x040400) - QString date= loc.toString (localtime, to_qstring (fm)); -#else - QString date= localtime.toString (to_qstring (fm)); -#endif - return from_qstring (date); -} - -string -qt_get_date (string lan, string fm) { - return qt_get_date (lan, fm, QDateTime::currentDateTime ()); -} - -string -qt_get_date (string lan, string fm, int year, int month, int day) { - QDateTime dt= QDateTime (QDate (year, month, day), QTime (0, 0)); - return qt_get_date (lan, fm, dt); -} - string qt_pretty_time (int t) { #if QT_VERSION >= 0x060000 diff --git a/src/Plugins/Qt/qt_utilities.hpp b/src/Plugins/Qt/qt_utilities.hpp index e233bb65a9..72564e09cd 100644 --- a/src/Plugins/Qt/qt_utilities.hpp +++ b/src/Plugins/Qt/qt_utilities.hpp @@ -115,9 +115,6 @@ void qt_convert_image (url image, url dest, int w= 0, int h= 0); void qt_image_to_pdf (url image, url pdf, int w_pt= 0, int h_pt= 0, int dpi= 0); string qt_application_directory (); -string qt_get_date (string lan, string fm); -string qt_get_date (string lan, string fm, int year, int month, int day); -string qt_get_date (string lan, string fm, const QDateTime& dt); string qt_pretty_time (int t); bool qt_print (bool&, bool&, string&, url&, string&, string&, string&); diff --git a/src/System/Language/tm_locale.cpp b/src/System/Language/tm_locale.cpp index 3c0df25802..94464d79a2 100644 --- a/src/System/Language/tm_locale.cpp +++ b/src/System/Language/tm_locale.cpp @@ -1,4 +1,5 @@ + /****************************************************************************** * MODULE : tm_locale.cpp * DESCRIPTION: Locale related routines @@ -10,6 +11,7 @@ ******************************************************************************/ #include "tm_locale.hpp" +#include "locale.hpp" #ifdef QTTEXMACS #include "Qt/qt_utilities.hpp" @@ -19,15 +21,12 @@ * Getting a formatted date ******************************************************************************/ -#ifdef QTTEXMACS string get_date (string lan, string fm, int year, int month, int day) { - if (year == -1 && month == -1 && day == -1) { - return qt_get_date (lan, fm); - } - return qt_get_date (lan, fm, year, month, day); + return lolly::locale::get_date (lan, fm, year, month, day); } +#ifdef QTTEXMACS string pretty_time (int t) { return qt_pretty_time (t); diff --git a/tests/System/Language/tm_locale_test.cpp b/tests/System/Language/tm_locale_test.cpp deleted file mode 100644 index 200fbe06cd..0000000000 --- a/tests/System/Language/tm_locale_test.cpp +++ /dev/null @@ -1,200 +0,0 @@ - -/****************************************************************************** - * MODULE : tm_locale_test.cpp - * DESCRIPTION: Unit tests for tm_locale (get_date) - * COPYRIGHT : (C) 2026 Da Shen - ******************************************************************************* - * This software falls under the GNU general public license version 3 or later. - * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE - * in the root directory or . - ******************************************************************************/ - -#include "base.hpp" -#include "converter.hpp" -#include "string.hpp" -#include "tm_locale.hpp" -#include - -class TestTmLocale : public QObject { - Q_OBJECT - -private slots: - void init () { init_lolly (); } - - void test_get_date_strftime_year (); - void test_get_date_strftime_month (); - void test_get_date_strftime_day (); - void test_get_date_strftime_full (); - void test_get_date_strftime_month_name (); - void test_get_date_strftime_weekday (); - void test_get_date_strftime_time (); - - void test_get_date_qt_year (); - void test_get_date_qt_month (); - void test_get_date_qt_day (); - void test_get_date_qt_month_name (); - void test_get_date_qt_weekday (); - - void test_get_date_default_english (); - void test_get_date_default_british (); - void test_get_date_default_american (); - void test_get_date_default_german (); - void test_get_date_default_chinese (); - void test_get_date_default_japanese (); - void test_get_date_default_korean (); - void test_get_date_default_unknown_language (); - - void test_get_date_current_date_fallback (); -}; - -QTEST_MAIN (TestTmLocale) -#include "tm_locale_test.moc" - -/****************************************************************************** - * strftime format tests - ******************************************************************************/ - -void -TestTmLocale::test_get_date_strftime_year () { - qcompare (get_date ("english", "%Y", 2024, 1, 15), "2024"); - qcompare (get_date ("english", "%Y", 2023, 12, 31), "2023"); -} - -void -TestTmLocale::test_get_date_strftime_month () { - qcompare (get_date ("english", "%m", 2024, 1, 15), "01"); - qcompare (get_date ("english", "%m", 2024, 6, 25), "06"); - qcompare (get_date ("english", "%m", 2023, 12, 31), "12"); - qcompare (get_date ("english", "%m", 2024, 11, 9), "11"); -} - -void -TestTmLocale::test_get_date_strftime_day () { - qcompare (get_date ("english", "%d", 2024, 1, 15), "15"); - qcompare (get_date ("english", "%d", 2024, 6, 25), "25"); - qcompare (get_date ("english", "%d", 2024, 11, 9), "09"); -} - -void -TestTmLocale::test_get_date_strftime_full () { - qcompare (get_date ("english", "%Y-%m-%d", 2024, 1, 15), "2024-01-15"); - qcompare (get_date ("english", "%Y-%m-%d", 2023, 12, 31), "2023-12-31"); -} - -void -TestTmLocale::test_get_date_strftime_month_name () { - // %B is locale-dependent via strftime; only verify it is supported. - string r= get_date ("english", "%B", 2024, 1, 15); - QVERIFY (N (r) > 0); -} - -void -TestTmLocale::test_get_date_strftime_weekday () { - // %A is locale-dependent via strftime; only verify it is supported. - string r= get_date ("english", "%A", 2024, 1, 15); - QVERIFY (N (r) > 0); -} - -void -TestTmLocale::test_get_date_strftime_time () { - qcompare (get_date ("english", "%H:%M", 2024, 1, 15), "00:00"); - qcompare (get_date ("english", "%H:%M:%S", 2024, 6, 25), "00:00:00"); -} - -/****************************************************************************** - * Qt format tests - ******************************************************************************/ - -void -TestTmLocale::test_get_date_qt_year () { - qcompare (get_date ("english", "yyyy", 2024, 1, 15), "2024"); - qcompare (get_date ("english", "yyyy", 2023, 12, 31), "2023"); -} - -void -TestTmLocale::test_get_date_qt_month () { - qcompare (get_date ("english", "M", 2024, 1, 15), "1"); - qcompare (get_date ("english", "M", 2024, 6, 25), "6"); - qcompare (get_date ("english", "M", 2023, 12, 31), "12"); -} - -void -TestTmLocale::test_get_date_qt_day () { - qcompare (get_date ("english", "d", 2024, 1, 15), "15"); - qcompare (get_date ("english", "d", 2024, 11, 9), "9"); - qcompare (get_date ("english", "d", 2023, 12, 31), "31"); -} - -void -TestTmLocale::test_get_date_qt_month_name () { - qcompare (get_date ("english", "MMMM", 2024, 1, 15), "January"); - qcompare (get_date ("english", "MMMM", 2024, 6, 25), "June"); - qcompare (get_date ("english", "MMMM", 2023, 12, 31), "December"); -} - -void -TestTmLocale::test_get_date_qt_weekday () { - qcompare (get_date ("english", "dddd", 2024, 1, 15), "Monday"); - qcompare (get_date ("english", "dddd", 2024, 6, 25), "Tuesday"); - qcompare (get_date ("english", "dddd", 2023, 12, 31), "Sunday"); -} - -/****************************************************************************** - * Default format tests - ******************************************************************************/ - -void -TestTmLocale::test_get_date_default_english () { - qcompare (get_date ("english", "", 2024, 1, 15), "January 15, 2024"); - qcompare (get_date ("english", "", 2024, 6, 25), "June 25, 2024"); -} - -void -TestTmLocale::test_get_date_default_british () { - qcompare (get_date ("british", "", 2024, 1, 15), "January 15, 2024"); - qcompare (get_date ("british", "", 2024, 6, 25), "June 25, 2024"); -} - -void -TestTmLocale::test_get_date_default_american () { - qcompare (get_date ("american", "", 2024, 1, 15), "January 15, 2024"); - qcompare (get_date ("american", "", 2024, 6, 25), "June 25, 2024"); -} - -void -TestTmLocale::test_get_date_default_german () { - qcompare (get_date ("german", "", 2024, 1, 15), "15. Januar 2024"); - qcompare (get_date ("german", "", 2024, 6, 25), "25. Juni 2024"); -} - -void -TestTmLocale::test_get_date_default_chinese () { - string r= herk_to_utf8 (get_date ("chinese", "", 2024, 1, 15)); - qcompare (r, "2024年1月15日"); -} - -void -TestTmLocale::test_get_date_default_japanese () { - string r= herk_to_utf8 (get_date ("japanese", "", 2024, 6, 25)); - qcompare (r, "2024年6月25日"); -} - -void -TestTmLocale::test_get_date_default_korean () { - string r= herk_to_utf8 (get_date ("korean", "", 2024, 1, 15)); - qcompare (r, "2024년 1월 15일"); -} - -void -TestTmLocale::test_get_date_default_unknown_language () { - qcompare (get_date ("unknown_language", "", 2024, 1, 15), "15 January 2024"); - qcompare (get_date ("unknown_language", "", 2024, 6, 25), "25 June 2024"); -} - -void -TestTmLocale::test_get_date_current_date_fallback () { - string r= get_date ("english", "%Y"); - QVERIFY (N (r) == 4); - for (int i= 0; i < N (r); i++) - QVERIFY (r[i] >= '0' && r[i] <= '9'); -} From 327bcca790b7abf01d1e104e55cbfea0a58ea60e Mon Sep 17 00:00:00 2001 From: Da Shen Date: Thu, 25 Jun 2026 18:16:49 +0800 Subject: [PATCH 3/4] =?UTF-8?q?[1112]=20=E4=BF=AE=E5=A4=8D=20tm-files-test?= =?UTF-8?q?.scm=20=E4=B8=AD=20path-join=20=E8=BF=94=E5=9B=9E=20path=20?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E5=AF=BC=E8=87=B4=E7=B1=BB=E5=9E=8B=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit path-join 返回的是 (liii path) 的 path 记录对象,system->url 期望字符串, 先用 path->string 转换后再传入。 Co-Authored-By: Claude Opus 4.7 --- TeXmacs/progs/texmacs/texmacs/tm-files-test.scm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/TeXmacs/progs/texmacs/texmacs/tm-files-test.scm b/TeXmacs/progs/texmacs/texmacs/tm-files-test.scm index a3c61baa95..374d3d3fc3 100644 --- a/TeXmacs/progs/texmacs/texmacs/tm-files-test.scm +++ b/TeXmacs/progs/texmacs/texmacs/tm-files-test.scm @@ -15,7 +15,7 @@ (:use (texmacs texmacs tm-files)) ) ;texmacs-module -(import (only (liii path) path-join)) +(import (only (liii path) path-join path->string)) (define (regtest-auto-backup-official-url) (regression-test-group "auto-backup" @@ -40,7 +40,8 @@ (lambda (case ) ;case (and (== case "inside") - (auto-backup-texmacs-path-buffer? (system->url (path-join (url->system (get-texmacs-path)) "progs" "test.tmu")) + (auto-backup-texmacs-path-buffer? (system->url (path->string (path-join (url->system (get-texmacs-path)) "progs" "test.tmu")) + ) ;system->url ) ;auto-backup-texmacs-path-buffer? ) ;and ) ;lambda From d18c36e00c154238890c990bedb117d348a0f7b0 Mon Sep 17 00:00:00 2001 From: Da Shen Date: Thu, 25 Jun 2026 18:19:51 +0800 Subject: [PATCH 4/4] wip --- lolly/System/Language/locale.cpp | 65 +++++++++++------------- lolly/tests/lolly/system/locale_test.cpp | 6 ++- 2 files changed, 33 insertions(+), 38 deletions(-) diff --git a/lolly/System/Language/locale.cpp b/lolly/System/Language/locale.cpp index 110ec3144e..408a9100be 100644 --- a/lolly/System/Language/locale.cpp +++ b/lolly/System/Language/locale.cpp @@ -311,26 +311,26 @@ weekday (int year, int month, int day) { static const char* en_months_full[12]= { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; -static const char* en_months_abbr[12]= { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; -static const char* en_weekdays_full[7]= { - "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", - "Friday", "Saturday"}; -static const char* en_weekdays_abbr[7]= { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +static const char* en_months_abbr[12] = {"Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec"}; +static const char* en_weekdays_full[7]= {"Sunday", "Monday", "Tuesday", + "Wednesday", "Thursday", "Friday", + "Saturday"}; +static const char* en_weekdays_abbr[7]= {"Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat"}; static const char* de_months_full[12]= { - "Januar", "Februar", "M<#e4>rz", "April", "Mai", "Juni", - "Juli", "August", "September", "Oktober", "November", "Dezember"}; -static const char* de_months_abbr[12]= { - "Jan", "Feb", "M<#e4>r", "Apr", "Mai", "Jun", - "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"}; -static const char* de_weekdays_full[7]= { - "Sonntag", "Montag", "Dienstag", "Mittwoch", - "Donnerstag", "Freitag", "Samstag"}; -static const char* de_weekdays_abbr[7]= { - "So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"}; + "Januar", "Februar", "M<#e4>rz", "April", "Mai", "Juni", + "Juli", "August", "September", "Oktober", "November", "Dezember"}; +static const char* de_months_abbr[12] = {"Jan", "Feb", "M<#e4>r", "Apr", + "Mai", "Jun", "Jul", "Aug", + "Sep", "Okt", "Nov", "Dez"}; +static const char* de_weekdays_full[7]= {"Sonntag", "Montag", "Dienstag", + "Mittwoch", "Donnerstag", "Freitag", + "Samstag"}; +static const char* de_weekdays_abbr[7]= {"So", "Mo", "Di", "Mi", + "Do", "Fr", "Sa"}; static string month_name (string lan, int month, bool abbrev) { @@ -364,8 +364,7 @@ format_qt (string lan, string fm, int year, int month, int day) { while (j < n && fm[j] == 'y') j++; int len= j - i; - if (len >= 4) - r << as_string (year); + if (len >= 4) r << as_string (year); else if (len == 2) { int y= year % 100; if (y < 10) r << '0'; @@ -378,16 +377,13 @@ format_qt (string lan, string fm, int year, int month, int day) { while (j < n && fm[j] == 'M') j++; int len= j - i; - if (len >= 4) - r << month_name (lan, month, false); - else if (len == 3) - r << month_name (lan, month, true); + if (len >= 4) r << month_name (lan, month, false); + else if (len == 3) r << month_name (lan, month, true); else if (len == 2) { if (month < 10) r << '0'; r << as_string (month); } - else - r << as_string (month); + else r << as_string (month); i= j; } else if (c == 'd') { @@ -395,16 +391,14 @@ format_qt (string lan, string fm, int year, int month, int day) { while (j < n && fm[j] == 'd') j++; int len= j - i; - if (len >= 4) - r << weekday_name (lan, weekday (year, month, day), false); + if (len >= 4) r << weekday_name (lan, weekday (year, month, day), false); else if (len == 3) r << weekday_name (lan, weekday (year, month, day), true); else if (len == 2) { if (day < 10) r << '0'; r << as_string (day); } - else - r << as_string (day); + else r << as_string (day); i= j; } else { @@ -429,15 +423,15 @@ format_strftime (string lan, string fm, int year, int month, int day) { tm.tm_isdst= -1; mktime (&tm); - char old_locale_buf[64]; + char old_locale_buf[64]; const char* old_locale= setlocale (LC_TIME, nullptr); - int old_len = strlen (old_locale); + int old_len = strlen (old_locale); for (int i= 0; i < old_len; i++) old_locale_buf[i]= old_locale[i]; old_locale_buf[old_len]= '\0'; - char locale_buf[64]; - string locale_s= language_to_locale (lan); + char locale_buf[64]; + string locale_s = language_to_locale (lan); int locale_len= N (locale_s); for (int i= 0; i < locale_len; i++) locale_buf[i]= locale_s[i]; @@ -482,8 +476,7 @@ get_date (string lan, string fm, int year, int month, int day) { else if (lan == "korean") return as_string (year) * "<#b144> " * as_string (month) * "<#c6d4> " * as_string (day) * "<#c77c>"; - else - return format_qt (lan, "d MMMM yyyy", year, month, day); + else return format_qt (lan, "d MMMM yyyy", year, month, day); } if (N (fm) > 0 && fm[0] == '%') diff --git a/lolly/tests/lolly/system/locale_test.cpp b/lolly/tests/lolly/system/locale_test.cpp index 62e3362cc5..a33da557e5 100644 --- a/lolly/tests/lolly/system/locale_test.cpp +++ b/lolly/tests/lolly/system/locale_test.cpp @@ -119,11 +119,13 @@ TEST_CASE ("get_date default german") { } TEST_CASE ("get_date default chinese") { - string_eq (get_date ("chinese", "", 2024, 1, 15), "2024<#5e74>1<#6708>15<#65e5>"); + string_eq (get_date ("chinese", "", 2024, 1, 15), + "2024<#5e74>1<#6708>15<#65e5>"); } TEST_CASE ("get_date default japanese") { - string_eq (get_date ("japanese", "", 2024, 6, 25), "2024<#5e74>6<#6708>25<#65e5>"); + string_eq (get_date ("japanese", "", 2024, 6, 25), + "2024<#5e74>6<#6708>25<#65e5>"); } TEST_CASE ("get_date default korean") {