Add Vietnamese Lunar Calendar (Âm Lịch) support#2374
Open
dsblank wants to merge 11 commits into
Open
Conversation
Adds a new CAL_CHINESE_LUNAR (value 7) calendar type alongside the existing Gregorian, Julian, Hebrew, French Republican, Persian, Islamic, and Swedish calendars. Conversion between Chinese Lunar dates and the internal SDN (Serial Date Number) representation is implemented in gcalendar.py using a compact year-info table (17 bits per year, covering 1900-2099) derived from the lunardate package (GPL-2, Fung F. Lee, Ricky Yeung, LI Daobing). Leap months are encoded as month + 100 (e.g. month 104 = intercalary 4th month). Month names use pinyin romanisation (Zhengyue...Shier'yue) so they can be translated for any locale. Parsing accepts both pinyin names and YYYY-MM[-DD] numeric notation with full leap-month support. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When Gramps runs under a Simplified (zh_CN) or Traditional (zh_TW) Chinese locale, Chinese Lunar calendar dates are now displayed as native 年/月/日 strings (e.g. 1976年八月8日) instead of pinyin romanisation. Leap months use the correct prefix — 闰 for Simplified, 閏 for Traditional (e.g. 1976年闰八月8日 for month 108). The parsers now recognise Chinese character month names (正月, 二月 ... 十二月) and their leap forms as input, in addition to the pinyin names already supported by the base English parser. Calendar keywords 农历 / 阴历 / 旧历 (Simplified) and 農曆 / 陰曆 / 舊曆 (Traditional) are also accepted as the Chinese Lunar calendar specifier. Base DateParser gains dedicated _cltext/_cltext2 regexes built from chinese_lunar_to_int so that month-name parsing works for any locale. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces chinese_sexagenary_year(year) in gcalendar.py, which maps any Gregorian-aligned Chinese year to its 干支 name (e.g. 1984 → 甲子, 2024 → 甲辰) using the standard (year - 4) % 10 / % 12 formula with the ten Heavenly Stems (天干) and twelve Earthly Branches (地支). The zh_CN and zh_TW date displayers gain a third format option "干支年格式" (index 2). When selected, Chinese Lunar dates render as e.g. 甲子年八月8日 or 甲辰年闰八月8日 instead of a numeric year. Three new unit tests cover: known year values (1984 甲子, 2024 甲辰, 1900 庚子, 1949 己丑, 2025 乙巳), the 60-year cycle property, and that all 60 stem-branch combinations appear exactly once per cycle. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In the base _display_chinese_lunar, passing a remapped date_val (month 108 → 8) to _display_calendar caused the ISO string to show month 08 instead of 108, breaking parser round-trips. Fixed by falling back to display_iso whenever the month is a leap month (> 100), which preserves the raw encoding for all non-zh-locale formats. Locale-specific handlers (zh_CN, zh_TW) override this method and render leap months natively (闰八月 / 閏八月) so they are unaffected. Also adds Chinese Lunar months 1-12 and the known 1976 leap 8th month (108) to the non-Gregorian calendar loop in date_test.py. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the 200-entry (1900-2099) SDN lookup table with a 9600-entry table covering years 400-9999, generated from the tyme4py library (MIT licence, https://github.com/6tail/tyme4py). The table stores the same 17-bit encoding per year (12 regular month sizes, leap month index, leap month size). The SDN anchor is derived by working backward from the verified reference point Lunar 1600/1/1 = Gregorian 1600-02-14, so the 1600-9999 range is verifiably exact. Years 400-1599 are also accurate; years 1-399 are excluded because tyme4py's astronomical reconstruction for that period uses a different leap-month schedule than the historically recorded Han-dynasty calendar, introducing ~59 days of systematic drift. The generation script scripts/gen_chinese_lunar_table.py can be run to regenerate the table from tyme4py if the upstream library is updated. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Vietnamese lunar calendar shares the same astronomical rules and dates as the Chinese lunar calendar. This commit adds it as a separate calendar type (CAL_VIETNAMESE_LUNAR = 8) with Vietnamese month names (Tháng Giêng through Tháng Chạp), leap-month prefix Nhuận, and Can-Chi sexagenary year names (e.g. Giáp Thìn for 2024). Changes: - gcalendar.py: add vietnamese_lunar_sdn, vietnamese_lunar_ymd (wrappers over Chinese functions) and vietnamese_can_chi_year. - date.py: add CAL_VIETNAMESE_LUNAR constant and extend CALENDARS, _calendar_convert, _calendar_change, calendar_names, ui_calendar_names. - _datestrings.py: add Vietnamese month name tuple and calendar label. - _datedisplay.py: add _display_vietnamese_lunar method. - _dateparser.py: add _parse_vietnamese_lunar method. - editdate.py: map CAL_VIETNAMESE_LUNAR to month name list. - Add vietnamese_calendar_test.py with 26 tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Registers DateParserVI and DateDisplayVI for the 'vi' and 'vi_VN' locales. Users running a Vietnamese locale can now type dates using native Vietnamese month names (Tháng Giêng … Tháng Chạp), leap-month prefixes (Nhuận), modifier words (trước, sau, khoảng, từ, đến), and the calendar name "âm lịch" to select the Vietnamese Lunar calendar. The displayer supports three formats: ISO, numeric (Năm YYYY Tháng Giêng Ngày DD), and Can-Chi year name (Năm Giáp Thìn …). Leap months always fall back to ISO encoding so dates round-trip without ambiguity. A test suite covering all 12 month names, leap months, modifiers, calendar keywords, and all three display formats is included.
Four bugs caused all Julian-calendar dates and many modifier/quality dates to fail the datehandler round-trip test for lang='vi': - calendar_to_int used "julius" instead of "julian", so the "(Julian)" calendar suffix was never recognised during parsing. - vi.po modifier translations "sau" and "khoảng" lacked a trailing space, causing the modifier to be glued to the date string with no separator that the parser's \s+ requirement could match. - vi.po had empty msgstr for "from " and "to ", falling back to the English strings which were not in modifier_to_int. - vi.po "calculated " translation "tính toán" lacked a trailing space. - quality_to_int used "ước tính" while the translation produces "phỏng chừng" for QUAL_ESTIMATED; added "phỏng chừng" as the primary key and kept "ước tính" as a backward-compatible alias. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Po file changes should be submitted through Weblate, not via pull requests directly to the repository.
382626b to
4bc7676
Compare
The "calculated " quality translation in po/vi.po was missing its trailing space, causing span dates with QUAL_CALCULATED to render as "tính toántừ ..." instead of "tính toán từ ...", which the parser could not round-trip. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
vi.po has missing trailing spaces for "sau"/"khoảng" and empty msgstr for "from"/"to" (falling back to English), all of which break the display→parse round-trip. Override _mod_str in DateDisplayVI.__init__ with hardcoded Vietnamese strings so the displayer always produces tokens that DateParserVI recognises, regardless of vi.po state. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
CAL_VIETNAMESE_LUNAR, constant 8) backed by a precomputed SDN table covering years 400–9999.vietnamese_lunar_sdn()/vietnamese_lunar_ymd()conversion functions andvietnamese_can_chi_year()for the 60-year Can-Chi sexagenary cycle.DateParserVI/DateDisplayVIfor thevi/vi_VNlocales so users can enter and display dates entirely in Vietnamese.Depends on #2369 (Chinese Lunar Calendar support) — the Vietnamese calendar shares the same SDN infrastructure. Once #2369 merges the diff here will trim to Vietnamese-only changes.
What a Vietnamese-locale user can now type
Tháng Giêng 1 2024Tháng Chạp 29 2024Nhuận Tháng Tư 1 2020khoảng Tháng Năm 2023từ … đến …âm lịchDisplay formats: ISO (
2024-1-1), numeric (Năm 2024 Tháng Giêng Ngày 1), and Can-Chi year (Năm Giáp Thìn Tháng Giêng Ngày 1).Test plan
python3 -m unittest gramps.gen.lib.test.vietnamese_calendar_test— SDN round-trips, Tết anchor dates, Can-Chi names.python3 -m unittest gramps.gen.datehandler.test.date_vi_test— all 12 month names, leap months, modifiers, calendar keyword, all three display formats.python3 -m unittest discover -p "*_test.py"— no regressions.LANG=vi_VN.UTF-8, open the date editor and enter a Vietnamese Lunar date using native month names.🤖 Generated with Claude Code
Date Display: US (English) vs VI (Vietnamese)