@lichta/core 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -73,22 +73,106 @@ declare class LichTa {
73
73
  }
74
74
 
75
75
  /**
76
- * Lấy ra chuỗi tả toàn bộ Can, Chi và Mệnh dựa vào số năm (Ví dụ: 2024)
77
- * Theo quy ước: Năm 4 (sau CN) là năm Giáp Tý (Can index 0, Chi index 0)
76
+ * Internationalization Hỗ trợ song ngữ Việt-Anh
78
77
  */
79
- declare function getYearDetails(year: number): {
80
- can: "Giáp" | "Ất" | "Bính" | "Đinh" | "Mậu" | "Kỷ" | "Canh" | "Tân" | "Nhâm" | "Quý";
81
- chi: "Tý" | "Sửu" | "Dần" | "Mão" | "Thìn" | "Tỵ" | "Ngọ" | "Mùi" | "Thân" | "Dậu" | "Tuất" | "Hợi";
78
+ type Locale = 'vi' | 'en' | 'ja' | 'ko';
79
+ /**
80
+ * Lấy bộ dịch theo locale
81
+ * @param locale - Ngôn ngữ ('vi' | 'en' | 'ja' | 'ko')
82
+ */
83
+ declare function t(locale: Locale): {
84
+ readonly heavenlyStems: readonly ["Giáp", "Ất", "Bính", "Đinh", "Mậu", "Kỷ", "Canh", "Tân", "Nhâm", "Quý"];
85
+ readonly earthlyBranches: readonly ["Tý", "Sửu", "Dần", "Mão", "Thìn", "Tỵ", "Ngọ", "Mùi", "Thân", "Dậu", "Tuất", "Hợi"];
86
+ readonly fiveElements: readonly ["Kim", "Mộc", "Thủy", "Hỏa", "Thổ"];
87
+ readonly zodiacAnimals: readonly ["Chuột", "Trâu", "Cọp", "Thỏ", "Rồng", "Rắn", "Ngựa", "Dê", "Khỉ", "Gà", "Chó", "Heo"];
88
+ readonly monthNames: readonly ["Giêng", "Hai", "Ba", "Tư", "Năm", "Sáu", "Bảy", "Tám", "Chín", "Mười", "Một", "Chạp"];
89
+ readonly lunarMonthNames: readonly ["Giêng", "Hai", "Ba", "Tư", "Năm", "Sáu", "Bảy", "Tám", "Chín", "Mười", "Một", "Chạp"];
90
+ readonly solarMonthNames: readonly ["Tháng 1", "Tháng 2", "Tháng 3", "Tháng 4", "Tháng 5", "Tháng 6", "Tháng 7", "Tháng 8", "Tháng 9", "Tháng 10", "Tháng 11", "Tháng 12"];
91
+ readonly weekDays: readonly ["CN", "T2", "T3", "T4", "T5", "T6", "T7"];
92
+ readonly leapLabel: "Nhuận";
93
+ readonly yearLabel: "Năm";
94
+ readonly monthLabel: "Tháng";
95
+ readonly destiny: "Mệnh";
96
+ } | {
97
+ readonly heavenlyStems: readonly ["Giáp", "Ất", "Bính", "Đinh", "Mậu", "Kỷ", "Canh", "Tân", "Nhâm", "Quý"];
98
+ readonly earthlyBranches: readonly ["Tý", "Sửu", "Dần", "Mão", "Thìn", "Tỵ", "Ngọ", "Mùi", "Thân", "Dậu", "Tuất", "Hợi"];
99
+ readonly fiveElements: readonly ["Metal", "Wood", "Water", "Fire", "Earth"];
100
+ readonly zodiacAnimals: readonly ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"];
101
+ readonly monthNames: readonly ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
102
+ readonly lunarMonthNames: readonly ["Month 1", "Month 2", "Month 3", "Month 4", "Month 5", "Month 6", "Month 7", "Month 8", "Month 9", "Month 10", "Month 11", "Month 12"];
103
+ readonly solarMonthNames: readonly ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
104
+ readonly weekDays: readonly ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
105
+ readonly leapLabel: "Leap";
106
+ readonly yearLabel: "Year";
107
+ readonly monthLabel: "Month";
108
+ readonly destiny: "Destiny";
109
+ } | {
110
+ readonly heavenlyStems: readonly ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"];
111
+ readonly earthlyBranches: readonly ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"];
112
+ readonly fiveElements: readonly ["金", "木", "水", "火", "土"];
113
+ readonly zodiacAnimals: readonly ["鼠", "牛", "虎", "兎", "竜", "蛇", "馬", "羊", "猿", "鶏", "犬", "猪"];
114
+ readonly monthNames: readonly ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"];
115
+ readonly lunarMonthNames: readonly ["旧暦1月", "旧暦2月", "旧暦3月", "旧暦4月", "旧暦5月", "旧暦6月", "旧暦7月", "旧暦8月", "旧暦9月", "旧暦10月", "旧暦11月", "旧暦12月"];
116
+ readonly solarMonthNames: readonly ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"];
117
+ readonly weekDays: readonly ["日", "月", "火", "水", "木", "金", "土"];
118
+ readonly leapLabel: "閏";
119
+ readonly yearLabel: "年";
120
+ readonly monthLabel: "月";
121
+ readonly destiny: "命";
122
+ } | {
123
+ readonly heavenlyStems: readonly ["갑", "을", "병", "정", "무", "기", "경", "신", "임", "계"];
124
+ readonly earthlyBranches: readonly ["자", "축", "인", "묘", "진", "사", "오", "미", "신", "유", "술", "해"];
125
+ readonly fiveElements: readonly ["금", "목", "수", "화", "토"];
126
+ readonly zodiacAnimals: readonly ["쥐", "소", "호랑이", "토끼", "용", "뱀", "말", "양", "원숭이", "닭", "개", "돼지"];
127
+ readonly monthNames: readonly ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"];
128
+ readonly lunarMonthNames: readonly ["음력 1월", "음력 2월", "음력 3월", "음력 4월", "음력 5월", "음력 6월", "음력 7월", "음력 8월", "음력 9월", "음력 10월", "음력 11월", "음력 12월"];
129
+ readonly solarMonthNames: readonly ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"];
130
+ readonly weekDays: readonly ["일", "월", "화", "수", "목", "금", "토"];
131
+ readonly leapLabel: "윤";
132
+ readonly yearLabel: "년";
133
+ readonly monthLabel: "월";
134
+ readonly destiny: "명";
135
+ };
136
+ /**
137
+ * Lấy tên con giáp theo locale
138
+ * @param branchIndex - Index Địa Chi (0-11)
139
+ * @param locale - Ngôn ngữ
140
+ */
141
+ declare function getZodiacAnimal(branchIndex: number, locale?: Locale): string;
142
+
143
+ /** Kết quả trả về của {@link getYearDetails}. */
144
+ interface YearDetails {
145
+ can: string;
146
+ chi: string;
82
147
  menh: string;
83
148
  fullString: string;
84
- };
149
+ }
150
+ /**
151
+ * Lấy ra chuỗi mô tả toàn bộ Can, Chi và Mệnh dựa vào số năm (Ví dụ: 2024)
152
+ * Theo quy ước: Năm 4 (sau CN) là năm Giáp Tý (Can index 0, Chi index 0)
153
+ *
154
+ * Công thức Can Chi là chu kỳ 60 năm lặp lại vô hạn nên nhận mọi số năm nguyên,
155
+ * kể cả năm 0 hoặc âm (trước Công Nguyên) — không giới hạn phạm vi như
156
+ * {@link LichTa.toLunar} (phạm vi đó là do thuật toán tìm Điểm Sóc, không áp
157
+ * dụng cho công thức Can Chi thuần).
158
+ *
159
+ * @param year - Năm (số nguyên bất kỳ, kể cả 0 hoặc âm)
160
+ *
161
+ * @example
162
+ * ```typescript
163
+ * getYearDetails(2024);
164
+ * // → { can: 'Giáp', chi: 'Thìn', menh: 'Thủy', fullString: 'Giáp Thìn - Mệnh Thủy' }
165
+ * ```
166
+ */
167
+ declare function getYearDetails(year: number): YearDetails;
85
168
  /**
86
169
  * Tính Can Chi ngày từ Julian Day Number.
87
170
  *
88
171
  * @param jd - Julian Day Number
172
+ * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi', giữ nguyên hành vi cũ)
89
173
  * @returns Chuỗi Can Chi (ví dụ: "Giáp Tý")
90
174
  */
91
- declare function getDayCanChi(jd: number): string;
175
+ declare function getDayCanChi(jd: number, locale?: Locale): string;
92
176
  /**
93
177
  * Tính Can Chi tháng từ tháng và năm âm lịch.
94
178
  * Can tháng phụ thuộc vào Can của năm (quy tắc Ngũ Hổ Độn):
@@ -100,8 +184,9 @@ declare function getDayCanChi(jd: number): string;
100
184
  *
101
185
  * @param lunarMonth - Tháng âm lịch (1-12)
102
186
  * @param lunarYear - Năm âm lịch
187
+ * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi', giữ nguyên hành vi cũ)
103
188
  */
104
- declare function getMonthCanChi(lunarMonth: number, lunarYear: number): string;
189
+ declare function getMonthCanChi(lunarMonth: number, lunarYear: number, locale?: Locale): string;
105
190
  /**
106
191
  * Tính Can Chi giờ từ giờ (0-23) và Julian Day Number của ngày.
107
192
  *
@@ -117,16 +202,30 @@ declare function getMonthCanChi(lunarMonth: number, lunarYear: number): string;
117
202
  *
118
203
  * @param hour - Giờ (0-23)
119
204
  * @param dayJd - Julian Day Number của ngày
205
+ * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi', giữ nguyên hành vi cũ)
120
206
  */
121
- declare function getHourCanChi(hour: number, dayJd: number): string;
207
+ declare function getHourCanChi(hour: number, dayJd: number, locale?: Locale): string;
122
208
  /**
123
209
  * Lấy danh sách 6 giờ Hoàng Đạo trong ngày.
124
210
  * Giờ Hoàng Đạo phụ thuộc vào Địa Chi của ngày.
125
211
  *
126
212
  * @param dayJd - Julian Day Number của ngày
213
+ * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi', giữ nguyên hành vi cũ)
127
214
  * @returns Mảng 6 chuỗi tên Địa Chi (ví dụ: ["Tý", "Sửu", "Mão", "Ngọ", "Mùi", "Dậu"])
128
215
  */
129
- declare function getAuspiciousHours(dayJd: number): string[];
216
+ declare function getAuspiciousHours(dayJd: number, locale?: Locale): string[];
217
+ /**
218
+ * Lấy index (0-11, theo thứ tự Địa Chi Tý→Hợi) của 6 giờ Hoàng Đạo trong ngày.
219
+ *
220
+ * Dùng khi cần một khoá ổn định, không phụ thuộc ngôn ngữ — ví dụ để map sang
221
+ * icon riêng, hoặc tự tra bảng dịch của bạn thay vì dùng chuỗi tên có sẵn từ
222
+ * {@link getAuspiciousHours}. Cả hai hàm dùng chung thứ tự dữ liệu nên
223
+ * `getAuspiciousHourIndices(jd)[i]` luôn tương ứng với `getAuspiciousHours(jd)[i]`.
224
+ *
225
+ * @param dayJd - Julian Day Number của ngày
226
+ * @returns Mảng 6 index Địa Chi (ví dụ: [0, 1, 3, 6, 7, 9])
227
+ */
228
+ declare function getAuspiciousHourIndices(dayJd: number): number[];
130
229
 
131
230
  /**
132
231
  * Lấy tên tháng âm lịch dạng chữ truyền thống.
@@ -170,13 +269,14 @@ declare function getDayName(day: number): string;
170
269
  * | `M` | Tháng | 1, 12 |
171
270
  * | `yyyy`| Năm 4 chữ số | 2024 |
172
271
  * | `yy` | Năm 2 chữ số cuối | 24 |
173
- * | `L` | "Nhuận" nếu tháng nhuận, "" nếu không | Nhuận |
272
+ * | `L` | Nhãn tháng nhuận theo `locale` (xem tham số `locale`), "" nếu không phải tháng nhuận | Nhuận |
174
273
  * | `CC` | Can Chi năm | Giáp Thìn |
175
274
  * | `DC` | Can Chi ngày | Giáp Tý |
176
275
  * | `MC` | Can Chi tháng | Bính Dần |
177
276
  *
178
277
  * @param lunar - Đối tượng LunarDate
179
278
  * @param pattern - Chuỗi pattern
279
+ * @param locale - Ngôn ngữ cho token `L` (mặc định: 'vi', giữ nguyên hành vi cũ — "Nhuận")
180
280
  *
181
281
  * @example
182
282
  * ```typescript
@@ -187,7 +287,7 @@ declare function getDayName(day: number): string;
187
287
  * // → "Ngày 1 tháng 1 năm Giáp Thìn"
188
288
  * ```
189
289
  */
190
- declare function formatLunarDate(lunar: LunarDate, pattern: string): string;
290
+ declare function formatLunarDate(lunar: LunarDate, pattern: string, locale?: Locale): string;
191
291
  /**
192
292
  * Format ngày âm lịch theo kiểu truyền thống Việt Nam.
193
293
  *
@@ -202,64 +302,26 @@ declare function formatLunarDate(lunar: LunarDate, pattern: string): string;
202
302
  */
203
303
  declare function formatTraditional(lunar: LunarDate): string;
204
304
 
305
+ /** Một ô ngày trong lưới lịch tháng. */
306
+ interface CalendarDayCell {
307
+ solar: Date;
308
+ lunar: LunarDate;
309
+ isToday: boolean;
310
+ isSelected: boolean;
311
+ isCurrentMonth: boolean;
312
+ }
205
313
  /**
206
- * Internationalization Hỗ trợ song ngữ Việt-Anh
207
- */
208
- type Locale = 'vi' | 'en' | 'ja' | 'ko';
209
- /**
210
- * Lấy bộ dịch theo locale
211
- * @param locale - Ngôn ngữ ('vi' | 'en' | 'ja' | 'ko')
212
- */
213
- declare function t(locale: Locale): {
214
- readonly heavenlyStems: readonly ["Giáp", "Ất", "Bính", "Đinh", "Mậu", "Kỷ", "Canh", "Tân", "Nhâm", "Quý"];
215
- readonly earthlyBranches: readonly ["Tý", "Sửu", "Dần", "Mão", "Thìn", "Tỵ", "Ngọ", "Mùi", "Thân", "Dậu", "Tuất", "Hợi"];
216
- readonly fiveElements: readonly ["Kim", "Mộc", "Thủy", "Hỏa", "Thổ"];
217
- readonly zodiacAnimals: readonly ["Chuột", "Trâu", "Cọp", "Thỏ", "Rồng", "Rắn", "Ngựa", "Dê", "Khỉ", "Gà", "Chó", "Heo"];
218
- readonly monthNames: readonly ["Giêng", "Hai", "Ba", "Tư", "Năm", "Sáu", "Bảy", "Tám", "Chín", "Mười", "Một", "Chạp"];
219
- readonly weekDays: readonly ["CN", "T2", "T3", "T4", "T5", "T6", "T7"];
220
- readonly leapLabel: "Nhuận";
221
- readonly yearLabel: "Năm";
222
- readonly monthLabel: "Tháng";
223
- readonly destiny: "Mệnh";
224
- } | {
225
- readonly heavenlyStems: readonly ["Giáp", "Ất", "Bính", "Đinh", "Mậu", "Kỷ", "Canh", "Tân", "Nhâm", "Quý"];
226
- readonly earthlyBranches: readonly ["Tý", "Sửu", "Dần", "Mão", "Thìn", "Tỵ", "Ngọ", "Mùi", "Thân", "Dậu", "Tuất", "Hợi"];
227
- readonly fiveElements: readonly ["Metal", "Wood", "Water", "Fire", "Earth"];
228
- readonly zodiacAnimals: readonly ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"];
229
- readonly monthNames: readonly ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
230
- readonly weekDays: readonly ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
231
- readonly leapLabel: "Leap";
232
- readonly yearLabel: "Year";
233
- readonly monthLabel: "Month";
234
- readonly destiny: "Destiny";
235
- } | {
236
- readonly heavenlyStems: readonly ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"];
237
- readonly earthlyBranches: readonly ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"];
238
- readonly fiveElements: readonly ["金", "木", "水", "火", "土"];
239
- readonly zodiacAnimals: readonly ["鼠", "牛", "虎", "兎", "竜", "蛇", "馬", "羊", "猿", "鶏", "犬", "猪"];
240
- readonly monthNames: readonly ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"];
241
- readonly weekDays: readonly ["日", "月", "火", "水", "木", "金", "土"];
242
- readonly leapLabel: "閏";
243
- readonly yearLabel: "年";
244
- readonly monthLabel: "月";
245
- readonly destiny: "命";
246
- } | {
247
- readonly heavenlyStems: readonly ["갑", "을", "병", "정", "무", "기", "경", "신", "임", "계"];
248
- readonly earthlyBranches: readonly ["자", "축", "인", "묘", "진", "사", "오", "미", "신", "유", "술", "해"];
249
- readonly fiveElements: readonly ["금", "목", "수", "화", "토"];
250
- readonly zodiacAnimals: readonly ["쥐", "소", "호랑이", "토끼", "용", "뱀", "말", "양", "원숭이", "닭", "개", "돼지"];
251
- readonly monthNames: readonly ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"];
252
- readonly weekDays: readonly ["일", "월", "화", "수", "목", "금", "토"];
253
- readonly leapLabel: "윤";
254
- readonly yearLabel: "년";
255
- readonly monthLabel: "월";
256
- readonly destiny: "명";
257
- };
258
- /**
259
- * Lấy tên con giáp theo locale
260
- * @param branchIndex - Index Địa Chi (0-11)
261
- * @param locale - Ngôn ngữ
314
+ * Dựng lưới 42 ô (6 tuần x 7 ngày) cho 1 tháng dương lịch, gồm ngày tràn từ
315
+ * tháng trước/sau để lấp đầy tuần đầu/cuối, mỗi ô kèm ngày âm tương ứng.
316
+ *
317
+ * Logic này trước đây bị lặp lại độc lập ở Calendar.tsx/vue/svelte — tách ra
318
+ * đây để 1 nguồn tính toán duy nhất (tránh 3 bản có thể lệch nhau khi sửa
319
+ * riêng lẻ), dùng chung cho cả Calendar DatePicker mọi framework.
320
+ *
321
+ * @param month - Tháng dương lịch (1-12)
322
+ * @param year - Năm dương lịch
323
+ * @param selectedDate - Ngày đang được chọn (nếu có), dùng để đánh dấu `isSelected`
262
324
  */
263
- declare function getZodiacAnimal(branchIndex: number, locale?: Locale): string;
325
+ declare function getCalendarGrid(month: number, year: number, selectedDate?: Date | null): CalendarDayCell[];
264
326
 
265
- export { LichTa, type Locale, type LunarDate, type SolarDate, formatLunarDate, formatTraditional, getAuspiciousHours, getDayCanChi, getDayName, getHourCanChi, getMonthCanChi, getMonthName, getYearDetails, getZodiacAnimal, jdFromDate, jdToDate, t };
327
+ export { type CalendarDayCell, LichTa, type Locale, type LunarDate, type SolarDate, type YearDetails, formatLunarDate, formatTraditional, getAuspiciousHourIndices, getAuspiciousHours, getCalendarGrid, getDayCanChi, getDayName, getHourCanChi, getMonthCanChi, getMonthName, getYearDetails, getZodiacAnimal, jdFromDate, jdToDate, t };
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ var __copyProps = (to, from, except, desc) => {
15
15
  }
16
16
  return to;
17
17
  };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2);
19
19
 
20
20
  // src/index.ts
21
21
  var index_exports = {};
@@ -23,7 +23,9 @@ __export(index_exports, {
23
23
  LichTa: () => LichTa,
24
24
  formatLunarDate: () => formatLunarDate,
25
25
  formatTraditional: () => formatTraditional,
26
+ getAuspiciousHourIndices: () => getAuspiciousHourIndices,
26
27
  getAuspiciousHours: () => getAuspiciousHours,
28
+ getCalendarGrid: () => getCalendarGrid,
27
29
  getDayCanChi: () => getDayCanChi,
28
30
  getDayName: () => getDayName,
29
31
  getHourCanChi: () => getHourCanChi,
@@ -321,10 +323,83 @@ var LichTa = class {
321
323
  // src/constants/five-elements.ts
322
324
  var FIVE_ELEMENTS = ["Kim", "M\u1ED9c", "Th\u1EE7y", "H\u1ECFa", "Th\u1ED5"];
323
325
 
326
+ // src/constants/i18n.ts
327
+ var translations = {
328
+ vi: {
329
+ heavenlyStems: ["Gi\xE1p", "\u1EA4t", "B\xEDnh", "\u0110inh", "M\u1EADu", "K\u1EF7", "Canh", "T\xE2n", "Nh\xE2m", "Qu\xFD"],
330
+ earthlyBranches: ["T\xFD", "S\u1EEDu", "D\u1EA7n", "M\xE3o", "Th\xECn", "T\u1EF5", "Ng\u1ECD", "M\xF9i", "Th\xE2n", "D\u1EADu", "Tu\u1EA5t", "H\u1EE3i"],
331
+ fiveElements: ["Kim", "M\u1ED9c", "Th\u1EE7y", "H\u1ECFa", "Th\u1ED5"],
332
+ zodiacAnimals: ["Chu\u1ED9t", "Tr\xE2u", "C\u1ECDp", "Th\u1ECF", "R\u1ED3ng", "R\u1EAFn", "Ng\u1EF1a", "D\xEA", "Kh\u1EC9", "G\xE0", "Ch\xF3", "Heo"],
333
+ // @deprecated Ngữ nghĩa không nhất quán giữa các locale (xem lunarMonthNames/solarMonthNames).
334
+ monthNames: ["Gi\xEAng", "Hai", "Ba", "T\u01B0", "N\u0103m", "S\xE1u", "B\u1EA3y", "T\xE1m", "Ch\xEDn", "M\u01B0\u1EDDi", "M\u1ED9t", "Ch\u1EA1p"],
335
+ lunarMonthNames: ["Gi\xEAng", "Hai", "Ba", "T\u01B0", "N\u0103m", "S\xE1u", "B\u1EA3y", "T\xE1m", "Ch\xEDn", "M\u01B0\u1EDDi", "M\u1ED9t", "Ch\u1EA1p"],
336
+ solarMonthNames: ["Th\xE1ng 1", "Th\xE1ng 2", "Th\xE1ng 3", "Th\xE1ng 4", "Th\xE1ng 5", "Th\xE1ng 6", "Th\xE1ng 7", "Th\xE1ng 8", "Th\xE1ng 9", "Th\xE1ng 10", "Th\xE1ng 11", "Th\xE1ng 12"],
337
+ weekDays: ["CN", "T2", "T3", "T4", "T5", "T6", "T7"],
338
+ leapLabel: "Nhu\u1EADn",
339
+ yearLabel: "N\u0103m",
340
+ monthLabel: "Th\xE1ng",
341
+ destiny: "M\u1EC7nh"
342
+ },
343
+ en: {
344
+ heavenlyStems: ["Gi\xE1p", "\u1EA4t", "B\xEDnh", "\u0110inh", "M\u1EADu", "K\u1EF7", "Canh", "T\xE2n", "Nh\xE2m", "Qu\xFD"],
345
+ earthlyBranches: ["T\xFD", "S\u1EEDu", "D\u1EA7n", "M\xE3o", "Th\xECn", "T\u1EF5", "Ng\u1ECD", "M\xF9i", "Th\xE2n", "D\u1EADu", "Tu\u1EA5t", "H\u1EE3i"],
346
+ fiveElements: ["Metal", "Wood", "Water", "Fire", "Earth"],
347
+ zodiacAnimals: ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"],
348
+ // @deprecated Ngữ nghĩa không nhất quán giữa các locale (xem lunarMonthNames/solarMonthNames).
349
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
350
+ lunarMonthNames: ["Month 1", "Month 2", "Month 3", "Month 4", "Month 5", "Month 6", "Month 7", "Month 8", "Month 9", "Month 10", "Month 11", "Month 12"],
351
+ solarMonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
352
+ weekDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
353
+ leapLabel: "Leap",
354
+ yearLabel: "Year",
355
+ monthLabel: "Month",
356
+ destiny: "Destiny"
357
+ },
358
+ ja: {
359
+ heavenlyStems: ["\u7532", "\u4E59", "\u4E19", "\u4E01", "\u620A", "\u5DF1", "\u5E9A", "\u8F9B", "\u58EC", "\u7678"],
360
+ earthlyBranches: ["\u5B50", "\u4E11", "\u5BC5", "\u536F", "\u8FB0", "\u5DF3", "\u5348", "\u672A", "\u7533", "\u9149", "\u620C", "\u4EA5"],
361
+ fiveElements: ["\u91D1", "\u6728", "\u6C34", "\u706B", "\u571F"],
362
+ zodiacAnimals: ["\u9F20", "\u725B", "\u864E", "\u514E", "\u7ADC", "\u86C7", "\u99AC", "\u7F8A", "\u733F", "\u9D8F", "\u72AC", "\u732A"],
363
+ // @deprecated Ngữ nghĩa không nhất quán giữa các locale (xem lunarMonthNames/solarMonthNames).
364
+ monthNames: ["1\u6708", "2\u6708", "3\u6708", "4\u6708", "5\u6708", "6\u6708", "7\u6708", "8\u6708", "9\u6708", "10\u6708", "11\u6708", "12\u6708"],
365
+ lunarMonthNames: ["\u65E7\u66A61\u6708", "\u65E7\u66A62\u6708", "\u65E7\u66A63\u6708", "\u65E7\u66A64\u6708", "\u65E7\u66A65\u6708", "\u65E7\u66A66\u6708", "\u65E7\u66A67\u6708", "\u65E7\u66A68\u6708", "\u65E7\u66A69\u6708", "\u65E7\u66A610\u6708", "\u65E7\u66A611\u6708", "\u65E7\u66A612\u6708"],
366
+ solarMonthNames: ["1\u6708", "2\u6708", "3\u6708", "4\u6708", "5\u6708", "6\u6708", "7\u6708", "8\u6708", "9\u6708", "10\u6708", "11\u6708", "12\u6708"],
367
+ weekDays: ["\u65E5", "\u6708", "\u706B", "\u6C34", "\u6728", "\u91D1", "\u571F"],
368
+ leapLabel: "\u958F",
369
+ yearLabel: "\u5E74",
370
+ monthLabel: "\u6708",
371
+ destiny: "\u547D"
372
+ },
373
+ ko: {
374
+ heavenlyStems: ["\uAC11", "\uC744", "\uBCD1", "\uC815", "\uBB34", "\uAE30", "\uACBD", "\uC2E0", "\uC784", "\uACC4"],
375
+ earthlyBranches: ["\uC790", "\uCD95", "\uC778", "\uBB18", "\uC9C4", "\uC0AC", "\uC624", "\uBBF8", "\uC2E0", "\uC720", "\uC220", "\uD574"],
376
+ fiveElements: ["\uAE08", "\uBAA9", "\uC218", "\uD654", "\uD1A0"],
377
+ zodiacAnimals: ["\uC950", "\uC18C", "\uD638\uB791\uC774", "\uD1A0\uB07C", "\uC6A9", "\uBC40", "\uB9D0", "\uC591", "\uC6D0\uC22D\uC774", "\uB2ED", "\uAC1C", "\uB3FC\uC9C0"],
378
+ // @deprecated Ngữ nghĩa không nhất quán giữa các locale (xem lunarMonthNames/solarMonthNames).
379
+ monthNames: ["1\uC6D4", "2\uC6D4", "3\uC6D4", "4\uC6D4", "5\uC6D4", "6\uC6D4", "7\uC6D4", "8\uC6D4", "9\uC6D4", "10\uC6D4", "11\uC6D4", "12\uC6D4"],
380
+ lunarMonthNames: ["\uC74C\uB825 1\uC6D4", "\uC74C\uB825 2\uC6D4", "\uC74C\uB825 3\uC6D4", "\uC74C\uB825 4\uC6D4", "\uC74C\uB825 5\uC6D4", "\uC74C\uB825 6\uC6D4", "\uC74C\uB825 7\uC6D4", "\uC74C\uB825 8\uC6D4", "\uC74C\uB825 9\uC6D4", "\uC74C\uB825 10\uC6D4", "\uC74C\uB825 11\uC6D4", "\uC74C\uB825 12\uC6D4"],
381
+ solarMonthNames: ["1\uC6D4", "2\uC6D4", "3\uC6D4", "4\uC6D4", "5\uC6D4", "6\uC6D4", "7\uC6D4", "8\uC6D4", "9\uC6D4", "10\uC6D4", "11\uC6D4", "12\uC6D4"],
382
+ weekDays: ["\uC77C", "\uC6D4", "\uD654", "\uC218", "\uBAA9", "\uAE08", "\uD1A0"],
383
+ leapLabel: "\uC724",
384
+ yearLabel: "\uB144",
385
+ monthLabel: "\uC6D4",
386
+ destiny: "\uBA85"
387
+ }
388
+ };
389
+ function t(locale) {
390
+ return translations[locale];
391
+ }
392
+ function getZodiacAnimal(branchIndex, locale = "vi") {
393
+ return translations[locale].zodiacAnimals[branchIndex % 12];
394
+ }
395
+
324
396
  // src/core/feng-shui.ts
397
+ function mod(n, m) {
398
+ return (n % m + m) % m;
399
+ }
325
400
  function getYearDetails(year) {
326
- const stemIndex = (year - 4) % 10;
327
- const branchIndex = (year - 4) % 12;
401
+ const stemIndex = mod(year - 4, 10);
402
+ const branchIndex = mod(year - 4, 12);
328
403
  const stemWeight = getStemWeight(stemIndex);
329
404
  const branchWeight = getBranchWeight(branchIndex);
330
405
  let elementValue = stemWeight + branchWeight;
@@ -339,24 +414,27 @@ function getYearDetails(year) {
339
414
  fullString: `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]} - M\u1EC7nh ${FIVE_ELEMENTS[elementIndex]}`
340
415
  };
341
416
  }
342
- function getDayCanChi(jd) {
417
+ function getDayCanChi(jd, locale = "vi") {
343
418
  const stemIndex = (jd + 9) % 10;
344
419
  const branchIndex = (jd + 1) % 12;
345
- return `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]}`;
420
+ const { heavenlyStems, earthlyBranches } = t(locale);
421
+ return `${heavenlyStems[stemIndex]} ${earthlyBranches[branchIndex]}`;
346
422
  }
347
- function getMonthCanChi(lunarMonth, lunarYear) {
423
+ function getMonthCanChi(lunarMonth, lunarYear, locale = "vi") {
348
424
  const yearStemIndex = (lunarYear + 6) % 10;
349
425
  const monthStemOffset = yearStemIndex % 5 * 2 + 2;
350
426
  const monthStemIndex = (monthStemOffset + lunarMonth - 1) % 10;
351
427
  const monthBranchIndex = (lunarMonth + 1) % 12;
352
- return `${HEAVENLY_STEMS[monthStemIndex]} ${EARTHLY_BRANCHES[monthBranchIndex]}`;
428
+ const { heavenlyStems, earthlyBranches } = t(locale);
429
+ return `${heavenlyStems[monthStemIndex]} ${earthlyBranches[monthBranchIndex]}`;
353
430
  }
354
- function getHourCanChi(hour, dayJd) {
431
+ function getHourCanChi(hour, dayJd, locale = "vi") {
355
432
  const hourBranchIndex = Math.floor((hour + 1) / 2) % 12;
356
433
  const dayStemIndex = (dayJd + 9) % 10;
357
434
  const hourStemOffset = dayStemIndex % 5 * 2;
358
435
  const hourStemIndex = (hourStemOffset + hourBranchIndex) % 10;
359
- return `${HEAVENLY_STEMS[hourStemIndex]} ${EARTHLY_BRANCHES[hourBranchIndex]}`;
436
+ const { heavenlyStems, earthlyBranches } = t(locale);
437
+ return `${heavenlyStems[hourStemIndex]} ${earthlyBranches[hourBranchIndex]}`;
360
438
  }
361
439
  var AUSPICIOUS_HOURS_TABLE = [
362
440
  [0, 1, 3, 6, 7, 9],
@@ -372,11 +450,17 @@ var AUSPICIOUS_HOURS_TABLE = [
372
450
  [2, 5, 6, 8, 11, 0]
373
451
  // Ngày Tỵ (5) / Hợi (11)
374
452
  ];
375
- function getAuspiciousHours(dayJd) {
453
+ function getAuspiciousHours(dayJd, locale = "vi") {
376
454
  const branchIndex = (dayJd + 1) % 12;
377
455
  const groupIndex = branchIndex % 6;
378
456
  const hourIndices = AUSPICIOUS_HOURS_TABLE[groupIndex];
379
- return hourIndices.map((i) => EARTHLY_BRANCHES[i]);
457
+ const { earthlyBranches } = t(locale);
458
+ return hourIndices.map((i) => earthlyBranches[i]);
459
+ }
460
+ function getAuspiciousHourIndices(dayJd) {
461
+ const branchIndex = (dayJd + 1) % 12;
462
+ const groupIndex = branchIndex % 6;
463
+ return [...AUSPICIOUS_HOURS_TABLE[groupIndex]];
380
464
  }
381
465
 
382
466
  // src/utils/format.ts
@@ -435,7 +519,7 @@ function getDayName(day) {
435
519
  }
436
520
  return "Ba M\u01B0\u01A1i";
437
521
  }
438
- function formatLunarDate(lunar, pattern) {
522
+ function formatLunarDate(lunar, pattern, locale = "vi") {
439
523
  let result = pattern;
440
524
  result = result.replace(/yyyy/g, String(lunar.year));
441
525
  result = result.replace(/yy/g, String(lunar.year).slice(-2));
@@ -444,7 +528,7 @@ function formatLunarDate(lunar, pattern) {
444
528
  result = result.replace(/CC/g, lunar.yearCanChi ?? "");
445
529
  result = result.replace(/DC/g, lunar.dayCanChi ?? "");
446
530
  result = result.replace(/MC/g, lunar.monthCanChi ?? "");
447
- result = result.replace(/L/g, lunar.isLeap ? "Nhu\u1EADn" : "");
531
+ result = result.replace(/L/g, lunar.isLeap ? t(locale).leapLabel : "");
448
532
  result = result.replace(/(?<![0-9])d(?![0-9d])/g, String(lunar.day));
449
533
  result = result.replace(/(?<![0-9])M(?![0-9MC])/g, String(lunar.month));
450
534
  return result.trim();
@@ -457,69 +541,53 @@ function formatTraditional(lunar) {
457
541
  return `${dayName} th\xE1ng ${monthName}${leapSuffix} n\u0103m ${yearCanChi}`.trim();
458
542
  }
459
543
 
460
- // src/constants/i18n.ts
461
- var translations = {
462
- vi: {
463
- heavenlyStems: ["Gi\xE1p", "\u1EA4t", "B\xEDnh", "\u0110inh", "M\u1EADu", "K\u1EF7", "Canh", "T\xE2n", "Nh\xE2m", "Qu\xFD"],
464
- earthlyBranches: ["T\xFD", "S\u1EEDu", "D\u1EA7n", "M\xE3o", "Th\xECn", "T\u1EF5", "Ng\u1ECD", "M\xF9i", "Th\xE2n", "D\u1EADu", "Tu\u1EA5t", "H\u1EE3i"],
465
- fiveElements: ["Kim", "M\u1ED9c", "Th\u1EE7y", "H\u1ECFa", "Th\u1ED5"],
466
- zodiacAnimals: ["Chu\u1ED9t", "Tr\xE2u", "C\u1ECDp", "Th\u1ECF", "R\u1ED3ng", "R\u1EAFn", "Ng\u1EF1a", "D\xEA", "Kh\u1EC9", "G\xE0", "Ch\xF3", "Heo"],
467
- monthNames: ["Gi\xEAng", "Hai", "Ba", "T\u01B0", "N\u0103m", "S\xE1u", "B\u1EA3y", "T\xE1m", "Ch\xEDn", "M\u01B0\u1EDDi", "M\u1ED9t", "Ch\u1EA1p"],
468
- weekDays: ["CN", "T2", "T3", "T4", "T5", "T6", "T7"],
469
- leapLabel: "Nhu\u1EADn",
470
- yearLabel: "N\u0103m",
471
- monthLabel: "Th\xE1ng",
472
- destiny: "M\u1EC7nh"
473
- },
474
- en: {
475
- heavenlyStems: ["Gi\xE1p", "\u1EA4t", "B\xEDnh", "\u0110inh", "M\u1EADu", "K\u1EF7", "Canh", "T\xE2n", "Nh\xE2m", "Qu\xFD"],
476
- earthlyBranches: ["T\xFD", "S\u1EEDu", "D\u1EA7n", "M\xE3o", "Th\xECn", "T\u1EF5", "Ng\u1ECD", "M\xF9i", "Th\xE2n", "D\u1EADu", "Tu\u1EA5t", "H\u1EE3i"],
477
- fiveElements: ["Metal", "Wood", "Water", "Fire", "Earth"],
478
- zodiacAnimals: ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"],
479
- monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
480
- weekDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
481
- leapLabel: "Leap",
482
- yearLabel: "Year",
483
- monthLabel: "Month",
484
- destiny: "Destiny"
485
- },
486
- ja: {
487
- heavenlyStems: ["\u7532", "\u4E59", "\u4E19", "\u4E01", "\u620A", "\u5DF1", "\u5E9A", "\u8F9B", "\u58EC", "\u7678"],
488
- earthlyBranches: ["\u5B50", "\u4E11", "\u5BC5", "\u536F", "\u8FB0", "\u5DF3", "\u5348", "\u672A", "\u7533", "\u9149", "\u620C", "\u4EA5"],
489
- fiveElements: ["\u91D1", "\u6728", "\u6C34", "\u706B", "\u571F"],
490
- zodiacAnimals: ["\u9F20", "\u725B", "\u864E", "\u514E", "\u7ADC", "\u86C7", "\u99AC", "\u7F8A", "\u733F", "\u9D8F", "\u72AC", "\u732A"],
491
- monthNames: ["1\u6708", "2\u6708", "3\u6708", "4\u6708", "5\u6708", "6\u6708", "7\u6708", "8\u6708", "9\u6708", "10\u6708", "11\u6708", "12\u6708"],
492
- weekDays: ["\u65E5", "\u6708", "\u706B", "\u6C34", "\u6728", "\u91D1", "\u571F"],
493
- leapLabel: "\u958F",
494
- yearLabel: "\u5E74",
495
- monthLabel: "\u6708",
496
- destiny: "\u547D"
497
- },
498
- ko: {
499
- heavenlyStems: ["\uAC11", "\uC744", "\uBCD1", "\uC815", "\uBB34", "\uAE30", "\uACBD", "\uC2E0", "\uC784", "\uACC4"],
500
- earthlyBranches: ["\uC790", "\uCD95", "\uC778", "\uBB18", "\uC9C4", "\uC0AC", "\uC624", "\uBBF8", "\uC2E0", "\uC720", "\uC220", "\uD574"],
501
- fiveElements: ["\uAE08", "\uBAA9", "\uC218", "\uD654", "\uD1A0"],
502
- zodiacAnimals: ["\uC950", "\uC18C", "\uD638\uB791\uC774", "\uD1A0\uB07C", "\uC6A9", "\uBC40", "\uB9D0", "\uC591", "\uC6D0\uC22D\uC774", "\uB2ED", "\uAC1C", "\uB3FC\uC9C0"],
503
- monthNames: ["1\uC6D4", "2\uC6D4", "3\uC6D4", "4\uC6D4", "5\uC6D4", "6\uC6D4", "7\uC6D4", "8\uC6D4", "9\uC6D4", "10\uC6D4", "11\uC6D4", "12\uC6D4"],
504
- weekDays: ["\uC77C", "\uC6D4", "\uD654", "\uC218", "\uBAA9", "\uAE08", "\uD1A0"],
505
- leapLabel: "\uC724",
506
- yearLabel: "\uB144",
507
- monthLabel: "\uC6D4",
508
- destiny: "\uBA85"
509
- }
510
- };
511
- function t(locale) {
512
- return translations[locale];
544
+ // src/utils/calendar-grid.ts
545
+ function dateKey(date) {
546
+ return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
513
547
  }
514
- function getZodiacAnimal(branchIndex, locale = "vi") {
515
- return translations[locale].zodiacAnimals[branchIndex % 12];
548
+ function getCalendarGrid(month, year, selectedDate) {
549
+ const grid = [];
550
+ const firstDay = new Date(year, month - 1, 1);
551
+ const lastDay = new Date(year, month, 0);
552
+ const startingDayOfWeek = firstDay.getDay();
553
+ const daysInMonth = lastDay.getDate();
554
+ const todayKey = dateKey(/* @__PURE__ */ new Date());
555
+ const selectedKey = selectedDate ? dateKey(selectedDate) : "";
556
+ const prevMonthLastDay = new Date(year, month - 1, 0).getDate();
557
+ const pushCell = (solar, d, m, y, isCurrentMonth) => {
558
+ grid.push({
559
+ solar,
560
+ lunar: LichTa.toLunar(d, m, y),
561
+ isToday: dateKey(solar) === todayKey,
562
+ isSelected: dateKey(solar) === selectedKey,
563
+ isCurrentMonth
564
+ });
565
+ };
566
+ for (let i = startingDayOfWeek - 1; i >= 0; i--) {
567
+ const d = prevMonthLastDay - i;
568
+ const m = month - 1 < 1 ? 12 : month - 1;
569
+ const y = month - 1 < 1 ? year - 1 : year;
570
+ pushCell(new Date(y, m - 1, d), d, m, y, false);
571
+ }
572
+ for (let d = 1; d <= daysInMonth; d++) {
573
+ pushCell(new Date(year, month - 1, d), d, month, year, true);
574
+ }
575
+ const remaining = 42 - grid.length;
576
+ for (let d = 1; d <= remaining; d++) {
577
+ const m = month + 1 > 12 ? 1 : month + 1;
578
+ const y = month + 1 > 12 ? year + 1 : year;
579
+ pushCell(new Date(y, m - 1, d), d, m, y, false);
580
+ }
581
+ return grid;
516
582
  }
517
583
  // Annotate the CommonJS export names for ESM import in node:
518
584
  0 && (module.exports = {
519
585
  LichTa,
520
586
  formatLunarDate,
521
587
  formatTraditional,
588
+ getAuspiciousHourIndices,
522
589
  getAuspiciousHours,
590
+ getCalendarGrid,
523
591
  getDayCanChi,
524
592
  getDayName,
525
593
  getHourCanChi,