From 780b374a4406e8bb23ba236b45d52c2d50bb2b9b Mon Sep 17 00:00:00 2001 From: sight <26325820+Sight-wcg@users.noreply.github.com> Date: Fri, 11 Jul 2025 13:31:51 +0800 Subject: [PATCH] =?UTF-8?q?wip(i18n):=20=E6=94=B9=E8=BF=9B=20laydate=20?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF=E4=B8=AD=E7=9A=84=E6=97=A5=E6=9C=9F=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/i18n/detail/options.md | 5 ++- examples/i18n/en.js | 3 ++ examples/i18n/fr.js | 3 ++ examples/i18n/zh-HK.js | 5 ++- src/modules/i18n.js | 15 +++++-- src/modules/laydate.js | 82 ++++++++++++++++++++++++++++++++----- 6 files changed, 97 insertions(+), 16 deletions(-) diff --git a/docs/i18n/detail/options.md b/docs/i18n/detail/options.md index 6ab90648..caf61f9b 100644 --- a/docs/i18n/detail/options.md +++ b/docs/i18n/detail/options.md @@ -41,9 +41,12 @@ i18n.set({ verifyErrorPromptTitle: '提示' }, laydate: { - months: ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'], + months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], weeks: ['日', '一', '二', '三', '四', '五', '六'], time: ['时', '分', '秒'], + literal: { + year: '年' + }, selectDate: '选择日期', selectTime: '选择时间', startTime: '开始时间', diff --git a/examples/i18n/en.js b/examples/i18n/en.js index ae6b1f7d..156171fa 100644 --- a/examples/i18n/en.js +++ b/examples/i18n/en.js @@ -44,6 +44,9 @@ export default { months: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], weeks: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], time: ['Hour', 'Minute', 'Second'], + literal: { + year: '' + }, selectDate: 'Select Date', selectTime: 'Select Time', startTime: 'Start Time', diff --git a/examples/i18n/fr.js b/examples/i18n/fr.js index 536a022b..c39fabce 100644 --- a/examples/i18n/fr.js +++ b/examples/i18n/fr.js @@ -43,6 +43,9 @@ export default { months: ['Janv', 'Févr', 'Mars', 'Avr', 'Mai', 'Juin', 'Juil', 'Août', 'Sept', 'Oct', 'Nov', 'Déc'], weeks: ['Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa'], time: ['Heure', 'Minute', 'Seconde'], + literal: { + year: '' + }, selectDate: 'Sélec. date', selectTime: 'Sélec. heure', startTime: 'Heure de début', diff --git a/examples/i18n/zh-HK.js b/examples/i18n/zh-HK.js index 9d500b5c..4ff1fcf5 100644 --- a/examples/i18n/zh-HK.js +++ b/examples/i18n/zh-HK.js @@ -40,9 +40,12 @@ export default { verifyErrorPromptTitle: '提示' }, laydate: { - months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], + months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], weeks: ['日', '一', '二', '三', '四', '五', '六'], time: ['時', '分', '秒'], + literal: { + year: '年' + }, selectDate: '選擇日期', selectTime: '選擇時間', startTime: '開始時間', diff --git a/src/modules/i18n.js b/src/modules/i18n.js index 1714152a..191e4ce5 100644 --- a/src/modules/i18n.js +++ b/src/modules/i18n.js @@ -53,9 +53,12 @@ layui.define('lay', function(exports) { verifyErrorPromptTitle: '提示' }, laydate: { - months: ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'], + months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], weeks: ['日', '一', '二', '三', '四', '五', '六'], time: ['时', '分', '秒'], + literal: { + year: '年' + }, selectDate: '选择日期', selectTime: '选择时间', startTime: '开始时间', @@ -263,6 +266,10 @@ layui.define('lay', function(exports) { return value } + function isDef(value) { + return value !== null && value !== undefined; + } + var resolveValue = memoize(function(path, obj, defaultValue){ var pathParts = path.split(':'); var locale = pathParts[0]; @@ -273,7 +280,7 @@ layui.define('lay', function(exports) { if (layui.cache.debug) { var isFallback = defaultValue === value || value === path; - var isNotFound = !value || isFallback; + var isNotFound = !isDef(value) || isFallback; if (isNotFound) { hint.errorOnce("Not found '" + path + "' key in '" + locale + "' locale messages.", 'warn'); } @@ -282,7 +289,7 @@ layui.define('lay', function(exports) { } } - return value || path; + return isDef(value) ? value : path; }); var i18n = { @@ -321,7 +328,7 @@ layui.define('lay', function(exports) { var locale = (options && options.locale) || config.locale; var i18nMessages = config.messages[locale]; var namespace = locale + ':'; - var fallbackMessage = options && options.default; + var fallbackMessage = (options && lay.hasOwn(options, 'default')) ? options.default : undefined; if (!i18nMessages) { hint.errorOnce("Locale '" + locale + "' not found. Please add i18n messages for this locale first.", 'error'); diff --git a/src/modules/laydate.js b/src/modules/laydate.js index dc123b2a..0a3f51df 100644 --- a/src/modules/laydate.js +++ b/src/modules/laydate.js @@ -13,6 +13,39 @@ layui.define(['lay', 'i18n'], function(exports) { var MOD_NAME = 'laydate'; var MOD_ID = 'lay-' + MOD_NAME + '-id'; // 已渲染过的索引标记名 var zhCN = 'zh-CN'; // 简体中文语言码 + var YearBeforeMonthLocale = ['eu-ES', 'ja-JP', 'km-KH', 'ko-KR', 'pt-BR', 'si-LK', 'ms-MY', 'ug-CN', 'zh-CN', 'zh-HK', 'zh-TW']; // 年份在前的语言 + + function addSpaceBetweenChars(str) { + if (typeof str !== 'string' || str.length <= 1) { + return str; + } + + let result = ''; + for (let i = 0; i < str.length - 1; i++) { + var char = str[i]; + var nextChar = str[i + 1]; + result += char; + + // 判断当前字符和下一个字符的类型 + var isCharDigit = isDigit(char); + var isNextCharDigit = isDigit(nextChar); + + // 在数字和非数字(非空格)之间添加空格 + if ( + (isCharDigit && !isNextCharDigit && nextChar !== ' ') || // 数字 → 非数字(非空格) + (char !== ' ' && !isCharDigit && isNextCharDigit) // 非空格非数字 → 数字 + ) { + result += ' '; + } + } + result += str[str.length - 1]; // 添加最后一个字符 + return result; + } + + function isDigit(char) { + var code = char.charCodeAt(0); + return code >= 48 && code <= 57; // '0' 到 '9' 的 ASCII 码范围 + } // 外部调用 var laydate = { @@ -114,6 +147,24 @@ layui.define(['lay', 'i18n'], function(exports) { // 更新 i18n 消息对象 that.i18nMessages = that.getI18nMessages(); + // 处理日期面板顶部年月顺序 + // 这是一个变通的方法,因为 i18nMessages.monthBeforeYear 不存在 + if(typeof that.i18nMessages.monthBeforeYear !== 'boolean'){ + if(!window.Intl){ + that.i18nMessages.monthBeforeYear = !(YearBeforeMonthLocale.indexOf(options.lang) > -1); + }else{ + var formatter = new Intl.DateTimeFormat(options.lang, { year: 'numeric', month: 'short' }); + var parts = formatter.formatToParts(new Date(1970, 0)); + var order = []; + parts.map(function(part) { + if (part.type === 'year' || part.type === 'month') { + order.push(part.type); + } + }) + that.i18nMessages.monthBeforeYear = order[0] === 'month'; + } + } + // 若重复执行 render,则视为 reload 处理 if(elem[0] && elem.attr(MOD_ID)){ var newThat = thisModule.getThis(elem.attr(MOD_ID)); @@ -206,6 +257,15 @@ layui.define(['lay', 'i18n'], function(exports) { locale: locale, default: ['Hour', 'Minute', 'Second'] }), + literal: { + year: i18n.$t('laydate.literal.year', null, { + locale: locale, + default: '' + }) + }, + monthBeforeYear: i18n.$t('laydate.monthBeforeYear', null, { + locale: locale + }), selectDate: i18n.$t('laydate.selectDate', null, { locale: locale, default: 'Select Date' @@ -1539,12 +1599,14 @@ layui.define(['lay', 'i18n'], function(exports) { if(!that.panelYM) that.panelYM = {}; that.panelYM[index] = {year: dateTime.year, month: dateTime.month}; - if(options.lang === zhCN){ - lay(elemYM[0]).attr('lay-type', 'year').html(dateTime.year + ' 年') - lay(elemYM[1]).attr('lay-type', 'month').html((dateTime.month + 1) + ' 月'); + var normalizedYearStr = addSpaceBetweenChars(dateTime.year + lang.literal.year); + var normalizedMonthStr = addSpaceBetweenChars(lang.months[dateTime.month]); + if(!lang.monthBeforeYear){ + lay(elemYM[0]).attr('lay-type', 'year').html(normalizedYearStr); + lay(elemYM[1]).attr('lay-type', 'month').html(normalizedMonthStr); } else { - lay(elemYM[0]).attr('lay-type', 'month').html(lang.months[dateTime.month]); - lay(elemYM[1]).attr('lay-type', 'year').html(dateTime.year); + lay(elemYM[0]).attr('lay-type', 'month').html(normalizedMonthStr); + lay(elemYM[1]).attr('lay-type', 'year').html(normalizedYearStr); } //初始默认选择器 @@ -1636,8 +1698,8 @@ layui.define(['lay', 'i18n'], function(exports) { ,elemYM = lay(elemHeader[2]).find('span') ,elemCont = that.elemCont[index || 0] ,haveList = lay(elemCont).find('.'+ ELEM_LIST)[0] - ,isCN = options.lang === zhCN - ,text = isCN ? '年' : '' + ,isMonthBeforeYear = lang.monthBeforeYear + ,text = lang.literal.year ,listYM = that.listYM[index] || {} ,hms = ['hours', 'minutes', 'seconds'] @@ -1685,7 +1747,7 @@ layui.define(['lay', 'i18n'], function(exports) { yearNum++; }); - lay(elemYM[isCN ? 0 : 1]).attr('lay-ym', (yearNum - 8) + '-' + listYM[1]) + lay(elemYM[!isMonthBeforeYear ? 0 : 1]).attr('lay-ym', (yearNum - 8) + '-' + listYM[1]) .html((startY + text) + ' - ' + (yearNum - 1 + text)); } @@ -1702,7 +1764,7 @@ layui.define(['lay', 'i18n'], function(exports) { }; i + 1 == listYM[1] && lay(li).addClass(THIS); - li.innerHTML = lang.months[i] + (isCN ? '月' : ''); + li.innerHTML = lang.months[i]; ul.appendChild(li); /* @@ -1724,7 +1786,7 @@ layui.define(['lay', 'i18n'], function(exports) { that.cellRender(li, {year: listYM[0], month: i + 1, date: 1}, 'month'); }); - lay(elemYM[isCN ? 0 : 1]).attr('lay-ym', listYM[0] + '-' + listYM[1]) + lay(elemYM[!isMonthBeforeYear ? 0 : 1]).attr('lay-ym', listYM[0] + '-' + listYM[1]) .html(listYM[0] + text); }