mirror of
https://github.com/layui/layui.git
synced 2026-02-09 02:09:18 +08:00
feat(i18n): 国际化支持 (#2698)
* wip(i18n): laydate 国际化 * wip(i18n): colorpicker 国际化 * wip(i18n): laypage 国际化 * fix * update code * wip(i18n): 修改国际化消息对象结构 * wip(i18n): update * wip(i18n): code 国际化 * wip(i18n): dropdown 国际化 * wip(i18n): flow 国际化 * wip(i18n): form 国际化 * wip(i18n): layer 国际化 * wip(i18n): table 国际化 * wip(i18n): transfer 国际化 * wip(i18n): tree 国际化 * wip(i18n): treeTable 控制台提示统一为英文 * wip(i18n): upload 国际化 * wip(i18n): util 国际化 * wip(i18n): update code * wip(i18n): update code * wip(i18n): fix * wip(i18n): 优化 $t 代码细节 * wip(i18n): 修复 laydate lang * wip(i18n): 改进 upload i18n key * wip(i18n): 修复打包后 laydate 和 layer 异常 * wip(i18n): 移除国际化消息中的 `lay` 命名空间 * refactor(i18n): 改进国际化支持 * wip(i18n): 修复 table text.none 切换 locale 无效问题 * style(laydate): 优化逗号格式 * chore(laydate): 优化部分提示 * chore(i18n): 优化演示中部分国际化消息 * refactor: 剔除 laydate 单独版的判断逻辑 为接下来全面支持国际化做铺垫 * wip(i18n): 为 laydate 重新添加完整国际化的支持 * i18n(laydate): 优化 lang() 方法中的逻辑 * chore(util): 删除未使用的代码 * chore(i18n): 优化注释 * docs(i18n): 新增国际化文档(beta) note: 由于时间关系,本次提交仅为初版,该文档尚未完成 * wip(docs): 完善 i18n 文档 * fix(i18n): 修复 laypage 变量定义前使用 * wip(i18n): 转义翻译结果 * fix(i18n): 修复 table 排序 key 无效 * wip(i18n): 优化获取对象中指定路径值的性能 * wip(i18n): 删除 $t 可变长参数重载 * chore(i18n): 删除不必要的注释 * refactor(i18n): laydate 国际化方案迁移至 i18n.$t (#2745) * wip(i18n): 改进 laydate i18nMsg key * update code * wip(i18n): 改进 laydate 面板中的日期格式处理 * wip(i18n): 改进 util.toDateString meridiem 遵循 CLDR day periods 标准 * update code * wip(docs): 优化 i18n 文档示例 * docs(i18n): 优化正式文档 * docs(i18n): 优化部分文案 * docs(i18n): 优化示例 --------- Co-authored-by: 贤心 <3277200+sentsim@users.noreply.github.com>
This commit is contained in:
786
docs/i18n/detail/demo.md
Normal file
786
docs/i18n/detail/demo.md
Normal file
@@ -0,0 +1,786 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>i18n 演示 - Layui</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="{{= d.layui[2].cdn.css }}" rel="stylesheet">
|
||||
</head>
|
||||
<body class="layui-padding-3">
|
||||
<div id="root"></div>{{!
|
||||
<template id="template">
|
||||
{{ const i18n = layui.i18n; }}
|
||||
<div class="layui-form">
|
||||
<div class="layui-inline">
|
||||
<strong>{{= i18n.$t('custom.switchLanguage') }}: </strong>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<select id="change-locale" lay-filter="change-locale">
|
||||
<option value="zh-CN">简体中文</option>
|
||||
<option value="en">English</option>
|
||||
<option value="zh-HK">繁體中文</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>README</legend>
|
||||
<div class="layui-field-box layui-text" id="tpl-test">
|
||||
<p>{{= i18n.$t('custom.readme.description') }}</p>
|
||||
<ul>
|
||||
<li><strong>locale</strong>: <span style="color:red">{{= i18n.config.locale }}</span></li>
|
||||
<li><strong>Date</strong>: {{= new Date().toLocaleDateString(i18n.config.locale) }}</li>
|
||||
<li><strong>Hello</strong>: {{= i18n.$t('custom.readme.hello') }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>code</legend>
|
||||
<div class="layui-field-box">
|
||||
<pre id="demo-code" class="layui-code" lay-options="{}">
|
||||
code content
|
||||
</pre>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>colorpicker</legend>
|
||||
<div class="layui-field-box">
|
||||
<div id="demo-colorpicker"></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>dropdown</legend>
|
||||
<div class="layui-field-box">
|
||||
<button id="demo-dropdown" class="layui-btn demo-dropdown-base">
|
||||
<span>Dropdown</span>
|
||||
<i class="layui-icon layui-icon-down layui-font-12"></i>
|
||||
</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>flow</legend>
|
||||
<div class="layui-field-box">
|
||||
<div class="flow-demo" id="demo-flow"></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>form</legend>
|
||||
<div class="layui-field-box">
|
||||
<form class="layui-form" action="">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">{{= i18n.$t('custom.form.required') }}</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="username" lay-verify="required" lay-vertype="alert" placeholder="{{= i18n.$t('custom.form.placeholder') }}" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">{{= i18n.$t('custom.form.phone') }}</label>
|
||||
<div class="layui-input-inline layui-input-wrap">
|
||||
<input type="tel" name="phone" lay-verify="phone" autocomplete="off" value="123456" lay-affix="clear"
|
||||
class="layui-input demo-phone">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">{{= i18n.$t('custom.form.email') }}</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="email" value="123.com" lay-verify="email" autocomplete="off"
|
||||
class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">{{= i18n.$t('custom.form.date') }}</label>
|
||||
<div class="layui-input-inline layui-input-wrap">
|
||||
<div class="layui-input-prefix">
|
||||
<i class="layui-icon layui-icon-date"></i>
|
||||
</div>
|
||||
<input type="text" name="date" value="2077" id="date" lay-verify="date" placeholder="yyyy-MM-dd"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">{{= i18n.$t('custom.form.select') }}</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="interest" lay-filter="aihao" lay-search>
|
||||
<option value=""></option>
|
||||
<option value="0">AAA</option>
|
||||
<option value="1" selected>BBB</option>
|
||||
<option value="2">CCC</option>
|
||||
<option value="3">DDD</option>
|
||||
<option value="4">EEE</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button type="submit" class="layui-btn" lay-submit lay-filter="demo1">
|
||||
{{= i18n.$t('custom.form.submit') }}
|
||||
</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">
|
||||
{{= i18n.$t('custom.form.reset') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>laydate</legend>
|
||||
<div class="layui-field-box">
|
||||
<div class="layui-inline">
|
||||
<input class="layui-input" id="demo-laydate" />
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>layer</legend>
|
||||
<div class="layui-field-box">
|
||||
<button type="button" class="layui-btn layui-btn-primary" lay-on="alert">Alert</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" lay-on="prompt">Prompt</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" lay-on="photos">Photos</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>laypage</legend>
|
||||
<div class="layui-field-box">
|
||||
<div id="demo-laypage-all"></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>table</legend>
|
||||
<div class="layui-field-box">
|
||||
<table class="layui-hide" id="demo-table" lay-filter="test"></table>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>transfer</legend>
|
||||
<div class="layui-field-box">
|
||||
<div id="demo-transfer"></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>tree</legend>
|
||||
<div class="layui-field-box">
|
||||
<div id="demo-tree"></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>upload</legend>
|
||||
<div class="layui-field-box">
|
||||
<button type="button" class="layui-btn" id="demo-upload">
|
||||
<i class="layui-icon layui-icon-upload"></i> Upload
|
||||
</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>utils</legend>
|
||||
<div class="layui-field-box">
|
||||
<label>
|
||||
timeAgo: <input id="demo-time-ago-picker" type="datetime-local" /> <span id="demo-time-ago-display"></span>
|
||||
</label>
|
||||
<br>
|
||||
<label>
|
||||
toDateString: <div id="demo-toDateString"></div>
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
</template>!}}
|
||||
|
||||
<script>
|
||||
// 配置 Layui 组件语言包
|
||||
window.LAYUI_GLOBAL = {
|
||||
i18n: {
|
||||
locale: localStorage.getItem('layui-i18n-local-test') || 'zh-CN', // 当前语言环境
|
||||
messages: { // 扩展其他语言包
|
||||
// English
|
||||
'en': {
|
||||
code: {
|
||||
copy: 'Copy Code',
|
||||
copied: 'Copied',
|
||||
copyError: 'Copy Failed',
|
||||
maximize: 'Maximize',
|
||||
restore: 'Restore',
|
||||
preview: 'Open Preview in New Window'
|
||||
},
|
||||
colorpicker: {
|
||||
clear: 'Clear',
|
||||
confirm: 'OK'
|
||||
},
|
||||
dropdown: {
|
||||
noData: 'No Data'
|
||||
},
|
||||
flow: {
|
||||
loadMore: 'Load More',
|
||||
noMore: 'No More Data'
|
||||
},
|
||||
form: {
|
||||
select: {
|
||||
noData: 'No Data',
|
||||
noMatch: 'No Matching Data',
|
||||
placeholder: 'Please Select'
|
||||
},
|
||||
validateMessages: {
|
||||
required: 'This field is required',
|
||||
phone: 'Invalid phone number format',
|
||||
email: 'Invalid email format',
|
||||
url: 'Invalid URL format',
|
||||
number: 'Numbers only',
|
||||
date: 'Invalid date format',
|
||||
identity: 'Invalid ID number format'
|
||||
},
|
||||
verifyErrorPromptTitle: 'Notice'
|
||||
},
|
||||
laydate: {
|
||||
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',
|
||||
endTime: 'End Time',
|
||||
tools: {
|
||||
confirm: 'Confirm',
|
||||
clear: 'Clear',
|
||||
now: 'Now',
|
||||
reset: 'Reset'
|
||||
},
|
||||
rangeOrderPrompt: 'End time cannot be less than start Time\nPlease re-select',
|
||||
invalidDatePrompt: 'Invalid date\n',
|
||||
formatErrorPrompt: 'Date format is invalid\nMust follow the format:\n{format}\n',
|
||||
autoResetPrompt: 'It has been reset',
|
||||
preview: 'The selected result'
|
||||
},
|
||||
layer: {
|
||||
confirm: 'OK',
|
||||
cancel: 'Cancel',
|
||||
defaultTitle: 'Info',
|
||||
prompt: {
|
||||
InputLengthPrompt: 'Maximum {length} characters'
|
||||
},
|
||||
photos: {
|
||||
noData: 'No Image',
|
||||
tools: {
|
||||
rotate: 'Rotate',
|
||||
scaleX: 'Flip Horizontally',
|
||||
zoomIn: 'Zoom In',
|
||||
zoomOut: 'Zoom Out',
|
||||
reset: 'Reset',
|
||||
close: 'Close'
|
||||
},
|
||||
viewPicture: 'View Picture',
|
||||
urlError: {
|
||||
prompt: 'Image URL is invalid, \nContinue to next one?',
|
||||
confirm: 'Next',
|
||||
cancel: 'Cancel'
|
||||
}
|
||||
}
|
||||
},
|
||||
laypage: {
|
||||
prev: 'Prev',
|
||||
next: 'Next',
|
||||
first: 'First',
|
||||
last: 'Last',
|
||||
total: 'Total {total} items',
|
||||
pagesize: '/page',
|
||||
goto: 'Go to',
|
||||
page: 'page',
|
||||
confirm: 'Confirm'
|
||||
},
|
||||
table: {
|
||||
sort: {
|
||||
asc: 'Ascending',
|
||||
desc: 'Descending'
|
||||
},
|
||||
noData: 'No Data',
|
||||
tools: {
|
||||
filter: {
|
||||
title: 'Filter Columns'
|
||||
},
|
||||
export: {
|
||||
title: 'Export',
|
||||
noDataPrompt: 'No data in the table',
|
||||
compatPrompt: 'Export is not supported in IE. Please use Chrome or another modern browser.',
|
||||
csvText: 'Export CSV File'
|
||||
},
|
||||
print: {
|
||||
title: 'Print',
|
||||
noDataPrompt: 'No data in the table'
|
||||
}
|
||||
},
|
||||
dataFormatError: 'Returned data is invalid. The correct success status code should be: "{statusName}": {statusCode}',
|
||||
xhrError: 'Request Error: {msg}'
|
||||
},
|
||||
transfer: {
|
||||
noData: 'No Data',
|
||||
noMatch: 'No Match',
|
||||
title: ['List 1', 'List 2'],
|
||||
searchPlaceholder: 'Search by Keyword'
|
||||
},
|
||||
tree: {
|
||||
defaultNodeName: 'Unnamed',
|
||||
noData: 'No Data',
|
||||
deleteNodePrompt: 'Are you sure you want to delete the node "{name}"?'
|
||||
},
|
||||
upload: {
|
||||
fileType: {
|
||||
file: 'File',
|
||||
image: 'Image',
|
||||
video: 'Video',
|
||||
audio: 'Audio'
|
||||
},
|
||||
validateMessages: {
|
||||
fileExtensionError: 'Unsupported format in selected {fileType}',
|
||||
filesOverLengthLimit: 'Maximum {length} files allowed at once',
|
||||
currentFilesLength: 'You have selected {length} files',
|
||||
fileOverSizeLimit: 'File size must not exceed {size}'
|
||||
},
|
||||
chooseText: '{length} files'
|
||||
},
|
||||
util: {
|
||||
timeAgo: {
|
||||
days: '{days} days ago',
|
||||
hours: '{hours} hours ago',
|
||||
minutes: '{minutes} minutes ago',
|
||||
future: 'In the future',
|
||||
justNow: 'Just now'
|
||||
},
|
||||
toDateString: {
|
||||
meridiem: function (hours, minutes) {
|
||||
return hours < 12 ? 'AM' : 'PM';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// 繁體中文
|
||||
'zh-HK': {
|
||||
code: {
|
||||
copy: '複製代碼',
|
||||
copied: '已複製',
|
||||
copyError: '複製失敗',
|
||||
maximize: '最大化顯示',
|
||||
restore: '還原顯示',
|
||||
preview: '在新視窗預覽'
|
||||
},
|
||||
colorpicker: {
|
||||
clear: '清除',
|
||||
confirm: '確定'
|
||||
},
|
||||
dropdown: {
|
||||
noData: '暫無資料'
|
||||
},
|
||||
flow: {
|
||||
loadMore: '載入更多',
|
||||
noMore: '沒有更多了'
|
||||
},
|
||||
form: {
|
||||
select: {
|
||||
noData: '暫無資料',
|
||||
noMatch: '無匹配資料',
|
||||
placeholder: '請選擇'
|
||||
},
|
||||
validateMessages: {
|
||||
required: '必填項不能為空',
|
||||
phone: '手機號碼格式不正確',
|
||||
email: '電郵格式不正確',
|
||||
url: '連結格式不正確',
|
||||
number: '只能填寫數字',
|
||||
date: '日期格式不正確',
|
||||
identity: '身份證號碼格式不正確'
|
||||
},
|
||||
verifyErrorPromptTitle: '提示'
|
||||
},
|
||||
laydate: {
|
||||
months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
|
||||
weeks: ['日', '一', '二', '三', '四', '五', '六'],
|
||||
time: ['時', '分', '秒'],
|
||||
literal: {
|
||||
year: '年'
|
||||
},
|
||||
selectDate: '選擇日期',
|
||||
selectTime: '選擇時間',
|
||||
startTime: '開始時間',
|
||||
endTime: '結束時間',
|
||||
tools: {
|
||||
confirm: '確定',
|
||||
clear: '清除',
|
||||
now: '現在',
|
||||
reset: '重設'
|
||||
},
|
||||
rangeOrderPrompt: '結束時間不能早於開始時間\n請重新選擇',
|
||||
invalidDatePrompt: '不在有效日期或時間範圍內\n',
|
||||
formatErrorPrompt: '日期格式不合法\n必須遵循:\n{format}\n',
|
||||
autoResetPrompt: '已自動重設',
|
||||
preview: '當前選中的結果'
|
||||
},
|
||||
layer: {
|
||||
confirm: '確定',
|
||||
cancel: '取消',
|
||||
defaultTitle: '資訊',
|
||||
prompt: {
|
||||
InputLengthPrompt: '最多輸入 {length} 個字符'
|
||||
},
|
||||
photos: {
|
||||
noData: '沒有圖片',
|
||||
tools:{
|
||||
rotate: '旋轉',
|
||||
scaleX: '水平變換',
|
||||
zoomIn: '放大',
|
||||
zoomOut: '縮小',
|
||||
reset: '還原',
|
||||
close: '關閉'
|
||||
},
|
||||
viewPicture: '查看原圖',
|
||||
urlError: {
|
||||
prompt: '當前圖片地址異常,\n是否繼續查看下一張?',
|
||||
confirm: '下一張',
|
||||
cancel: '不看了'
|
||||
}
|
||||
}
|
||||
},
|
||||
laypage: {
|
||||
prev: '上一頁',
|
||||
next: '下一頁',
|
||||
first: '首頁',
|
||||
last: '尾頁',
|
||||
total: '共 {total} 條',
|
||||
pagesize: '條/頁',
|
||||
goto: '到第',
|
||||
page: '頁',
|
||||
confirm: '確定'
|
||||
},
|
||||
table: {
|
||||
sort: {
|
||||
asc: '升序',
|
||||
desc: '降序'
|
||||
},
|
||||
noData: '無資料',
|
||||
tools:{
|
||||
filter: {
|
||||
title: '篩選列'
|
||||
},
|
||||
export: {
|
||||
title: '匯出',
|
||||
noDataPrompt: '當前表格無資料',
|
||||
compatPrompt: '匯出功能不支援 IE,請用 Chrome 等高級瀏覽器匯出',
|
||||
csvText : '匯出 CSV 檔案'
|
||||
},
|
||||
print: {
|
||||
title: '列印',
|
||||
noDataPrompt: '當前表格無資料'
|
||||
}
|
||||
},
|
||||
dataFormatError: '返回的資料不符合規範,正確的成功狀態碼應為:"{statusName}": {statusCode}',
|
||||
xhrError: '請求異常,錯誤提示:{msg}'
|
||||
},
|
||||
transfer: {
|
||||
noData: '無資料',
|
||||
noMatch: '無匹配資料',
|
||||
title: ['列表一', '列表二'],
|
||||
searchPlaceholder: '關鍵詞搜尋'
|
||||
},
|
||||
tree: {
|
||||
defaultNodeName: '未命名',
|
||||
noData: '無資料',
|
||||
deleteNodePrompt: '確認刪除"{name}"節點嗎?'
|
||||
},
|
||||
upload: {
|
||||
fileType: {
|
||||
file: '檔案',
|
||||
image: '圖片',
|
||||
video: '影片',
|
||||
audio: '音訊'
|
||||
},
|
||||
validateMessages: {
|
||||
fileExtensionError: '選擇的{fileType}中包含不支援的格式',
|
||||
filesOverLengthLimit: '同時最多只能上傳: {length} 個檔案',
|
||||
currentFilesLength: '您當前已經選擇了: {length} 個檔案',
|
||||
fileOverSizeLimit: '檔案大小不能超過 {size}'
|
||||
},
|
||||
chooseText: '{length} 個檔案'
|
||||
},
|
||||
util: {
|
||||
timeAgo: {
|
||||
days: '{days} 天前',
|
||||
hours: '{hours} 小時前',
|
||||
minutes: '{minutes} 分鐘前',
|
||||
future: '未來',
|
||||
justNow: '剛剛'
|
||||
},
|
||||
toDateString: {
|
||||
meridiem: function(hours, minutes){
|
||||
var hm = hours * 100 + minutes;
|
||||
if (hm < 500) {
|
||||
return '凌晨';
|
||||
} else if (hm < 800) {
|
||||
return '早上';
|
||||
} else if (hm < 1200) {
|
||||
return '上午';
|
||||
} else if (hm < 1300) {
|
||||
return '中午';
|
||||
} else if (hm < 1900) {
|
||||
return '下午';
|
||||
}
|
||||
return '晚上';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script src="{{= d.layui[2].cdn.js }}"></script>
|
||||
<script>
|
||||
layui.use(async function () {
|
||||
const {
|
||||
$, colorpicker, dropdown, flow, form,
|
||||
i18n, laydate, laypage, laytpl, layer,
|
||||
table, transfer, tree, upload, util
|
||||
} = layui;
|
||||
|
||||
/**
|
||||
* 业务 i18n 配置
|
||||
* 说明:此处仅为了让演示的「页面内容」与「Layui 组件」语言保持一致。实际使用时通常只需指定 Layui 组件语言环境,而页面内容的语言建议由您的项目本身进行管理。
|
||||
*/
|
||||
i18n.set({
|
||||
messages: {
|
||||
'zh-CN': {
|
||||
custom: {
|
||||
switchLanguage: '切换语言',
|
||||
readme: {
|
||||
description: 'layui.i18n.$t 是私有方法(未文档化),此处仅用于演示',
|
||||
hello: '你好',
|
||||
},
|
||||
form: {
|
||||
required: '验证必填项',
|
||||
phone: '验证手机号',
|
||||
email: '验证邮箱',
|
||||
date: '验证日期',
|
||||
select: '选择框',
|
||||
submit: '立即提交',
|
||||
reset: '重置',
|
||||
placeholder: '请输入'
|
||||
}
|
||||
}
|
||||
},
|
||||
'en': {
|
||||
custom: {
|
||||
switchLanguage: 'Switch Language',
|
||||
readme: {
|
||||
description: 'layui.i18n.$t is a private method (undocumented), used here for demonstration only.',
|
||||
hello: 'Hello',
|
||||
},
|
||||
form: {
|
||||
required: 'Required',
|
||||
phone: 'Telephone',
|
||||
email: 'Email',
|
||||
date: 'Date',
|
||||
select: 'Select',
|
||||
submit: 'Submit',
|
||||
reset: 'Reset',
|
||||
placeholder: 'Please enter'
|
||||
}
|
||||
}
|
||||
},
|
||||
'zh-HK': {
|
||||
custom: {
|
||||
switchLanguage: '切換語言',
|
||||
readme: {
|
||||
description: 'layui.i18n.$t 是私有方法(未文檔化),此處僅用於示範',
|
||||
hello: '你好',
|
||||
},
|
||||
form: {
|
||||
required: '驗證必填項',
|
||||
phone: '驗證手機號',
|
||||
email: '驗證郵箱',
|
||||
date: '驗證日期',
|
||||
select: '選擇框',
|
||||
submit: '立即提交',
|
||||
reset: '重置',
|
||||
placeholder: '請輸入'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 渲染页面模板
|
||||
const template = $('#template').html();
|
||||
const html = laytpl(template, { tagStyle: 'modern' }).render();
|
||||
$('#root').html(html);
|
||||
|
||||
|
||||
/**
|
||||
* 组件示例
|
||||
*/
|
||||
|
||||
// code
|
||||
layui.code({
|
||||
elem: "#demo-code",
|
||||
preview: true,
|
||||
tools: ['copy', 'full', 'window'],
|
||||
header: true,
|
||||
lang: 'html',
|
||||
langMarker: true,
|
||||
});
|
||||
|
||||
// colorpicker
|
||||
colorpicker.render({
|
||||
elem: "#demo-colorpicker",
|
||||
});
|
||||
|
||||
// dropdown
|
||||
dropdown.render({
|
||||
elem: "#demo-dropdown",
|
||||
});
|
||||
|
||||
// flow
|
||||
flow.load({
|
||||
elem: '#demo-flow',
|
||||
scrollElem: '#demo-flow',
|
||||
done: function (page, next) {
|
||||
// 模拟数据插入
|
||||
setTimeout(function () {
|
||||
var lis = [];
|
||||
for (var i = 0; i < 3; i++) {
|
||||
lis.push('<li>' + ((page - 1) * 3 + i + 1) + '</li>')
|
||||
}
|
||||
next(lis.join(''), page < 2);
|
||||
}, 200);
|
||||
}
|
||||
});
|
||||
|
||||
// form
|
||||
form.on('submit(demo1)', function (data) {
|
||||
var field = data.field;
|
||||
// 显示填写结果,仅作演示用
|
||||
layer.alert(JSON.stringify(field));
|
||||
return false;
|
||||
});
|
||||
|
||||
// laydate
|
||||
laydate.render({
|
||||
elem: "#demo-laydate",
|
||||
type: "datetime",
|
||||
calendar: true
|
||||
});
|
||||
|
||||
// layer
|
||||
util.on({
|
||||
alert: function () {
|
||||
layer.alert("Hello world");
|
||||
},
|
||||
prompt: function () {
|
||||
layer.prompt({ formType: 1, maxlength: 3 }, function (value, index) {
|
||||
layer.close(index);
|
||||
});
|
||||
},
|
||||
photos: function () {
|
||||
layer.photos({
|
||||
photos: {
|
||||
"title": "Photos Demo",
|
||||
"start": 0,
|
||||
"data": [
|
||||
{
|
||||
"alt": "layer",
|
||||
"pid": 1,
|
||||
"src": "https://unpkg.com/outeres@0.1.1/demo/layer.png",
|
||||
},
|
||||
{
|
||||
"alt": "error",
|
||||
"pid": 3,
|
||||
"src": "error.png",
|
||||
},
|
||||
{
|
||||
"alt": "universe",
|
||||
"pid": 5,
|
||||
"src": "https://unpkg.com/outeres@0.1.1/demo/outer-space.jpg",
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
// laypage
|
||||
laypage.render({
|
||||
elem: "demo-laypage-all",
|
||||
count: 100,
|
||||
layout: ["count", "prev", "page", "next", "limit", "refresh", "skip"],
|
||||
});
|
||||
|
||||
// table
|
||||
table.render({
|
||||
elem: '#demo-table',
|
||||
cols: [[{ field: 'test', title: '1', sort: true }, { field: 'test2', title: '2', sort: true }]],
|
||||
data: new Array(0),
|
||||
toolbar: 'default',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
height: 'full',
|
||||
page: true,
|
||||
text: {
|
||||
// none: 'none'
|
||||
}
|
||||
});
|
||||
|
||||
// transfer
|
||||
transfer.render({
|
||||
elem: '#demo-transfer',
|
||||
data: [
|
||||
{ "value": "1", "title": "Item 1" },
|
||||
{ "value": "2", "title": "Item 2" },
|
||||
{ "value": "3", "title": "Item 3" },
|
||||
],
|
||||
showSearch: true
|
||||
});
|
||||
|
||||
// tree
|
||||
tree.render({
|
||||
elem: '#demo-tree',
|
||||
data: [{ title: 'Item 1', id: 1, children: [{ title: 'Item 1-1', id: 2 }] }],
|
||||
edit: ['add', 'update', 'del']
|
||||
});
|
||||
|
||||
// upload
|
||||
upload.render({
|
||||
elem: '#demo-upload',
|
||||
url: '', // 实际使用时改成您自己的上传接口即可。
|
||||
multiple: true,
|
||||
accept: 'file',
|
||||
number: 1
|
||||
});
|
||||
|
||||
// util
|
||||
$('#demo-time-ago-picker').on('change', function(){
|
||||
$('#demo-time-ago-display').html(
|
||||
util.timeAgo(this.value)
|
||||
);
|
||||
})
|
||||
|
||||
$('#demo-toDateString').html(
|
||||
util.toDateString('2023-01-01 11:35:25', 'yyyy-MM-dd HH:mm:ss A')
|
||||
+ '<br>'
|
||||
+ util.toDateString('2023-01-01 18:35:25', 'yyyy-MM-dd HH:mm:ss A')
|
||||
)
|
||||
|
||||
// 演示:切换语言
|
||||
$("#change-locale").val(i18n.config.locale);
|
||||
form.render('select').on("select(change-locale)", function (elem) {
|
||||
// 记录语言,并重载页面(推荐)
|
||||
localStorage.setItem('layui-i18n-local-test', elem.value);
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
$("body").css("opacity", 1);
|
||||
console.log(i18n.config)
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
183
docs/i18n/detail/options.md
Normal file
183
docs/i18n/detail/options.md
Normal file
@@ -0,0 +1,183 @@
|
||||
<pre class="layui-code" lay-options="{style: 'height: 525px;', layout: ['code'], tools: []}">
|
||||
<textarea>
|
||||
i18n.set({
|
||||
locale: 'zh-CN', // 设置语言环境
|
||||
messages: { // 语言包
|
||||
'zh-CN': { // 简体中文语言包(内置)
|
||||
code: {
|
||||
copy: '复制代码',
|
||||
copied: '已复制',
|
||||
copyError: '复制失败',
|
||||
maximize: '最大化显示',
|
||||
restore: '还原显示',
|
||||
preview: '在新窗口预览'
|
||||
},
|
||||
colorpicker: {
|
||||
clear: '清除',
|
||||
confirm: '确定'
|
||||
},
|
||||
dropdown: {
|
||||
noData: '暂无数据'
|
||||
},
|
||||
flow: {
|
||||
loadMore: '加载更多',
|
||||
noMore: '没有更多了'
|
||||
},
|
||||
form: {
|
||||
select: {
|
||||
noData: '暂无数据',
|
||||
noMatch: '无匹配数据',
|
||||
placeholder: '请选择'
|
||||
},
|
||||
validateMessages: {
|
||||
required: '必填项不能为空',
|
||||
phone: '手机号格式不正确',
|
||||
email: '邮箱格式不正确',
|
||||
url: '链接格式不正确',
|
||||
number: '只能填写数字',
|
||||
date: '日期格式不正确',
|
||||
identity: '身份证号格式不正确'
|
||||
},
|
||||
verifyErrorPromptTitle: '提示'
|
||||
},
|
||||
laydate: {
|
||||
months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
|
||||
weeks: ['日', '一', '二', '三', '四', '五', '六'],
|
||||
time: ['时', '分', '秒'],
|
||||
literal: {
|
||||
year: '年'
|
||||
},
|
||||
selectDate: '选择日期',
|
||||
selectTime: '选择时间',
|
||||
startTime: '开始时间',
|
||||
endTime: '结束时间',
|
||||
tools: {
|
||||
confirm: '确定',
|
||||
clear: '清空',
|
||||
now: '现在',
|
||||
reset: '重置'
|
||||
},
|
||||
rangeOrderPrompt: '结束时间不能早于开始时间\n请重新选择',
|
||||
invalidDatePrompt: '不在有效日期或时间范围内\n',
|
||||
formatErrorPrompt: '日期格式不合法\n必须遵循:\n{format}\n',
|
||||
autoResetPrompt: '已自动重置',
|
||||
preview: '当前选中的结果'
|
||||
},
|
||||
layer: {
|
||||
confirm: '确定',
|
||||
cancel: '取消',
|
||||
defaultTitle: '信息',
|
||||
prompt: {
|
||||
InputLengthPrompt: '最多输入 {length} 个字符'
|
||||
},
|
||||
photos: {
|
||||
noData: '没有图片',
|
||||
tools:{
|
||||
rotate: '旋转',
|
||||
scaleX: '水平变换',
|
||||
zoomIn: '放大',
|
||||
zoomOut: '缩小',
|
||||
reset: '还原',
|
||||
close: '关闭'
|
||||
},
|
||||
viewPicture: '查看原图',
|
||||
urlError: {
|
||||
prompt: '当前图片地址异常,\n是否继续查看下一张?',
|
||||
confirm: '下一张',
|
||||
cancel: '不看了'
|
||||
}
|
||||
}
|
||||
},
|
||||
laypage: {
|
||||
prev: '上一页',
|
||||
next: '下一页',
|
||||
first: '首页',
|
||||
last: '尾页',
|
||||
total: '共 {total} 条',
|
||||
pagesize: '条/页',
|
||||
goto: '到第',
|
||||
page: '页',
|
||||
confirm: '确定'
|
||||
},
|
||||
table: {
|
||||
sort: {
|
||||
asc: '升序',
|
||||
desc: '降序'
|
||||
},
|
||||
noData: '暂无数据',
|
||||
tools:{
|
||||
filter: {
|
||||
title: '筛选列'
|
||||
},
|
||||
export: {
|
||||
title: '导出',
|
||||
noDataPrompt: '当前表格无数据',
|
||||
compatPrompt: '导出功能不支持 IE,请用 Chrome 等高级浏览器导出',
|
||||
csvText : '导出 CSV 文件'
|
||||
},
|
||||
print: {
|
||||
title: '打印',
|
||||
noDataPrompt: '当前表格无数据'
|
||||
}
|
||||
},
|
||||
dataFormatError: '返回的数据不符合规范,正确的成功状态码应为:"{statusName}": {statusCode}',
|
||||
xhrError: '请求异常,错误提示:{msg}'
|
||||
},
|
||||
transfer: {
|
||||
noData: '暂无数据',
|
||||
noMatch: '无匹配数据',
|
||||
title: ['列表一', '列表二'],
|
||||
searchPlaceholder: '关键词搜索'
|
||||
},
|
||||
tree: {
|
||||
defaultNodeName: '未命名',
|
||||
noData: '暂无数据',
|
||||
deleteNodePrompt: '确认删除"{name}"节点吗?'
|
||||
},
|
||||
upload: {
|
||||
fileType: {
|
||||
file: '文件',
|
||||
image: '图片',
|
||||
video: '视频',
|
||||
audio: '音频'
|
||||
},
|
||||
validateMessages: {
|
||||
fileExtensionError: '选择的{fileType}中包含不支持的格式',
|
||||
filesOverLengthLimit: '同时最多只能上传: {length} 个文件',
|
||||
currentFilesLength: '当前已经选择了: {length} 个文件',
|
||||
fileOverSizeLimit: '文件大小不能超过 {size}'
|
||||
},
|
||||
chooseText: '{length} 个文件'
|
||||
},
|
||||
util: {
|
||||
timeAgo: {
|
||||
days: '{days} 天前',
|
||||
hours: '{hours} 小时前',
|
||||
minutes: '{minutes} 分钟前',
|
||||
future: '未来',
|
||||
justNow: '刚刚'
|
||||
},
|
||||
toDateString: {
|
||||
// https://www.unicode.org/cldr/charts/47/supplemental/day_periods.html
|
||||
meridiem: function(hours, minutes){
|
||||
var hm = hours * 100 + minutes;
|
||||
if (hm < 500) {
|
||||
return '凌晨';
|
||||
} else if (hm < 800) {
|
||||
return '早上';
|
||||
} else if (hm < 1200) {
|
||||
return '上午';
|
||||
} else if (hm < 1300) {
|
||||
return '中午';
|
||||
} else if (hm < 1900) {
|
||||
return '下午';
|
||||
}
|
||||
return '晚上';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</textarea>
|
||||
</pre>
|
||||
114
docs/i18n/index.md
Normal file
114
docs/i18n/index.md
Normal file
@@ -0,0 +1,114 @@
|
||||
---
|
||||
title: 国际化 i18n
|
||||
toc: true
|
||||
---
|
||||
|
||||
# 国际化 <sup>2.12+</sup>
|
||||
|
||||
> `i18n` 是 2.12 版本新增的国际化模块,用于为 Layui 各组件实现多语言支持。
|
||||
|
||||
<h2 id="examples" lay-toc="{}" style="margin-bottom: 0;">完整演示</h2>
|
||||
|
||||
为了避免语言包配置冗长而影响示例源代码的查看,此处只演示「简体中文 / English / 繁體中文」语言环境,你可以点击该示例头部的「切换语言」选择框查看 Layui 组件在不同语言环境中的显示效果。
|
||||
|
||||
<div class="ws-docs-showcase"></div>
|
||||
|
||||
<pre class="layui-code" lay-options="{preview: 'iframe', text: {preview: 'Preview'}, style: 'height: 560px;', layout: ['preview', 'code'], tools: ['full','window']}">
|
||||
<textarea>
|
||||
{{- d.include("/i18n/detail/demo.md") }}
|
||||
</textarea>
|
||||
</pre>
|
||||
|
||||
<h2 id="api" lay-toc="{hot: true}">API</h2>
|
||||
|
||||
| API | 描述 |
|
||||
| --- | --- |
|
||||
| var i18n = layui.i18n | 获得 `i18n` 模块。|
|
||||
| [i18n.set(options)](#set) | 设置语言环境及语言包。|
|
||||
|
||||
<h3 id="set" lay-toc="{level: 2}">配置方式</h3>
|
||||
|
||||
i18n 支持两种配置方式,你可以根据实际应用场景选择任一方式。
|
||||
|
||||
#### 1. 通过 `i18n.set()` 方法配置
|
||||
|
||||
`i18n.set(options)`
|
||||
|
||||
- 参数 `options` : 基础属性选项。[#详见语言包选项](#options)
|
||||
|
||||
```js
|
||||
layui.use(function() {
|
||||
var i18n = layui.i18n;
|
||||
|
||||
// 设置语言
|
||||
i18n.set({
|
||||
locale: 'zh-CN', // 当前语言环境。zh-CN 为内置简体中文语言包
|
||||
messages: { // 扩展其他语言包
|
||||
'en': {},
|
||||
'zh-HK': {},
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
🔔 请注意:如果你的页面有用到 Layui 组件的自动渲染(如 table 模板配置渲染方式),因为执行顺序的问题,组件在自动渲染时可能无法读取到 `i18n.set()` 的配置信息,此时建议采用下述 `LAYUI_GLOBAL.i18n` 全局配置。
|
||||
|
||||
#### 2. 通过 `LAYUI_GLOBAL.i18n` 全局配置(推荐)
|
||||
|
||||
由于 i18n 配置与组件渲染存在执行顺序问题,为了确保 i18n 配置始终在组件渲染之前生效,更推荐采用该全局配置方式。
|
||||
|
||||
```html
|
||||
<script>
|
||||
// 全局配置应放在 layui.js 引入之前的位置
|
||||
window.LAYUI_GLOBAL = {
|
||||
i18n: { // 选项同 i18n.set(options)
|
||||
locale: 'zh-CN', // 当前语言环境
|
||||
messages: { // 扩展其他语言包
|
||||
'en': {},
|
||||
'zh-HK': {},
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script src="/layui/layui.js"></script>
|
||||
```
|
||||
|
||||
<h3 id="options" lay-toc="{level: 2}">语言包选项</h3>
|
||||
|
||||
i18n 默认采用简体中文(`zh-CN`)语言环境,以下为各组件消息文本对应的选项:
|
||||
|
||||
<div>
|
||||
{{- d.include("/i18n/detail/options.md") }}
|
||||
</div>
|
||||
|
||||
|
||||
基于上述选项,还可以扩展更多语言包,如:
|
||||
|
||||
```js
|
||||
i18n.set({
|
||||
locale: 'en', // 当前语言环境
|
||||
messages: { // 扩展更多语言包
|
||||
'en': { // 通用英语
|
||||
code: {
|
||||
copy: 'Copy Code',
|
||||
copied: 'Copied',
|
||||
// ……
|
||||
},
|
||||
// ……
|
||||
},
|
||||
'fr': {}, // 通用法语
|
||||
'zh-HK': {}, // 繁体中文
|
||||
// …… // 更多语言
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
为了节省时间,也可以借助「**第三方提供并维护**的 Layui 多语言 AI 翻译工具」直接生成不同语言的消息文本,如:
|
||||
|
||||
| 翻译工具 | 提供者 |
|
||||
| --- | --- |
|
||||
| <a href="https://gitee.com/mail_osc/translate/tree/master/extend/layui-i18n-object-translate" target="_blank">https://gitee.com/mail_osc/translate/tree/master/extend/layui-i18n-object-translate</a> | <a href="https://github.com/xnx3" target="_blank">@xnx3</a> |
|
||||
|
||||
## 💖 心语
|
||||
|
||||
i18n 模块是在众多开发者强烈的需求呼声中,由 Layui 核心 Contributor [@Sight-wcg](https://github.com/Sight-wcg) 完成,该模块通过简练的设计,为 Layui 组件实现了多语言的无缝接入,并且兼容了一些原本自带简单多语言或消息配置的组件,Layui 2.x 版本也因此具备国际化能力。
|
||||
486
examples/i18n.html
Normal file
486
examples/i18n.html
Normal file
@@ -0,0 +1,486 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>i18n - Layui</title>
|
||||
<link href="../src/css/layui.css" rel="stylesheet" />
|
||||
<style>
|
||||
body {
|
||||
transition: opacity 0.8s ease-in-out;
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="layui-padding-3">
|
||||
<div id="root"></div>
|
||||
<template id="template">
|
||||
{{ const i18n = layui.i18n; }}
|
||||
<div class="layui-form">
|
||||
<div class="layui-inline">
|
||||
<strong>{{= i18n.$t('custom.switchLanguage') }}: </strong>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<select id="change-locale" lay-filter="change-locale">
|
||||
<option value="zh-CN">简体中文</option>
|
||||
<option value="en">English</option>
|
||||
<option value="fr">Français</option>
|
||||
<option value="zh-HK">繁體中文</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>README</legend>
|
||||
<div class="layui-field-box layui-text" id="tpl-test">
|
||||
<p>{{= i18n.$t('custom.readme.description') }}</p>
|
||||
<ul>
|
||||
<li><strong>locale</strong>: <span style="color:red">{{= i18n.config.locale }}</span></li>
|
||||
<li><strong>Date</strong>: {{= new Date().toLocaleDateString(i18n.config.locale) }}</li>
|
||||
<li><strong>Hello</strong>: {{= i18n.$t('custom.readme.hello') }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>code</legend>
|
||||
<div class="layui-field-box">
|
||||
<pre id="demo-code" class="layui-code" lay-options="{}">
|
||||
<textarea>
|
||||
code content
|
||||
</textarea>
|
||||
</pre>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>colorpicker</legend>
|
||||
<div class="layui-field-box">
|
||||
<div id="demo-colorpicker"></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>dropdown</legend>
|
||||
<div class="layui-field-box">
|
||||
<button id="demo-dropdown" class="layui-btn demo-dropdown-base">
|
||||
<span>Dropdown</span>
|
||||
<i class="layui-icon layui-icon-down layui-font-12"></i>
|
||||
</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>flow</legend>
|
||||
<div class="layui-field-box">
|
||||
<div class="flow-demo" id="demo-flow"></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>form</legend>
|
||||
<div class="layui-field-box">
|
||||
<form class="layui-form" action="">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">{{= i18n.$t('custom.form.required') }}</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="username" lay-verify="required" lay-vertype="alert" placeholder="{{= i18n.$t('custom.form.placeholder') }}" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">{{= i18n.$t('custom.form.phone') }}</label>
|
||||
<div class="layui-input-inline layui-input-wrap">
|
||||
<input type="tel" name="phone" lay-verify="phone" autocomplete="off" value="123456" lay-affix="clear"
|
||||
class="layui-input demo-phone">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">{{= i18n.$t('custom.form.email') }}</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="email" value="123.com" lay-verify="email" autocomplete="off"
|
||||
class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">{{= i18n.$t('custom.form.date') }}</label>
|
||||
<div class="layui-input-inline layui-input-wrap">
|
||||
<div class="layui-input-prefix">
|
||||
<i class="layui-icon layui-icon-date"></i>
|
||||
</div>
|
||||
<input type="text" name="date" value="2077" id="date" lay-verify="date" placeholder="yyyy-MM-dd"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">{{= i18n.$t('custom.form.select') }}</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="interest" lay-filter="aihao" lay-search>
|
||||
<option value=""></option>
|
||||
<option value="0">AAA</option>
|
||||
<option value="1" selected>BBB</option>
|
||||
<option value="2">CCC</option>
|
||||
<option value="3">DDD</option>
|
||||
<option value="4">EEE</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button type="submit" class="layui-btn" lay-submit lay-filter="demo1">
|
||||
{{= i18n.$t('custom.form.submit') }}
|
||||
</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">
|
||||
{{= i18n.$t('custom.form.reset') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>laydate</legend>
|
||||
<div class="layui-field-box">
|
||||
<div class="layui-inline">
|
||||
<input class="layui-input" id="demo-laydate" />
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>layer</legend>
|
||||
<div class="layui-field-box">
|
||||
<button type="button" class="layui-btn layui-btn-primary" lay-on="alert">Alert</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" lay-on="prompt">Prompt</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" lay-on="photos">Photos</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>laypage</legend>
|
||||
<div class="layui-field-box">
|
||||
<div id="demo-laypage-all"></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>table</legend>
|
||||
<div class="layui-field-box">
|
||||
<table class="layui-hide" id="demo-table" lay-filter="test"></table>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>transfer</legend>
|
||||
<div class="layui-field-box">
|
||||
<div id="demo-transfer"></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>tree</legend>
|
||||
<div class="layui-field-box">
|
||||
<div id="demo-tree"></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>upload</legend>
|
||||
<div class="layui-field-box">
|
||||
<button type="button" class="layui-btn" id="demo-upload">
|
||||
<i class="layui-icon layui-icon-upload"></i> Upload
|
||||
</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>utils</legend>
|
||||
<div class="layui-field-box">
|
||||
<label>
|
||||
timeAgo: <input id="demo-time-ago-picker" type="datetime-local" /> <span id="demo-time-ago-display"></span>
|
||||
</label>
|
||||
<br>
|
||||
<label>
|
||||
toDateString: <div id="demo-toDateString"></div>
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
</template>
|
||||
|
||||
<script src="../src/layui.js"></script>
|
||||
<script>
|
||||
layui.use(async function () {
|
||||
const {
|
||||
$, colorpicker, dropdown, flow, form,
|
||||
i18n, laydate, laypage, laytpl, layer,
|
||||
table, transfer, tree, upload, util
|
||||
} = layui;
|
||||
|
||||
// 演示异步加载组件语言包
|
||||
const { default: en } = await import('./i18n/en.js');
|
||||
const { default: fr } = await import('./i18n/fr.js');
|
||||
const { default: zhHK } = await import('./i18n/zh-HK.js');
|
||||
|
||||
// 组件 i18n 配置
|
||||
i18n.set({
|
||||
locale: layui.data('layui-i18n-test').locale || 'zh-CN', // 指定语言
|
||||
messages: {
|
||||
en, // 扩展英语
|
||||
fr, // 扩展法语
|
||||
'zh-HK': zhHK, // 扩展繁体中文
|
||||
},
|
||||
});
|
||||
|
||||
// 业务 i18n 配置
|
||||
i18n.set({
|
||||
messages: {
|
||||
'zh-CN': {
|
||||
custom: {
|
||||
switchLanguage: '切换语言',
|
||||
readme: {
|
||||
description: 'layui.i18n.$t 是私有方法(未文档化),此处仅用于演示',
|
||||
hello: '你好',
|
||||
},
|
||||
form: {
|
||||
required: '验证必填项',
|
||||
phone: '验证手机号',
|
||||
email: '验证邮箱',
|
||||
date: '验证日期',
|
||||
select: '选择框',
|
||||
submit: '立即提交',
|
||||
reset: '重置',
|
||||
placeholder: '请输入'
|
||||
}
|
||||
}
|
||||
},
|
||||
'en': {
|
||||
custom: {
|
||||
switchLanguage: 'Switch Language',
|
||||
readme: {
|
||||
description: 'layui.i18n.$t is a private method (undocumented), used here for demonstration only.',
|
||||
hello: 'Hello',
|
||||
},
|
||||
form: {
|
||||
required: 'Required',
|
||||
phone: 'Telephone',
|
||||
email: 'Email',
|
||||
date: 'Date',
|
||||
select: 'Select',
|
||||
submit: 'Submit',
|
||||
reset: 'Reset',
|
||||
placeholder: 'Please enter'
|
||||
}
|
||||
}
|
||||
},
|
||||
'fr': {
|
||||
custom: {
|
||||
switchLanguage: 'Changer la langue',
|
||||
readme: {
|
||||
description: 'layui.i18n.$t est une méthode privée (non documentée), utilisée ici uniquement à des fins de démonstration.',
|
||||
hello: 'Bonjour',
|
||||
},
|
||||
form: {
|
||||
required: 'Requis',
|
||||
phone: 'Téléphone',
|
||||
email: 'Email',
|
||||
date: 'Date',
|
||||
select: 'Sélection',
|
||||
submit: 'Soumettre maintenant',
|
||||
reset: 'Réinitialiser',
|
||||
placeholder: 'Veuillez entrer'
|
||||
}
|
||||
}
|
||||
},
|
||||
'zh-HK': {
|
||||
custom: {
|
||||
switchLanguage: '切換語言',
|
||||
readme: {
|
||||
description: 'layui.i18n.$t 是私有方法(未文檔化),此處僅用於示範',
|
||||
hello: '你好',
|
||||
},
|
||||
form: {
|
||||
required: '驗證必填項',
|
||||
phone: '驗證手機號',
|
||||
email: '驗證郵箱',
|
||||
date: '驗證日期',
|
||||
select: '選擇框',
|
||||
submit: '立即提交',
|
||||
reset: '重置',
|
||||
placeholder: '請輸入'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 渲染页面模板
|
||||
const template = $('#template').html();
|
||||
const html = laytpl(template, { tagStyle: 'modern' }).render();
|
||||
$('#root').html(html);
|
||||
|
||||
|
||||
/**
|
||||
* 组件示例
|
||||
*/
|
||||
|
||||
// code
|
||||
layui.code({
|
||||
elem: "#demo-code",
|
||||
preview: true,
|
||||
tools: ['copy', 'full', 'window'],
|
||||
header: true,
|
||||
lang: 'html',
|
||||
langMarker: true,
|
||||
});
|
||||
|
||||
// colorpicker
|
||||
colorpicker.render({
|
||||
elem: "#demo-colorpicker",
|
||||
});
|
||||
|
||||
// dropdown
|
||||
dropdown.render({
|
||||
elem: "#demo-dropdown",
|
||||
});
|
||||
|
||||
// flow
|
||||
flow.load({
|
||||
elem: '#demo-flow',
|
||||
scrollElem: '#demo-flow',
|
||||
done: function (page, next) {
|
||||
// 模拟数据插入
|
||||
setTimeout(function () {
|
||||
var lis = [];
|
||||
for (var i = 0; i < 3; i++) {
|
||||
lis.push('<li>' + ((page - 1) * 3 + i + 1) + '</li>')
|
||||
}
|
||||
next(lis.join(''), page < 2);
|
||||
}, 200);
|
||||
}
|
||||
});
|
||||
|
||||
// form
|
||||
form.on('submit(demo1)', function (data) {
|
||||
var field = data.field;
|
||||
// 显示填写结果,仅作演示用
|
||||
layer.alert(JSON.stringify(field));
|
||||
return false;
|
||||
});
|
||||
|
||||
//laydate
|
||||
laydate.render({
|
||||
elem: "#demo-laydate",
|
||||
type: "datetime",
|
||||
calendar: true
|
||||
});
|
||||
|
||||
// layer
|
||||
util.on({
|
||||
alert: function () {
|
||||
layer.alert("Hello world");
|
||||
},
|
||||
prompt: function () {
|
||||
layer.prompt({ formType: 1, maxlength: 3 }, function (value, index) {
|
||||
layer.close(index);
|
||||
});
|
||||
},
|
||||
photos: function () {
|
||||
layer.photos({
|
||||
photos: {
|
||||
"title": "Photos Demo",
|
||||
"start": 0,
|
||||
"data": [
|
||||
{
|
||||
"alt": "layer",
|
||||
"pid": 1,
|
||||
"src": "https://unpkg.com/outeres@0.1.1/demo/layer.png",
|
||||
},
|
||||
{
|
||||
"alt": "error",
|
||||
"pid": 3,
|
||||
"src": "错误提示演示",
|
||||
},
|
||||
{
|
||||
"alt": "universe",
|
||||
"pid": 5,
|
||||
"src": "https://unpkg.com/outeres@0.1.1/demo/outer-space.jpg",
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
// laypage
|
||||
laypage.render({
|
||||
elem: "demo-laypage-all",
|
||||
count: 100,
|
||||
layout: ["count", "prev", "page", "next", "limit", "refresh", "skip"],
|
||||
});
|
||||
|
||||
// table
|
||||
table.render({
|
||||
elem: '#demo-table',
|
||||
cols: [[{ field: 'test', title: '1', sort: true }, { field: 'test2', title: '2', sort: true }]],
|
||||
data: new Array(0),
|
||||
toolbar: 'default',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
height: 'full',
|
||||
page: true,
|
||||
text: {
|
||||
// none: 'none'
|
||||
}
|
||||
});
|
||||
|
||||
// transfer
|
||||
transfer.render({
|
||||
elem: '#demo-transfer',
|
||||
data: [
|
||||
{ "value": "1", "title": "Item 1" },
|
||||
{ "value": "2", "title": "Item 2" },
|
||||
{ "value": "3", "title": "Item 3" },
|
||||
],
|
||||
showSearch: true
|
||||
});
|
||||
|
||||
// tree
|
||||
tree.render({
|
||||
elem: '#demo-tree',
|
||||
//data: [],
|
||||
data: [{ title: 'Item 1', id: 1, children: [{ title: 'Item 1-1', id: 2 }] }],
|
||||
edit: ['add', 'update', 'del']
|
||||
});
|
||||
|
||||
// upload
|
||||
upload.render({
|
||||
elem: '#demo-upload',
|
||||
url: '', // 实际使用时改成您自己的上传接口即可。
|
||||
multiple: true,
|
||||
accept: 'file',
|
||||
//exts: 'zip',
|
||||
number: 1,
|
||||
//size: 60,
|
||||
});
|
||||
|
||||
// util
|
||||
$('#demo-time-ago-picker').on('change', function(){
|
||||
$('#demo-time-ago-display').html(
|
||||
util.timeAgo(this.value)
|
||||
);
|
||||
})
|
||||
|
||||
$('#demo-toDateString').html(
|
||||
util.toDateString('2023-01-01 11:35:25', 'yyyy-MM-dd HH:mm:ss A')
|
||||
+ '<br>'
|
||||
+ util.toDateString('2023-01-01 18:35:25', 'yyyy-MM-dd HH:mm:ss A')
|
||||
)
|
||||
|
||||
// 演示:切换语言
|
||||
$("#change-locale").val(i18n.config.locale);
|
||||
form.render('select').on("select(change-locale)", function (elem) {
|
||||
// 记录语言,并重载页面(推荐)
|
||||
layui.data('layui-i18n-test', {
|
||||
key: 'locale',
|
||||
value: elem.value
|
||||
});
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
$("body").css("opacity", 1);
|
||||
layer.msg(layui.v);
|
||||
console.log(i18n.config)
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
166
examples/i18n/en.js
Normal file
166
examples/i18n/en.js
Normal file
@@ -0,0 +1,166 @@
|
||||
/**
|
||||
* English (en)
|
||||
*/
|
||||
|
||||
// Common English internationalization message object
|
||||
export default {
|
||||
code: {
|
||||
copy: 'Copy Code',
|
||||
copied: 'Copied',
|
||||
copyError: 'Copy Failed',
|
||||
maximize: 'Maximize',
|
||||
restore: 'Restore',
|
||||
preview: 'Preview in New Window'
|
||||
},
|
||||
colorpicker: {
|
||||
clear: 'Clear',
|
||||
confirm: 'OK'
|
||||
},
|
||||
dropdown: {
|
||||
noData: 'No Data'
|
||||
},
|
||||
flow: {
|
||||
loadMore: 'Load More',
|
||||
noMore: 'No More Data'
|
||||
},
|
||||
form: {
|
||||
select: {
|
||||
noData: 'No Data',
|
||||
noMatch: 'No Matching Data',
|
||||
placeholder: 'Please Select'
|
||||
},
|
||||
validateMessages: {
|
||||
required: 'This field is required',
|
||||
phone: 'Invalid phone number format',
|
||||
email: 'Invalid email format',
|
||||
url: 'Invalid URL format',
|
||||
number: 'Numbers only',
|
||||
date: 'Invalid date format',
|
||||
identity: 'Invalid ID number format'
|
||||
},
|
||||
verifyErrorPromptTitle: 'Notice'
|
||||
},
|
||||
laydate: {
|
||||
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',
|
||||
endTime: 'End Time',
|
||||
tools: {
|
||||
confirm: 'Confirm',
|
||||
clear: 'Clear',
|
||||
now: 'Now',
|
||||
reset: 'Reset'
|
||||
},
|
||||
rangeOrderPrompt: 'End time cannot be less than start Time\nPlease re-select',
|
||||
invalidDatePrompt: 'Invalid date\n',
|
||||
formatErrorPrompt: 'Date format is invalid\nMust follow the format:\n{format}\n',
|
||||
autoResetPrompt: 'It has been reset',
|
||||
preview: 'The selected result'
|
||||
},
|
||||
layer: {
|
||||
confirm: 'OK',
|
||||
cancel: 'Cancel',
|
||||
defaultTitle: 'Info',
|
||||
prompt: {
|
||||
InputLengthPrompt: 'Maximum {length} characters'
|
||||
},
|
||||
photos: {
|
||||
noData: 'No Image',
|
||||
tools: {
|
||||
rotate: 'Rotate',
|
||||
scaleX: 'Flip Horizontally',
|
||||
zoomIn: 'Zoom In',
|
||||
zoomOut: 'Zoom Out',
|
||||
reset: 'Reset',
|
||||
close: 'Close'
|
||||
},
|
||||
viewPicture: 'View Original',
|
||||
urlError: {
|
||||
prompt: 'Image URL is invalid, \nContinue to next one?',
|
||||
confirm: 'Next',
|
||||
cancel: 'Cancel'
|
||||
}
|
||||
}
|
||||
},
|
||||
laypage: {
|
||||
prev: 'Prev',
|
||||
next: 'Next',
|
||||
first: 'First',
|
||||
last: 'Last',
|
||||
total: 'Total {total} items',
|
||||
pagesize: 'items/page',
|
||||
goto: 'Go to',
|
||||
page: 'page',
|
||||
confirm: 'Confirm'
|
||||
},
|
||||
table: {
|
||||
sort: {
|
||||
asc: 'Ascending',
|
||||
desc: 'Descending'
|
||||
},
|
||||
noData: 'No Data',
|
||||
tools: {
|
||||
filter: {
|
||||
title: 'Filter Columns'
|
||||
},
|
||||
export: {
|
||||
title: 'Export',
|
||||
noDataPrompt: 'No data in the table',
|
||||
compatPrompt: 'Export is not supported in IE. Please use Chrome or another modern browser.',
|
||||
csvText: 'Export CSV File'
|
||||
},
|
||||
print: {
|
||||
title: 'Print',
|
||||
noDataPrompt: 'No data in the table'
|
||||
}
|
||||
},
|
||||
dataFormatError: 'Returned data is invalid. The correct success status code should be: "{statusName}": {statusCode}',
|
||||
xhrError: 'Request Error: {msg}'
|
||||
},
|
||||
transfer: {
|
||||
noData: 'No Data',
|
||||
noMatch: 'No Match',
|
||||
title: ['List One', 'List Two'],
|
||||
searchPlaceholder: 'Search by Keyword'
|
||||
},
|
||||
tree: {
|
||||
defaultNodeName: 'Unnamed',
|
||||
noData: 'No Data',
|
||||
deleteNodePrompt: 'Are you sure you want to delete the node "{name}"?'
|
||||
},
|
||||
upload: {
|
||||
fileType: {
|
||||
file: 'File',
|
||||
image: 'Image',
|
||||
video: 'Video',
|
||||
audio: 'Audio'
|
||||
},
|
||||
validateMessages: {
|
||||
fileExtensionError: 'Unsupported format in selected {fileType}',
|
||||
filesOverLengthLimit: 'Maximum {length} files allowed at once',
|
||||
currentFilesLength: 'You have selected {length} files',
|
||||
fileOverSizeLimit: 'File size must not exceed {size}'
|
||||
},
|
||||
chooseText: '{length} files'
|
||||
},
|
||||
util: {
|
||||
timeAgo: {
|
||||
days: '{days} days ago',
|
||||
hours: '{hours} hours ago',
|
||||
minutes: '{minutes} minutes ago',
|
||||
future: 'In the future',
|
||||
justNow: 'Just now'
|
||||
},
|
||||
toDateString: {
|
||||
meridiem: function (hours, minutes) {
|
||||
return hours < 12 ? 'AM' : 'PM';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
166
examples/i18n/fr.js
Normal file
166
examples/i18n/fr.js
Normal file
@@ -0,0 +1,166 @@
|
||||
/**
|
||||
* Français (fr)
|
||||
*/
|
||||
|
||||
export default {
|
||||
code: {
|
||||
copy: 'Copier le code',
|
||||
copied: 'Copié',
|
||||
copyError: 'Échec de la copie',
|
||||
maximize: 'Afficher en plein écran',
|
||||
restore: 'Restaurer l’affichage',
|
||||
preview: 'Aperçu dans une nouvelle fenêtre'
|
||||
},
|
||||
colorpicker: {
|
||||
clear: 'Effacer',
|
||||
confirm: 'OK'
|
||||
},
|
||||
dropdown: {
|
||||
noData: 'Aucune donnée disponible'
|
||||
},
|
||||
flow: {
|
||||
loadMore: 'Charger plus',
|
||||
noMore: 'Plus de données'
|
||||
},
|
||||
form: {
|
||||
select: {
|
||||
noData: 'Aucune donnée disponible',
|
||||
noMatch: 'Aucune correspondance',
|
||||
placeholder: 'Veuillez sélectionner'
|
||||
},
|
||||
validateMessages: {
|
||||
required: 'Ce champ est obligatoire',
|
||||
phone: 'Numéro de téléphone invalide',
|
||||
email: 'Adresse e-mail invalide',
|
||||
url: 'URL invalide',
|
||||
number: 'Uniquement des chiffres',
|
||||
date: 'Format de date invalide',
|
||||
identity: 'Numéro d’identification invalide'
|
||||
},
|
||||
verifyErrorPromptTitle: 'Avertissement'
|
||||
},
|
||||
laydate: {
|
||||
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',
|
||||
endTime: 'Heure de fin',
|
||||
// Recommandé en version abrégée en raison de l’espace limité du composant
|
||||
tools: {
|
||||
confirm: 'OK',
|
||||
clear: 'Eff.',
|
||||
now: 'Ajd.',
|
||||
reset: 'Réinit.'
|
||||
},
|
||||
rangeOrderPrompt: 'L’heure de fin ne peut pas être antérieure à l’heure de début\nVeuillez recommencer',
|
||||
invalidDatePrompt: 'Date ou heure hors plage valide\n',
|
||||
formatErrorPrompt: 'Format de date invalide\nLe format attendu est :\n{format}\n',
|
||||
autoResetPrompt: 'Il a été réinitialisé pour vous',
|
||||
preview: 'Résultat sélectionné actuel'
|
||||
},
|
||||
layer: {
|
||||
confirm: 'Confirmer',
|
||||
cancel: 'Annuler',
|
||||
defaultTitle: 'Information',
|
||||
prompt: {
|
||||
InputLengthPrompt: 'Maximum {length} caractères'
|
||||
},
|
||||
photos: {
|
||||
noData: 'Aucune image',
|
||||
tools: {
|
||||
rotate: 'Faire pivoter',
|
||||
scaleX: 'Inverser horizontalement',
|
||||
zoomIn: 'Agrandir',
|
||||
zoomOut: 'Réduire',
|
||||
reset: 'Réinitialiser',
|
||||
close: 'Fermer'
|
||||
},
|
||||
viewPicture: 'Voir l’image originale',
|
||||
urlError: {
|
||||
prompt: 'L’adresse de l’image est invalide,\nContinuer avec la suivante ?',
|
||||
confirm: 'Suivante',
|
||||
cancel: 'Annuler'
|
||||
}
|
||||
}
|
||||
},
|
||||
laypage: {
|
||||
prev: 'Page précédente',
|
||||
next: 'Page suivante',
|
||||
first: 'Première',
|
||||
last: 'Dernière',
|
||||
total: 'Total {total} éléments',
|
||||
pagesize: 'éléments/page',
|
||||
goto: 'Aller à',
|
||||
page: 'page',
|
||||
confirm: 'Confirmer'
|
||||
},
|
||||
table: {
|
||||
sort: {
|
||||
asc: 'Croissant',
|
||||
desc: 'Décroissant'
|
||||
},
|
||||
noData: 'Aucune donnée',
|
||||
tools: {
|
||||
filter: {
|
||||
title: 'Filtrer les colonnes'
|
||||
},
|
||||
export: {
|
||||
title: 'Exporter',
|
||||
noDataPrompt: 'Aucune donnée à exporter',
|
||||
compatPrompt: 'L’exportation n’est pas supportée par IE, veuillez utiliser Chrome ou un autre navigateur moderne',
|
||||
csvText: 'Exporter au format CSV'
|
||||
},
|
||||
print: {
|
||||
title: 'Imprimer',
|
||||
noDataPrompt: 'Aucune donnée à imprimer'
|
||||
}
|
||||
},
|
||||
dataFormatError: 'Les données retournées sont invalides. Le code de réussite attendu est : "{statusName}": {statusCode}',
|
||||
xhrError: 'Erreur de requête : {msg}'
|
||||
},
|
||||
transfer: {
|
||||
noData: 'Aucune donnée',
|
||||
noMatch: 'Aucune correspondance',
|
||||
title: ['Liste 1', 'Liste 2'],
|
||||
searchPlaceholder: 'Recherche par mot-clé'
|
||||
},
|
||||
tree: {
|
||||
defaultNodeName: 'Sans nom',
|
||||
noData: 'Aucune donnée',
|
||||
deleteNodePrompt: 'Confirmer la suppression du nœud "{name}" ?'
|
||||
},
|
||||
upload: {
|
||||
fileType: {
|
||||
file: 'Fichier',
|
||||
image: 'Image',
|
||||
video: 'Vidéo',
|
||||
audio: 'Audio'
|
||||
},
|
||||
validateMessages: {
|
||||
fileExtensionError: 'Le {fileType} sélectionné contient un format non supporté',
|
||||
filesOverLengthLimit: 'Nombre maximum de fichiers : {length}',
|
||||
currentFilesLength: 'Vous avez sélectionné {length} fichiers',
|
||||
fileOverSizeLimit: 'La taille du fichier ne doit pas dépasser {size}'
|
||||
},
|
||||
chooseText: '{length} fichiers'
|
||||
},
|
||||
util: {
|
||||
timeAgo: {
|
||||
days: 'il y a {days} jours',
|
||||
hours: 'il y a {hours} heures',
|
||||
minutes: 'il y a {minutes} minutes',
|
||||
future: 'Futur',
|
||||
justNow: 'À l’instant'
|
||||
},
|
||||
toDateString: {
|
||||
meridiem: function(hours, minutes){
|
||||
return hours < 12 ? 'AM' : 'PM';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
177
examples/i18n/zh-HK.js
Normal file
177
examples/i18n/zh-HK.js
Normal file
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* 繁體中文 (zh-HK)
|
||||
*/
|
||||
|
||||
export default {
|
||||
code: {
|
||||
copy: '複製代碼',
|
||||
copied: '已複製',
|
||||
copyError: '複製失敗',
|
||||
maximize: '最大化顯示',
|
||||
restore: '還原顯示',
|
||||
preview: '在新視窗預覽'
|
||||
},
|
||||
colorpicker: {
|
||||
clear: '清除',
|
||||
confirm: '確定'
|
||||
},
|
||||
dropdown: {
|
||||
noData: '暫無資料'
|
||||
},
|
||||
flow: {
|
||||
loadMore: '載入更多',
|
||||
noMore: '沒有更多了'
|
||||
},
|
||||
form: {
|
||||
select: {
|
||||
noData: '暫無資料',
|
||||
noMatch: '無匹配資料',
|
||||
placeholder: '請選擇'
|
||||
},
|
||||
validateMessages: {
|
||||
required: '必填項不能為空',
|
||||
phone: '手機號碼格式不正確',
|
||||
email: '電郵格式不正確',
|
||||
url: '連結格式不正確',
|
||||
number: '只能填寫數字',
|
||||
date: '日期格式不正確',
|
||||
identity: '身份證號碼格式不正確'
|
||||
},
|
||||
verifyErrorPromptTitle: '提示'
|
||||
},
|
||||
laydate: {
|
||||
months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
|
||||
weeks: ['日', '一', '二', '三', '四', '五', '六'],
|
||||
time: ['時', '分', '秒'],
|
||||
literal: {
|
||||
year: '年'
|
||||
},
|
||||
selectDate: '選擇日期',
|
||||
selectTime: '選擇時間',
|
||||
startTime: '開始時間',
|
||||
endTime: '結束時間',
|
||||
tools: {
|
||||
confirm: '確定',
|
||||
clear: '清除',
|
||||
now: '現在',
|
||||
reset: '重設'
|
||||
},
|
||||
rangeOrderPrompt: '結束時間不能早於開始時間\n請重新選擇',
|
||||
invalidDatePrompt: '不在有效日期或時間範圍內\n',
|
||||
formatErrorPrompt: '日期格式不合法\n必須遵循:\n{format}\n',
|
||||
autoResetPrompt: '已自動重設',
|
||||
preview: '當前選中的結果'
|
||||
},
|
||||
layer: {
|
||||
confirm: '確定',
|
||||
cancel: '取消',
|
||||
defaultTitle: '資訊',
|
||||
prompt: {
|
||||
InputLengthPrompt: '最多輸入 {length} 個字符'
|
||||
},
|
||||
photos: {
|
||||
noData: '沒有圖片',
|
||||
tools:{
|
||||
rotate: '旋轉',
|
||||
scaleX: '水平變換',
|
||||
zoomIn: '放大',
|
||||
zoomOut: '縮小',
|
||||
reset: '還原',
|
||||
close: '關閉'
|
||||
},
|
||||
viewPicture: '查看原圖',
|
||||
urlError: {
|
||||
prompt: '當前圖片地址異常,\n是否繼續查看下一張?',
|
||||
confirm: '下一張',
|
||||
cancel: '不看了'
|
||||
}
|
||||
}
|
||||
},
|
||||
laypage: {
|
||||
prev: '上一頁',
|
||||
next: '下一頁',
|
||||
first: '首頁',
|
||||
last: '尾頁',
|
||||
total: '共 {total} 條',
|
||||
pagesize: '條/頁',
|
||||
goto: '到第',
|
||||
page: '頁',
|
||||
confirm: '確定'
|
||||
},
|
||||
table: {
|
||||
sort: {
|
||||
asc: '升序',
|
||||
desc: '降序'
|
||||
},
|
||||
noData: '無資料',
|
||||
tools:{
|
||||
filter: {
|
||||
title: '篩選列'
|
||||
},
|
||||
export: {
|
||||
title: '匯出',
|
||||
noDataPrompt: '當前表格無資料',
|
||||
compatPrompt: '匯出功能不支援 IE,請用 Chrome 等高級瀏覽器匯出',
|
||||
csvText : '匯出 CSV 檔案'
|
||||
},
|
||||
print: {
|
||||
title: '列印',
|
||||
noDataPrompt: '當前表格無資料'
|
||||
}
|
||||
},
|
||||
dataFormatError: '返回的資料不符合規範,正確的成功狀態碼應為:"{statusName}": {statusCode}',
|
||||
xhrError: '請求異常,錯誤提示:{msg}'
|
||||
},
|
||||
transfer: {
|
||||
noData: '無資料',
|
||||
noMatch: '無匹配資料',
|
||||
title: ['列表一', '列表二'],
|
||||
searchPlaceholder: '關鍵詞搜尋'
|
||||
},
|
||||
tree: {
|
||||
defaultNodeName: '未命名',
|
||||
noData: '無資料',
|
||||
deleteNodePrompt: '確認刪除"{name}"節點嗎?'
|
||||
},
|
||||
upload: {
|
||||
fileType: {
|
||||
file: '檔案',
|
||||
image: '圖片',
|
||||
video: '影片',
|
||||
audio: '音訊'
|
||||
},
|
||||
validateMessages: {
|
||||
fileExtensionError: '選擇的{fileType}中包含不支援的格式',
|
||||
filesOverLengthLimit: '同時最多只能上傳: {length} 個檔案',
|
||||
currentFilesLength: '您當前已經選擇了: {length} 個檔案',
|
||||
fileOverSizeLimit: '檔案大小不能超過 {size}'
|
||||
},
|
||||
chooseText: '{length} 個檔案'
|
||||
},
|
||||
util: {
|
||||
timeAgo: {
|
||||
days: '{days} 天前',
|
||||
hours: '{hours} 小時前',
|
||||
minutes: '{minutes} 分鐘前',
|
||||
future: '未來',
|
||||
justNow: '剛剛'
|
||||
},
|
||||
toDateString: {
|
||||
meridiem: function(hours, minutes){
|
||||
var hm = hours * 100 + minutes;
|
||||
if (hm < 500) {
|
||||
return '凌晨';
|
||||
} else if (hm < 800) {
|
||||
return '早上';
|
||||
} else if (hm < 1200) {
|
||||
return '上午';
|
||||
} else if (hm < 1300) {
|
||||
return '中午';
|
||||
} else if (hm < 1900) {
|
||||
return '下午';
|
||||
}
|
||||
return '晚上';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -20,7 +20,7 @@ const config = {
|
||||
{pkg: pkg, js: ';'}
|
||||
],
|
||||
// 全部模块
|
||||
modules: 'lay,laytpl,laypage,laydate,jquery,component,layer,util,dropdown,slider,colorpicker,element,upload,form,table,treeTable,tabs,tree,transfer,carousel,rate,flow,code'
|
||||
modules: 'lay,i18n,laytpl,laypage,laydate,jquery,component,layer,util,dropdown,slider,colorpicker,element,upload,form,table,treeTable,tabs,tree,transfer,carousel,rate,flow,code'
|
||||
};
|
||||
|
||||
// 获取参数
|
||||
|
||||
@@ -46,6 +46,7 @@ html #layuicss-laydate{display: none; position: absolute; width: 1989px;}
|
||||
.layui-laydate-header i.laydate-prev-m{left: 45px;}
|
||||
.layui-laydate-header i.laydate-next-y{right: 15px;}
|
||||
.layui-laydate-header i.laydate-next-m{right: 45px;}
|
||||
.laydate-time-show .layui-laydate-header{padding-left: 10px; padding-right: 10px;}
|
||||
.laydate-set-ym{width: 100%; text-align: center; box-sizing: border-box; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;}
|
||||
.laydate-set-ym span{padding: 0 10px; cursor: pointer;}
|
||||
.laydate-time-text{cursor: default !important;}
|
||||
@@ -95,7 +96,7 @@ html #layuicss-laydate{display: none; position: absolute; width: 1989px;}
|
||||
.layui-laydate .laydate-time-list-hide-2 ol li{padding-left: 117px;}
|
||||
|
||||
/* 提示 */
|
||||
.layui-laydate-hint{position: absolute; top: 115px; left: 50%; width: 250px; margin-left: -125px; line-height: 20px; padding: 15px; text-align: center; font-size: 12px; color: #FF5722;}
|
||||
.layui-laydate-hint{position: absolute; top: 115px; left: 50%; width: 250px; margin-left: -125px; line-height: 20px; padding: 15px; text-align: center; font-size: 12px; color: #FF5722;white-space: pre-line;}
|
||||
|
||||
|
||||
/* 双日历 */
|
||||
|
||||
25
src/layui.js
25
src/layui.js
@@ -55,8 +55,25 @@
|
||||
// 异常提示
|
||||
var error = function(msg, type) {
|
||||
type = type || 'log';
|
||||
window.console && console[type] && console[type]('layui error hint: ' + msg);
|
||||
msg = '[Layui warn]: ' + msg;
|
||||
|
||||
if (window.console) {
|
||||
console[type] ? console[type](msg) : console.log(msg);
|
||||
}
|
||||
};
|
||||
var warned = Object.create(null);
|
||||
|
||||
var errorOnce = function (msg, type) {
|
||||
if(warned._size && warned._size > 100){
|
||||
warned = Object.create(null);
|
||||
warned._size = 0;
|
||||
}
|
||||
if (!warned[msg]) {
|
||||
warned[msg] = true;
|
||||
warned._size = (warned._size || 0) + 1;
|
||||
error(msg, type)
|
||||
}
|
||||
}
|
||||
|
||||
// 内置模块
|
||||
var builtinModules = config.builtin = {
|
||||
@@ -83,6 +100,7 @@
|
||||
code: 'code', // 代码修饰器
|
||||
jquery: 'jquery', // DOM 库(第三方)
|
||||
component: 'component', // 组件构建器
|
||||
i18n: 'i18n', // 国际化
|
||||
|
||||
all: 'all',
|
||||
'layui.all': 'layui.all' // 聚合标识(功能性的,非真实模块)
|
||||
@@ -161,7 +179,7 @@
|
||||
|
||||
/**
|
||||
* 全局配置
|
||||
* @param {Object} options
|
||||
* @param {Object} options - 配置对象
|
||||
*/
|
||||
Class.prototype.config = function(options) {
|
||||
Object.assign(config, options);
|
||||
@@ -710,7 +728,8 @@
|
||||
// 提示
|
||||
Class.prototype.hint = function() {
|
||||
return {
|
||||
error: error
|
||||
error: error,
|
||||
errorOnce: errorOnce
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Code 预览组件
|
||||
*/
|
||||
|
||||
layui.define(['lay', 'util', 'element', 'tabs', 'form'], function(exports){
|
||||
layui.define(['lay', 'i18n', 'util', 'element', 'tabs', 'form'], function(exports) {
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
@@ -13,6 +13,7 @@ layui.define(['lay', 'util', 'element', 'tabs', 'form'], function(exports){
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
var hint = layui.hint();
|
||||
var i18n = layui.i18n;
|
||||
|
||||
// 常量
|
||||
var CONST = {
|
||||
@@ -201,7 +202,7 @@ layui.define(['lay', 'util', 'element', 'tabs', 'form'], function(exports){
|
||||
var tools = {
|
||||
copy: {
|
||||
className: 'file-b',
|
||||
title: ['复制代码'],
|
||||
title: [i18n.$t('code.copy')],
|
||||
event: function(obj){
|
||||
var code = util.unescape(finalCode(options.code));
|
||||
var hasOnCopy = typeof options.onCopy === 'function';
|
||||
@@ -215,14 +216,14 @@ layui.define(['lay', 'util', 'element', 'tabs', 'form'], function(exports){
|
||||
if(ret === false) return;
|
||||
}
|
||||
|
||||
layer.msg('已复制', {icon: 1});
|
||||
layer.msg(i18n.$t('code.copied'), {icon: 1});
|
||||
},
|
||||
error: function() {
|
||||
if(hasOnCopy){
|
||||
var ret = options.onCopy(code, false);
|
||||
if(ret === false) return;
|
||||
}
|
||||
layer.msg('复制失败', {icon: 2});
|
||||
layer.msg(i18n.$t('code.copyError'), {icon: 2});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -277,7 +278,7 @@ layui.define(['lay', 'util', 'element', 'tabs', 'form'], function(exports){
|
||||
$.extend(tools, {
|
||||
'full': {
|
||||
className: 'screen-full',
|
||||
title: ['最大化显示', '还原显示'],
|
||||
title: [i18n.$t('code.maximize'), i18n.$t('code.restore')],
|
||||
event: function(obj){
|
||||
var el = obj.elem;
|
||||
var elemView = el.closest('.'+ CONST.ELEM_PREVIEW);
|
||||
@@ -302,7 +303,7 @@ layui.define(['lay', 'util', 'element', 'tabs', 'form'], function(exports){
|
||||
},
|
||||
'window': {
|
||||
className: 'release',
|
||||
title: ['在新窗口预览'],
|
||||
title: [i18n.$t('code.preview')],
|
||||
event: function(obj){
|
||||
util.openWin({
|
||||
content: finalCode(options.code)
|
||||
@@ -561,9 +562,11 @@ layui.define(['lay', 'util', 'element', 'tabs', 'form'], function(exports){
|
||||
|
||||
// 若开启复制,且未开启预览,则单独生成复制图标
|
||||
if(options.copy && !options.preview){
|
||||
var copyElem = $(['<span class="layui-code-copy">',
|
||||
'<i class="layui-icon layui-icon-file-b" title="复制"></i>',
|
||||
'</span>'].join(''));
|
||||
var copyElem = $([
|
||||
'<span class="layui-code-copy">',
|
||||
'<i class="layui-icon layui-icon-file-b" title="' + i18n.$t('code.copy') + '"></i>',
|
||||
'</span>'
|
||||
].join(''));
|
||||
|
||||
// 点击复制
|
||||
copyElem.on('click', function(){
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
* 颜色选择组件
|
||||
*/
|
||||
|
||||
layui.define(['jquery', 'lay'], function(exports) {
|
||||
layui.define(['i18n', 'jquery', 'lay'], function(exports) {
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
var lay = layui.lay;
|
||||
var hint = layui.hint();
|
||||
var i18n = layui.i18n;
|
||||
var device = layui.device();
|
||||
var clickOrMousedown = (device.mobile ? 'click' : 'mousedown');
|
||||
|
||||
@@ -284,9 +285,9 @@ layui.define(['jquery', 'lay'], function(exports) {
|
||||
,'<div class="layui-inline">'
|
||||
,'<input type="text" class="layui-input">'
|
||||
,'</div>'
|
||||
,'<div class="layui-btn-container">'
|
||||
,'<button class="layui-btn layui-btn-primary layui-btn-sm" colorpicker-events="clear">清空</button>'
|
||||
,'<button class="layui-btn layui-btn-sm" colorpicker-events="confirm">确定</button>'
|
||||
,'<div class="layui-btn-group">'
|
||||
,'<button style="border-radius: 0" class="layui-btn layui-btn-primary layui-btn-sm" colorpicker-events="clear">' + i18n.$t('colorpicker.clear') + '</button>'
|
||||
,'<button style="border-radius: 0; border-left: 0" class="layui-btn layui-btn-primary layui-btn-sm" colorpicker-events="confirm">' + i18n.$t('colorpicker.confirm') + '</button>'
|
||||
,'</div'
|
||||
,'</div>'
|
||||
,'</div>'].join(''))
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
* 下拉菜单组件
|
||||
*/
|
||||
|
||||
layui.define(['jquery', 'laytpl', 'lay', 'util'], function(exports) {
|
||||
layui.define(['i18n', 'jquery', 'laytpl', 'lay', 'util'], function(exports) {
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
var laytpl = layui.laytpl;
|
||||
var util = layui.util;
|
||||
var hint = layui.hint();
|
||||
var i18n = layui.i18n;
|
||||
var device = layui.device();
|
||||
var clickOrMousedown = (device.mobile ? 'touchstart' : 'mousedown');
|
||||
|
||||
@@ -181,7 +182,7 @@ layui.define(['jquery', 'laytpl', 'lay', 'util'], function(exports) {
|
||||
if(options.data.length > 0 ){
|
||||
eachItemView(elemUl, options.data)
|
||||
} else {
|
||||
elemUl.html('<li class="layui-menu-item-none">暂无数据</li>');
|
||||
elemUl.html('<li class="layui-menu-item-none">' + i18n.$t('dropdown.noData') + '</li>');
|
||||
}
|
||||
return elemUl;
|
||||
};
|
||||
@@ -569,7 +570,7 @@ layui.define(['jquery', 'laytpl', 'lay', 'util'], function(exports) {
|
||||
that.remove();
|
||||
}, lay.passiveSupported ? { passive: false} : false);
|
||||
|
||||
// onClickOutside 检测 iframe
|
||||
// onClickOutside 检测 iframe
|
||||
_WIN.on('blur', function(e){
|
||||
if(!dropdown.thisId) return;
|
||||
var that = thisModule.getThis(dropdown.thisId)
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
*/
|
||||
|
||||
|
||||
layui.define('jquery', function(exports) {
|
||||
layui.define(['i18n', 'jquery'], function(exports) {
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
var i18n = layui.i18n;
|
||||
var Flow = function(options) {};
|
||||
var ELEM_MORE = 'layui-flow-more';
|
||||
var ELEM_LOAD = '<i class="layui-anim layui-anim-rotate layui-anim-loop layui-icon "></i>';
|
||||
@@ -20,8 +21,8 @@ layui.define('jquery', function(exports) {
|
||||
var scrollElem = $(options.scrollElem || document); // 滚动条所在元素
|
||||
var threshold = 'mb' in options ? options.mb : 50; // 临界距离
|
||||
var isAuto = 'isAuto' in options ? options.isAuto : true; // 否自动滚动加载
|
||||
var moreText = options.moreText || "加载更多"; // 手动加载时,加载更多按钮文案
|
||||
var end = options.end || '没有更多了'; // “末页”显示文案
|
||||
var moreText = options.moreText || i18n.$t('flow.loadMore'); // 手动加载时,加载更多按钮文案
|
||||
var end = options.end || i18n.$t('flow.noMore'); // “末页”显示文案
|
||||
var direction = options.direction || 'bottom';
|
||||
var isTop = direction === 'top';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* form 表单组件
|
||||
*/
|
||||
|
||||
layui.define(['lay', 'layer', 'util'], function(exports){
|
||||
layui.define(['lay', 'i18n', 'layer', 'util'], function(exports){
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
@@ -10,6 +10,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
||||
var util = layui.util;
|
||||
var hint = layui.hint();
|
||||
var device = layui.device();
|
||||
var i18n = layui.i18n;
|
||||
|
||||
var MOD_NAME = 'form';
|
||||
var ELEM = '.layui-form';
|
||||
@@ -31,42 +32,42 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
||||
verify: {
|
||||
required: function(value) {
|
||||
if (!/[\S]+/.test(value) || value === undefined || value === null) {
|
||||
return '必填项不能为空';
|
||||
return i18n.$t('form.validateMessages.required');
|
||||
}
|
||||
},
|
||||
phone: function(value) {
|
||||
var EXP = /^1\d{10}$/;
|
||||
if (value && !EXP.test(value)) {
|
||||
return '手机号格式不正确';
|
||||
return i18n.$t('form.validateMessages.phone');
|
||||
}
|
||||
},
|
||||
email: function(value) {
|
||||
var EXP = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
|
||||
if (value && !EXP.test(value)) {
|
||||
return '邮箱格式不正确';
|
||||
return i18n.$t('form.validateMessages.email');
|
||||
}
|
||||
},
|
||||
url: function(value) {
|
||||
var EXP = /^(#|(http(s?)):\/\/|\/\/)[^\s]+\.[^\s]+$/;
|
||||
if (value && !EXP.test(value)) {
|
||||
return '链接格式不正确';
|
||||
return i18n.$t('form.validateMessages.url');
|
||||
}
|
||||
},
|
||||
number: function(value){
|
||||
if (value && isNaN(value)) {
|
||||
return '只能填写数字';
|
||||
return i18n.$t('form.validateMessages.number');
|
||||
}
|
||||
},
|
||||
date: function(value){
|
||||
var EXP = /^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/;
|
||||
if (value && !EXP.test(value)) {
|
||||
return '日期格式不正确';
|
||||
return i18n.$t('form.validateMessages.date');
|
||||
}
|
||||
},
|
||||
identity: function(value) {
|
||||
var EXP = /(^\d{15}$)|(^\d{17}(x|X|\d)$)/;
|
||||
if (value && !EXP.test(value)) {
|
||||
return '身份证号格式不正确';
|
||||
return i18n.$t('form.validateMessages.identity');
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -466,7 +467,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
||||
|
||||
// 下拉选择框
|
||||
,select: function(elem){
|
||||
var TIPS = '请选择';
|
||||
var TIPS = i18n.$t('form.select.placeholder');
|
||||
var CLASS = 'layui-form-select';
|
||||
var TITLE = 'layui-select-title';
|
||||
var NONE = 'layui-select-none';
|
||||
@@ -765,7 +766,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
||||
}
|
||||
}else{
|
||||
if(none){
|
||||
dl.find('.'+NONE)[0] || dl.append('<p class="'+ NONE +'">无匹配项</p>');
|
||||
dl.find('.'+NONE)[0] || dl.append('<p class="'+ NONE + '">' + i18n.$t('form.select.noMatch') + '</p>');
|
||||
} else {
|
||||
dl.find('.'+NONE).remove();
|
||||
}
|
||||
@@ -956,7 +957,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
||||
}
|
||||
});
|
||||
if (arr.length === 0) {
|
||||
arr.push('<dd lay-value="" class="'+ DISABLED +'">None</dd>');
|
||||
arr.push('<dd lay-value="" class="'+ DISABLED + '">' + i18n.$t('form.select.noData') + '</dd>');
|
||||
}
|
||||
return arr.join('');
|
||||
}();
|
||||
@@ -1258,7 +1259,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
||||
}
|
||||
} else {
|
||||
type ? (
|
||||
items[type] ? items[type]() : hint.error('不支持的 "'+ type + '" 表单渲染')
|
||||
items[type] ? items[type]() : hint.error('[form] "' + type + '" is an unsupported form element type')
|
||||
) : renderItem();
|
||||
}
|
||||
return that;
|
||||
@@ -1384,7 +1385,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
||||
return othis;
|
||||
}(), {tips: 1});
|
||||
} else if(verType === 'alert') {
|
||||
layer.alert(errorText, {title: '提示', shadeClose: true});
|
||||
layer.alert(errorText, {title: i18n.$t('form.verifyErrorPromptTitle'), shadeClose: true});
|
||||
}
|
||||
// 若返回的为字符或数字,则自动弹出默认提示框;否则由 verify 方法中处理提示
|
||||
else if(/\b(string|number)\b/.test(typeof errorText)) {
|
||||
|
||||
357
src/modules/i18n.js
Normal file
357
src/modules/i18n.js
Normal file
@@ -0,0 +1,357 @@
|
||||
/**
|
||||
* i18n
|
||||
* 国际化
|
||||
*/
|
||||
|
||||
layui.define('lay', function(exports) {
|
||||
'use strict';
|
||||
|
||||
var lay = layui.lay;
|
||||
var hint = layui.hint();
|
||||
|
||||
var MOD_NAME = 'i18n';
|
||||
|
||||
// 识别预先可能定义的指定全局对象
|
||||
var GLOBAL = window.LAYUI_GLOBAL || {};
|
||||
|
||||
// 简体中文
|
||||
var zhCN = {
|
||||
code: {
|
||||
copy: '复制代码',
|
||||
copied: '已复制',
|
||||
copyError: '复制失败',
|
||||
maximize: '最大化显示',
|
||||
restore: '还原显示',
|
||||
preview: '在新窗口预览'
|
||||
},
|
||||
colorpicker: {
|
||||
clear: '清除',
|
||||
confirm: '确定'
|
||||
},
|
||||
dropdown: {
|
||||
noData: '暂无数据'
|
||||
},
|
||||
flow: {
|
||||
loadMore: '加载更多',
|
||||
noMore: '没有更多了'
|
||||
},
|
||||
form: {
|
||||
select: {
|
||||
noData: '暂无数据',
|
||||
noMatch: '无匹配数据',
|
||||
placeholder: '请选择'
|
||||
},
|
||||
validateMessages: {
|
||||
required: '必填项不能为空',
|
||||
phone: '手机号格式不正确',
|
||||
email: '邮箱格式不正确',
|
||||
url: '链接格式不正确',
|
||||
number: '只能填写数字',
|
||||
date: '日期格式不正确',
|
||||
identity: '身份证号格式不正确'
|
||||
},
|
||||
verifyErrorPromptTitle: '提示'
|
||||
},
|
||||
laydate: {
|
||||
months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
|
||||
weeks: ['日', '一', '二', '三', '四', '五', '六'],
|
||||
time: ['时', '分', '秒'],
|
||||
literal: {
|
||||
year: '年'
|
||||
},
|
||||
selectDate: '选择日期',
|
||||
selectTime: '选择时间',
|
||||
startTime: '开始时间',
|
||||
endTime: '结束时间',
|
||||
tools: {
|
||||
confirm: '确定',
|
||||
clear: '清空',
|
||||
now: '现在',
|
||||
reset: '重置'
|
||||
},
|
||||
rangeOrderPrompt: '结束时间不能早于开始时间\n请重新选择',
|
||||
invalidDatePrompt: '不在有效日期或时间范围内\n',
|
||||
formatErrorPrompt: '日期格式不合法\n必须遵循:\n{format}\n',
|
||||
autoResetPrompt: '已自动重置',
|
||||
preview: '当前选中的结果'
|
||||
},
|
||||
layer: {
|
||||
confirm: '确定',
|
||||
cancel: '取消',
|
||||
defaultTitle: '信息',
|
||||
prompt: {
|
||||
InputLengthPrompt: '最多输入 {length} 个字符'
|
||||
},
|
||||
photos: {
|
||||
noData: '没有图片',
|
||||
tools:{
|
||||
rotate: '旋转',
|
||||
scaleX: '水平变换',
|
||||
zoomIn: '放大',
|
||||
zoomOut: '缩小',
|
||||
reset: '还原',
|
||||
close: '关闭'
|
||||
},
|
||||
viewPicture: '查看原图',
|
||||
urlError: {
|
||||
prompt: '当前图片地址异常,\n是否继续查看下一张?',
|
||||
confirm: '下一张',
|
||||
cancel: '不看了'
|
||||
}
|
||||
}
|
||||
},
|
||||
laypage: {
|
||||
prev: '上一页',
|
||||
next: '下一页',
|
||||
first: '首页',
|
||||
last: '尾页',
|
||||
total: '共 {total} 条',
|
||||
pagesize: '条/页',
|
||||
goto: '到第',
|
||||
page: '页',
|
||||
confirm: '确定'
|
||||
},
|
||||
table: {
|
||||
sort: {
|
||||
asc: '升序',
|
||||
desc: '降序'
|
||||
},
|
||||
noData: '暂无数据',
|
||||
tools:{
|
||||
filter: {
|
||||
title: '筛选列'
|
||||
},
|
||||
export: {
|
||||
title: '导出',
|
||||
noDataPrompt: '当前表格无数据',
|
||||
compatPrompt: '导出功能不支持 IE,请用 Chrome 等高级浏览器导出',
|
||||
csvText : '导出 CSV 文件'
|
||||
},
|
||||
print: {
|
||||
title: '打印',
|
||||
noDataPrompt: '当前表格无数据'
|
||||
}
|
||||
},
|
||||
dataFormatError: '返回的数据不符合规范,正确的成功状态码应为:"{statusName}": {statusCode}',
|
||||
xhrError: '请求异常,错误提示:{msg}'
|
||||
},
|
||||
transfer: {
|
||||
noData: '暂无数据',
|
||||
noMatch: '无匹配数据',
|
||||
title: ['列表一', '列表二'],
|
||||
searchPlaceholder: '关键词搜索'
|
||||
},
|
||||
tree: {
|
||||
defaultNodeName: '未命名',
|
||||
noData: '暂无数据',
|
||||
deleteNodePrompt: '确认删除"{name}"节点吗?'
|
||||
},
|
||||
upload: {
|
||||
fileType: {
|
||||
file: '文件',
|
||||
image: '图片',
|
||||
video: '视频',
|
||||
audio: '音频'
|
||||
},
|
||||
validateMessages: {
|
||||
fileExtensionError: '选择的{fileType}中包含不支持的格式',
|
||||
filesOverLengthLimit: '同时最多只能上传: {length} 个文件',
|
||||
currentFilesLength: '当前已经选择了: {length} 个文件',
|
||||
fileOverSizeLimit: '文件大小不能超过 {size}'
|
||||
},
|
||||
chooseText: '{length} 个文件'
|
||||
},
|
||||
util: {
|
||||
timeAgo: {
|
||||
days: '{days} 天前',
|
||||
hours: '{hours} 小时前',
|
||||
minutes: '{minutes} 分钟前',
|
||||
future: '未来',
|
||||
justNow: '刚刚'
|
||||
},
|
||||
toDateString: {
|
||||
// https://www.unicode.org/cldr/charts/47/supplemental/day_periods.html
|
||||
meridiem: function(hours, minutes){
|
||||
var hm = hours * 100 + minutes;
|
||||
if (hm < 500) {
|
||||
return '凌晨';
|
||||
} else if (hm < 800) {
|
||||
return '早上';
|
||||
} else if (hm < 1200) {
|
||||
return '上午';
|
||||
} else if (hm < 1300) {
|
||||
return '中午';
|
||||
} else if (hm < 1900) {
|
||||
return '下午';
|
||||
}
|
||||
return '晚上';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 默认配置
|
||||
var config = lay.extend({
|
||||
locale: 'zh-CN', // 全局内置语言
|
||||
messages: { // 全局国际化消息对象
|
||||
'zh-CN': zhCN
|
||||
}
|
||||
}, GLOBAL.i18n); // 读取全局预设配置,确保打包后的版本初始调用时机
|
||||
|
||||
var OBJECT_REPLACE_REGEX = /\{(\w+)\}/g;
|
||||
|
||||
/**
|
||||
* 获取对象中指定路径的值,类似于 lodash 的 _.get 方法(简易版)
|
||||
* @param {Record<string, any>} obj - 要查找的对象
|
||||
* @param {string} path - 要查找的路径,支持类似 'a[0].b.c' 的格式
|
||||
* @param {any} defaultValue - 若未找到对应值时返回的默认值
|
||||
* @returns {any} - 找到的值或默认值
|
||||
*/
|
||||
function get(obj, path, defaultValue) {
|
||||
// 'a[0].b.c' ==> ['a', '0', 'b', 'c']
|
||||
var casePath = path.replace(/\[(\d+)\]/g, '.$1').split('.');
|
||||
var result = obj;
|
||||
|
||||
for(var i = 0; i < casePath.length; i++) {
|
||||
result = result && result[casePath[i]];
|
||||
if(result === null || result === undefined){
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为纯函数创建具有缓存功能的版本,类似于 lodash 的 _.memoize 方法(简易版)
|
||||
* @template T
|
||||
* @param {(key: string, ...args) => T} fn - 需要缓存的函数,第一个参数为键
|
||||
* @returns {{(key: string, ...args): T, cleanup: () => void}} - 带有缓存的函数
|
||||
*/
|
||||
function memoize(fn){
|
||||
/** @type Record<string, T> */
|
||||
var cache = Object.create(null);
|
||||
|
||||
function cachedFn(key) {
|
||||
var hit = cache[key];
|
||||
return hit || (cache[key] = fn.apply(cache, arguments));
|
||||
}
|
||||
|
||||
cachedFn.cleanup = function() {
|
||||
cache = Object.create(null);
|
||||
}
|
||||
return cachedFn;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对传入的值进行转义处理
|
||||
* 若值为字符串,直接进行转义;若为函数,对函数返回的字符串进行转义;若为数组,对数组中的字符串元素进行转义
|
||||
* @param {any} value - 需要进行转义处理的值
|
||||
* @returns {any} - 转义后的结果
|
||||
*/
|
||||
function escape(value) {
|
||||
if(typeof value === 'string'){
|
||||
value = lay.escape(value);
|
||||
}else if(typeof value === 'function'){
|
||||
var origFn = value;
|
||||
value = function(){
|
||||
var val = origFn.apply(this, arguments)
|
||||
return typeof val === 'string' ? lay.escape(val) : val;
|
||||
}
|
||||
}else if(layui.type(value) === 'array'){
|
||||
value = value.map(function(v){
|
||||
return typeof v === 'string' ? lay.escape(v) : v;
|
||||
});
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
path = pathParts[1];
|
||||
|
||||
var value = get(obj, path, defaultValue);
|
||||
|
||||
if (layui.cache.debug) {
|
||||
var isFallback = defaultValue === value || value === path;
|
||||
var isNotFound = !isDef(value) || isFallback;
|
||||
if (isNotFound) {
|
||||
hint.errorOnce("Not found '" + path + "' key in '" + locale + "' locale messages.", 'warn');
|
||||
}
|
||||
if (isFallback) {
|
||||
hint.errorOnce("Fallback to default message for key: '" + path + "'", 'warn');
|
||||
}
|
||||
}
|
||||
|
||||
return isDef(value) ? value : path;
|
||||
});
|
||||
|
||||
var i18n = {
|
||||
config: config,
|
||||
set: function(options) {
|
||||
lay.extend(config, options);
|
||||
resolveValue.cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据给定的键从国际化消息中获取翻译后的内容
|
||||
* 未文档化的私有方法,仅限内部使用
|
||||
*
|
||||
* @internal
|
||||
* @param {string} keypath 要翻译的键路径
|
||||
* @param {Record<string, any> | any[]} [parameters] 可选的占位符替换参数:
|
||||
* - 对象形式:用于替换 `{key}` 形式的占位符;
|
||||
* - 数组形式:用于替换 `{0}`, `{1}` 等占位符;
|
||||
* @param {{locale: string, default: string}} [options] 翻译选项
|
||||
* @returns {string} 翻译后的文本
|
||||
*
|
||||
* @example 使用对象替换命名占位符
|
||||
* message: {
|
||||
* hello: '{msg} world'
|
||||
* }
|
||||
* i18n.$t('message.hello', { msg: 'Hello' })
|
||||
*
|
||||
* @example 使用数组替换索引占位符
|
||||
* message: {
|
||||
* hello: '{0} world'
|
||||
* }
|
||||
* i18n.$t('message.hello', ['Hello'])
|
||||
*/
|
||||
i18n.translation = function(keypath, parameters, options) {
|
||||
var locale = (options && options.locale) || config.locale;
|
||||
var i18nMessages = config.messages[locale];
|
||||
var namespace = locale + ':';
|
||||
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');
|
||||
}
|
||||
|
||||
var result = resolveValue(namespace + keypath, i18nMessages, fallbackMessage);
|
||||
|
||||
// 替换占位符
|
||||
if (typeof result === 'string' && parameters) {
|
||||
// 第二个参数为对象或数组,替换占位符 {key} 或 {0}, {1}...
|
||||
result = result.replace(OBJECT_REPLACE_REGEX, function(match, key) {
|
||||
return parameters[key] !== undefined ? parameters[key] : match;
|
||||
});
|
||||
}
|
||||
|
||||
return escape(result);
|
||||
};
|
||||
|
||||
/**
|
||||
* i18n.translation 的别名,用于简化代码书写,未文档化仅限内部使用
|
||||
*/
|
||||
i18n.$t = i18n.translation;
|
||||
|
||||
exports(MOD_NAME, i18n);
|
||||
});
|
||||
@@ -796,10 +796,46 @@
|
||||
};
|
||||
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
/**
|
||||
* 检查对象是否具有指定的属性
|
||||
* @param {Record<string, any>} obj 要检查的对象
|
||||
* @param {string} prop 要检查的属性名
|
||||
* @returns {boolean} 如果对象具有指定的属性,则为 true;否则为 false
|
||||
*/
|
||||
lay.hasOwn = function(obj, prop){
|
||||
return hasOwnProperty.call(obj, prop);
|
||||
};
|
||||
|
||||
/**
|
||||
* 转义 HTML 字符串中的特殊字符
|
||||
* @param {string} html 要转义的 HTML 字符串
|
||||
* @returns {string} 转义后的 HTML 字符串
|
||||
*/
|
||||
lay.escape = function (html) {
|
||||
var exp = /[<"'>]|&(?=#?[a-zA-Z0-9]+)/g;
|
||||
if (html === undefined || html === null) return '';
|
||||
|
||||
html += '';
|
||||
if (!exp.test(html)) return html;
|
||||
|
||||
return html.replace(/&(?=#?[a-zA-Z0-9]+;?)/g, '&')
|
||||
.replace(/</g, '<').replace(/>/g, '>')
|
||||
.replace(/'/g, ''').replace(/"/g, '"');
|
||||
};
|
||||
|
||||
/**
|
||||
* 还原转义的 HTML 字符串中的特殊字符
|
||||
* @param {string} html 要还原转义的 HTML 字符串
|
||||
* @returns {string} 还原转义后的 HTML 字符串
|
||||
*/
|
||||
lay.unescape = function (html) {
|
||||
if (html === undefined || html === null) return '';
|
||||
|
||||
return String(html).replace(/\"/g, '"').replace(/\'/g, '\'')
|
||||
.replace(/\>/g, '>').replace(/\</g, '<')
|
||||
.replace(/\&/g, '&');
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* lay 元素操作
|
||||
|
||||
@@ -1,39 +1,59 @@
|
||||
/** laydate 日期与时间控件 | MIT Licensed */
|
||||
// @ts-expect-error
|
||||
(function(window, document) {
|
||||
/**
|
||||
* laydate
|
||||
* 日期与时间组件
|
||||
*/
|
||||
|
||||
layui.define(['lay', 'i18n'], function(exports) {
|
||||
"use strict";
|
||||
|
||||
var isLayui = window.layui && layui.define;
|
||||
var ready = {
|
||||
getPath: window.lay && lay.getPath ? lay.getPath : '',
|
||||
|
||||
// 载入 CSS 依赖
|
||||
link: function (href, fn, cssname) {
|
||||
// 未设置路径,则不主动加载 css
|
||||
if (!laydate.path) return;
|
||||
|
||||
// 加载 css
|
||||
if (window.lay && lay.layui) {
|
||||
lay.layui.link(laydate.path + href, fn, cssname);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 识别预先可能定义的指定全局对象
|
||||
var GLOBAL = window.LAYUI_GLOBAL || {};
|
||||
var lay = layui.lay;
|
||||
var i18n = layui.i18n;
|
||||
|
||||
// 模块名
|
||||
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;
|
||||
}
|
||||
|
||||
var result = '';
|
||||
for (var 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 = {
|
||||
v: '5.6.0', // layDate 版本号
|
||||
v: '5.7.0', // layDate 版本号
|
||||
config: {
|
||||
weekStart: 0 // 默认周日一周的开始
|
||||
}, // 全局配置项
|
||||
index: window.laydate && window.laydate.v ? 100000 : 0,
|
||||
path: GLOBAL.laydate_dir || ready.getPath,
|
||||
|
||||
// 设置全局项
|
||||
set: function (options) {
|
||||
@@ -45,14 +65,14 @@
|
||||
// 主体 CSS 等待事件
|
||||
ready: function (callback) {
|
||||
var cssname = 'laydate';
|
||||
var ver = '';
|
||||
var path = (isLayui ? 'modules/' : '') + 'laydate.css?v=' + laydate.v + ver;
|
||||
var path = 'modules/laydate.css?v=' + laydate.v;
|
||||
|
||||
isLayui ? (
|
||||
layui['layui.all'] ?
|
||||
(typeof callback === 'function' && callback()) :
|
||||
layui.addcss(path, callback, cssname)
|
||||
) : ready.link(path, callback, cssname);
|
||||
// 打包版直接执行回调函数
|
||||
if (layui['layui.all']) {
|
||||
typeof callback === 'function' && callback();
|
||||
} else {
|
||||
layui.addcss(path, callback, cssname);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -124,6 +144,27 @@
|
||||
// 初始化属性
|
||||
options = lay.extend(that.config, lay.options(elem[0])); // 继承节点上的属性
|
||||
|
||||
// 更新 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));
|
||||
@@ -164,76 +205,127 @@
|
||||
|
||||
// 默认配置
|
||||
Class.prototype.config = {
|
||||
type: 'date' //控件类型,支持:year/month/date/time/datetime
|
||||
,range: false //是否开启范围选择,即双控件
|
||||
,format: 'yyyy-MM-dd' //默认日期格式
|
||||
,value: null //默认日期,支持传入new Date(),或者符合format参数设定的日期格式字符
|
||||
,isInitValue: true //用于控制是否自动向元素填充初始值(需配合 value 参数使用)
|
||||
,min: '1900-1-1' //有效最小日期,年月日必须用“-”分割,时分秒必须用“:”分割。注意:它并不是遵循 format 设定的格式。
|
||||
,max: '2099-12-31' //有效最大日期,同上
|
||||
,trigger: 'click' //呼出控件的事件
|
||||
,show: false //是否直接显示,如果设置 true,则默认直接显示控件
|
||||
,showBottom: true //是否显示底部栏
|
||||
,isPreview: true //是否显示值预览
|
||||
,btns: ['clear', 'now', 'confirm'] //右下角显示的按钮,会按照数组顺序排列
|
||||
,lang: 'cn' //语言,只支持cn/en,即中文和英文
|
||||
,theme: 'default' //主题
|
||||
,position: null //控件定位方式定位, 默认absolute,支持:fixed/absolute/static
|
||||
,calendar: false //是否开启公历重要节日,仅支持中文版
|
||||
,mark: {} //日期备注,如重要事件或活动标记
|
||||
,holidays: null // 标注法定节假日或补假上班
|
||||
,zIndex: null //控件层叠顺序
|
||||
,done: null //控件选择完毕后的回调,点击清空/现在/确定也均会触发
|
||||
,change: null //日期时间改变后的回调
|
||||
,autoConfirm: true //是否自动确认(日期|年份|月份选择器非range下是否自动确认)
|
||||
,shade: 0
|
||||
type: 'date', // 控件类型,支持:year/month/date/time/datetime
|
||||
range: false, // 是否开启范围选择,即双控件
|
||||
format: 'yyyy-MM-dd', // 默认日期格式
|
||||
value: null, // 默认日期,支持传入new Date(),或者符合format参数设定的日期格式字符
|
||||
isInitValue: true, // 用于控制是否自动向元素填充初始值(需配合 value 参数使用)
|
||||
min: '1900-1-1', // 有效最小日期,年月日必须用“-”分割,时分秒必须用“:”分割。注意:它并不是遵循 format 设定的格式。
|
||||
max: '2099-12-31', // 有效最大日期,同上
|
||||
trigger: 'click', // 呼出控件的事件
|
||||
show: false, // 是否直接显示,如果设置 true,则默认直接显示控件
|
||||
showBottom: true, // 是否显示底部栏
|
||||
isPreview: true, // 是否显示值预览
|
||||
btns: ['clear', 'now', 'confirm'], // 右下角显示的按钮,会按照数组顺序排列
|
||||
// 为实现 lang 选项就近生效,去除此处的默认值,$t 设置了英文回退值
|
||||
lang: '', // 语言,只支持 cn/en,即中文和英文
|
||||
theme: 'default', // 主题
|
||||
position: null, // 控件定位方式定位, 默认absolute,支持:fixed/absolute/static
|
||||
calendar: false, // 是否开启公历重要节日,仅支持中文版
|
||||
mark: {}, // 日期备注,如重要事件或活动标记
|
||||
holidays: null, // 标注法定节假日或补假上班
|
||||
zIndex: null, // 控件层叠顺序
|
||||
done: null, // 控件选择完毕后的回调,点击清空/现在/确定也均会触发
|
||||
change: null, // 日期时间改变后的回调
|
||||
autoConfirm: true, // 是否自动确认(日期|年份|月份选择器非range下是否自动确认)
|
||||
shade: 0
|
||||
};
|
||||
|
||||
//多语言
|
||||
Class.prototype.lang = function(){
|
||||
var that = this
|
||||
,options = that.config
|
||||
,text = {
|
||||
cn: {
|
||||
weeks: ['日', '一', '二', '三', '四', '五', '六']
|
||||
,time: ['时', '分', '秒']
|
||||
,timeTips: '选择时间'
|
||||
,startTime: '开始时间'
|
||||
,endTime: '结束时间'
|
||||
,dateTips: '返回日期'
|
||||
,month: ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二']
|
||||
,tools: {
|
||||
confirm: '确定'
|
||||
,clear: '清空'
|
||||
,now: '现在'
|
||||
}
|
||||
,timeout: '结束时间不能早于开始时间<br>请重新选择'
|
||||
,invalidDate: '不在有效日期或时间范围内'
|
||||
,formatError: ['日期格式不合法<br>必须遵循下述格式:<br>', '<br>已为你重置']
|
||||
,preview: '当前选中的结果'
|
||||
}
|
||||
,en: {
|
||||
weeks: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']
|
||||
,time: ['Hours', 'Minutes', 'Seconds']
|
||||
,timeTips: 'Select Time'
|
||||
,startTime: 'Start Time'
|
||||
,endTime: 'End Time'
|
||||
,dateTips: 'Select Date'
|
||||
,month: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||
,tools: {
|
||||
confirm: 'Confirm'
|
||||
,clear: 'Clear'
|
||||
,now: 'Now'
|
||||
}
|
||||
,timeout: 'End time cannot be less than start Time<br>Please re-select'
|
||||
,invalidDate: 'Invalid date'
|
||||
,formatError: ['The date format error<br>Must be followed:<br>', '<br>It has been reset']
|
||||
,preview: 'The selected result'
|
||||
}
|
||||
};
|
||||
return text[options.lang] || text['cn'];
|
||||
};
|
||||
Class.prototype.getI18nMessages = function () {
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
var locale = i18n.config.locale;
|
||||
|
||||
// 纠正旧版「简体中文」语言码
|
||||
if (options.lang === 'cn') {
|
||||
options.lang = zhCN;
|
||||
}else if(!options.lang){
|
||||
options.lang = i18n.config.locale;
|
||||
}
|
||||
locale = options.lang;
|
||||
|
||||
return {
|
||||
months: i18n.$t('laydate.months', null, {
|
||||
locale: locale,
|
||||
default: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||
}),
|
||||
weeks: i18n.$t('laydate.weeks', null, {
|
||||
locale: locale,
|
||||
default: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']
|
||||
}),
|
||||
time: i18n.$t('laydate.time', null, {
|
||||
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'
|
||||
}),
|
||||
selectTime: i18n.$t('laydate.selectTime', null, {
|
||||
locale: locale,
|
||||
default: 'Select Time'
|
||||
}),
|
||||
startTime: i18n.$t('laydate.startTime', null, {
|
||||
locale: locale,
|
||||
default: 'Start Time'
|
||||
}),
|
||||
endTime: i18n.$t('laydate.endTime', null, {
|
||||
locale: locale,
|
||||
default: 'End Time'
|
||||
}),
|
||||
tools: {
|
||||
confirm: i18n.$t('laydate.tools.confirm', null, {
|
||||
locale: locale,
|
||||
default: 'Confirm'
|
||||
}),
|
||||
clear: i18n.$t('laydate.tools.clear', null, {
|
||||
locale: locale,
|
||||
default: 'Clear'
|
||||
}),
|
||||
now: i18n.$t('laydate.tools.now', null, {
|
||||
locale: locale,
|
||||
default: 'Now'
|
||||
}),
|
||||
reset: i18n.$t('laydate.tools.reset', null, {
|
||||
locale: locale,
|
||||
default: 'Reset'
|
||||
})
|
||||
},
|
||||
rangeOrderPrompt: i18n.$t('laydate.rangeOrderPrompt', null, {
|
||||
locale: locale,
|
||||
default: 'End time cannot be less than start Time\nPlease re-select'
|
||||
}),
|
||||
invalidDatePrompt: i18n.$t('laydate.invalidDatePrompt', null, {
|
||||
locale: locale,
|
||||
default: 'Invalid date\n'
|
||||
}),
|
||||
formatErrorPrompt: function (format) {
|
||||
return i18n.$t('laydate.formatErrorPrompt', {format: format}, {
|
||||
locale: locale,
|
||||
default: 'Date format is invalid\nMust follow the format:\n{format}\n'
|
||||
});
|
||||
},
|
||||
autoResetPrompt: i18n.$t('laydate.autoResetPrompt', null, {
|
||||
locale: locale,
|
||||
default: 'It has been reset'
|
||||
}),
|
||||
preview: i18n.$t('laydate.preview', null, {
|
||||
locale: locale,
|
||||
default: 'The selected result'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 仅简体中文生效,不做国际化
|
||||
Class.prototype.markerOfChineseFestivals = {
|
||||
'0-1-1': '元旦',
|
||||
'0-2-14': '情人' ,
|
||||
@@ -246,7 +338,7 @@
|
||||
'0-9-10': '教师',
|
||||
'0-10-1': '国庆',
|
||||
'0-12-25': '圣诞'
|
||||
}
|
||||
};
|
||||
|
||||
// 重载实例
|
||||
Class.prototype.reload = function(options){
|
||||
@@ -327,7 +419,7 @@
|
||||
// 设置了一周的开始是周几,此处做一个控制
|
||||
if (options.weekStart) {
|
||||
if (!/^[0-6]$/.test(options.weekStart)) {
|
||||
var lang = that.lang();
|
||||
var lang = that.i18nMessages;
|
||||
options.weekStart = lang.weeks.indexOf(options.weekStart);
|
||||
if (options.weekStart === -1) options.weekStart = 0;
|
||||
}
|
||||
@@ -444,7 +536,7 @@
|
||||
Class.prototype.render = function(){
|
||||
var that = this
|
||||
,options = that.config
|
||||
,lang = that.lang()
|
||||
,lang = that.i18nMessages
|
||||
,isStatic = options.position === 'static'
|
||||
|
||||
//主面板
|
||||
@@ -576,7 +668,7 @@
|
||||
lay(divFooter).html(function(){
|
||||
var html = [], btns = [];
|
||||
if(options.type === 'datetime'){
|
||||
html.push('<span lay-type="datetime" class="'+ ELEM_TIME_BTN +'">'+ lang.timeTips +'</span>');
|
||||
html.push('<span lay-type="datetime" class="'+ ELEM_TIME_BTN +'">'+ lang.selectTime +'</span>');
|
||||
}
|
||||
if(!(!options.range && options.type === 'datetime') || options.fullPanel){
|
||||
html.push('<span class="'+ ELEM_PREVIEW +'" title="'+ lang.preview +'"></span>')
|
||||
@@ -584,8 +676,10 @@
|
||||
|
||||
lay.each(options.btns, function(i, item){
|
||||
var title = lang.tools[item] || 'btn';
|
||||
if(options.range && item === 'now') return;
|
||||
if(isStatic && item === 'clear') title = options.lang === 'cn' ? '重置' : 'Reset';
|
||||
if (options.range && item === 'now') return;
|
||||
if (isStatic && item === 'clear') {
|
||||
title = lang.tools.reset;
|
||||
}
|
||||
btns.push('<span lay-type="'+ item +'" class="laydate-btns-'+ item +'">'+ title +'</span>');
|
||||
});
|
||||
html.push('<div class="laydate-footer-btns">'+ btns.join('') +'</div>');
|
||||
@@ -838,7 +932,7 @@
|
||||
var that = this
|
||||
,thisDate = new Date()
|
||||
,options = that.config
|
||||
,lang = that.lang()
|
||||
,lang = that.i18nMessages
|
||||
,dateTime = options.dateTime = options.dateTime || that.systemDate()
|
||||
,thisMaxDate, error
|
||||
|
||||
@@ -970,9 +1064,12 @@
|
||||
}
|
||||
} else {
|
||||
//格式不合法
|
||||
that.hint(lang.formatError[0] + (
|
||||
options.range ? (options.format + ' '+ that.rangeStr +' ' + options.format) : options.format
|
||||
) + lang.formatError[1]);
|
||||
that.hint(
|
||||
lang.formatErrorPrompt(
|
||||
options.range ? (options.format + ' '+ that.rangeStr +' ' + options.format) : options.format
|
||||
) +
|
||||
lang.autoResetPrompt
|
||||
);
|
||||
error = true;
|
||||
}
|
||||
} else if(value && layui.type(value) === 'date'){ //若值为日期对象
|
||||
@@ -1050,7 +1147,7 @@
|
||||
// 初始值不在最大最小范围内
|
||||
if(minMaxError && value){
|
||||
that.setValue(that.parse());
|
||||
that.hint('value ' + lang.invalidDate + lang.formatError[1]);
|
||||
that.hint('value ' + lang.invalidDatePrompt + lang.autoResetPrompt);
|
||||
}
|
||||
|
||||
// 初始赋值 startDate,endState
|
||||
@@ -1101,8 +1198,11 @@
|
||||
that.markRender(td, YMD, markers);
|
||||
}
|
||||
|
||||
if(options.calendar && options.lang === 'cn'){
|
||||
render(that.markerOfChineseFestivals);
|
||||
// chineseFestivals 仅简体中文生效
|
||||
if (options.calendar) {
|
||||
if (options.lang === zhCN) {
|
||||
render(that.markerOfChineseFestivals);
|
||||
}
|
||||
}
|
||||
|
||||
if(typeof options.mark === 'function'){
|
||||
@@ -1436,14 +1536,14 @@
|
||||
,options = that.config
|
||||
,dateTime = value || that.thisDateTime(index)
|
||||
,thisDate = new Date(), startWeek, prevMaxDate, thisMaxDate
|
||||
,lang = that.lang()
|
||||
,lang = that.i18nMessages
|
||||
|
||||
,isAlone = options.type !== 'date' && options.type !== 'datetime'
|
||||
,tds = lay(that.table[index]).find('td')
|
||||
,elemYM = lay(that.elemHeader[index][2]).find('span');
|
||||
|
||||
if(dateTime.year < LIMIT_YEAR[0]) dateTime.year = LIMIT_YEAR[0], that.hint(lang.invalidDate);
|
||||
if(dateTime.year > LIMIT_YEAR[1]) dateTime.year = LIMIT_YEAR[1], that.hint(lang.invalidDate);
|
||||
if(dateTime.year < LIMIT_YEAR[0]) dateTime.year = LIMIT_YEAR[0], that.hint(lang.invalidDatePrompt);
|
||||
if(dateTime.year > LIMIT_YEAR[1]) dateTime.year = LIMIT_YEAR[1], that.hint(lang.invalidDatePrompt);
|
||||
|
||||
//记录初始值
|
||||
if(!that.firstDate){
|
||||
@@ -1499,12 +1599,14 @@
|
||||
if(!that.panelYM) that.panelYM = {};
|
||||
that.panelYM[index] = {year: dateTime.year, month: dateTime.month};
|
||||
|
||||
if(options.lang === 'cn'){
|
||||
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.month[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);
|
||||
}
|
||||
|
||||
//初始默认选择器
|
||||
@@ -1518,9 +1620,10 @@
|
||||
that.list(options.type, 0).list(options.type, 1);
|
||||
|
||||
//同步按钮可点状态
|
||||
options.type === 'time' ? that.setBtnStatus('时间'
|
||||
,lay.extend({}, that.systemDate(), that.startTime)
|
||||
,lay.extend({}, that.systemDate(), that.endTime)
|
||||
options.type === 'time' ? that.setBtnStatus(
|
||||
true,
|
||||
lay.extend({}, that.systemDate(), that.startTime),
|
||||
lay.extend({}, that.systemDate(), that.endTime)
|
||||
) : that.setBtnStatus(true);
|
||||
}
|
||||
} else {
|
||||
@@ -1581,7 +1684,7 @@
|
||||
var that = this
|
||||
,options = that.config
|
||||
,dateTime = that.rangeLinked ? options.dateTime : [options.dateTime, that.endDate][index]
|
||||
,lang = that.lang()
|
||||
,lang = that.i18nMessages
|
||||
,isAlone = options.range && options.type !== 'date' && options.type !== 'datetime' //独立范围选择器
|
||||
|
||||
,ul = lay.elem('ul', {
|
||||
@@ -1595,8 +1698,8 @@
|
||||
,elemYM = lay(elemHeader[2]).find('span')
|
||||
,elemCont = that.elemCont[index || 0]
|
||||
,haveList = lay(elemCont).find('.'+ ELEM_LIST)[0]
|
||||
,isCN = options.lang === 'cn'
|
||||
,text = isCN ? '年' : ''
|
||||
,isMonthBeforeYear = lang.monthBeforeYear
|
||||
,text = lang.literal.year
|
||||
|
||||
,listYM = that.listYM[index] || {}
|
||||
,hms = ['hours', 'minutes', 'seconds']
|
||||
@@ -1644,7 +1747,7 @@
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -1661,7 +1764,7 @@
|
||||
};
|
||||
|
||||
i + 1 == listYM[1] && lay(li).addClass(THIS);
|
||||
li.innerHTML = lang.month[i] + (isCN ? '月' : '');
|
||||
li.innerHTML = lang.months[i];
|
||||
ul.appendChild(li);
|
||||
|
||||
/*
|
||||
@@ -1683,7 +1786,7 @@
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1852,7 +1955,7 @@
|
||||
,haveSpan = lay(elemHeader[2]).find('.'+ ELEM_TIME_TEXT);
|
||||
|
||||
scroll();
|
||||
span.innerHTML = options.range ? [lang.startTime,lang.endTime][index] : lang.timeTips;
|
||||
span.innerHTML = options.range ? [lang.startTime,lang.endTime][index] : lang.selectTime;
|
||||
lay(that.elemMain[index]).addClass('laydate-time-show');
|
||||
|
||||
if(haveSpan[0]) haveSpan.remove();
|
||||
@@ -1913,7 +2016,7 @@
|
||||
Class.prototype.setBtnStatus = function(tips, start, end){
|
||||
var that = this
|
||||
,options = that.config
|
||||
,lang = that.lang()
|
||||
,lang = that.i18nMessages
|
||||
,isOut
|
||||
,elemBtn = lay(that.footer).find(ELEM_CONFIRM)
|
||||
,timeParams = options.type === 'datetime' || options.type === 'time' ? ['hours', 'minutes', 'seconds'] : undefined;
|
||||
@@ -1937,10 +2040,10 @@
|
||||
? elemBtn.addClass(DISABLED)
|
||||
: elemBtn[isOut ? 'addClass' : 'removeClass'](DISABLED);
|
||||
|
||||
//是否异常提示
|
||||
if(tips && isOut) that.hint(
|
||||
typeof tips === 'string' ? lang.timeout.replace(/日期/g, tips) : lang.timeout
|
||||
);
|
||||
// 是否异常提示
|
||||
if (tips && isOut) {
|
||||
that.hint(lang.rangeOrderPrompt);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2320,7 +2423,7 @@
|
||||
Class.prototype.tool = function(btn, type){
|
||||
var that = this
|
||||
,options = that.config
|
||||
,lang = that.lang()
|
||||
,lang = that.i18nMessages
|
||||
,dateTime = options.dateTime
|
||||
,isStatic = options.position === 'static'
|
||||
,active = {
|
||||
@@ -2329,13 +2432,13 @@
|
||||
if(lay(btn).hasClass(DISABLED)) return;
|
||||
that.list('time', 0);
|
||||
options.range && that.list('time', 1);
|
||||
lay(btn).attr('lay-type', 'date').html(that.lang().dateTips);
|
||||
lay(btn).attr('lay-type', 'date').html(that.i18nMessages.selectDate);
|
||||
}
|
||||
|
||||
//选择日期
|
||||
,date: function(){
|
||||
that.closeList();
|
||||
lay(btn).attr('lay-type', 'datetime').html(that.lang().timeTips);
|
||||
lay(btn).attr('lay-type', 'datetime').html(that.i18nMessages.selectTime);
|
||||
}
|
||||
|
||||
//清空、重置
|
||||
@@ -2360,7 +2463,7 @@
|
||||
|
||||
// 当前系统时间未在 min/max 范围内,则不可点击
|
||||
if(lay(btn).hasClass(DISABLED)){
|
||||
return that.hint(lang.tools.now +', '+ lang.invalidDate);
|
||||
return that.hint(lang.tools.now +', '+ lang.invalidDatePrompt);
|
||||
}
|
||||
|
||||
lay.extend(dateTime, that.systemDate(), {
|
||||
@@ -2382,12 +2485,10 @@
|
||||
? that.startTime && that.endTime && that.newDate(that.startTime) > that.newDate(that.endTime)
|
||||
: that.startDate && that.endDate && that.newDate(lay.extend({},that.startDate, that.startTime || {})) > that.newDate(lay.extend({},that.endDate, that.endTime || {}));
|
||||
|
||||
return isTimeout
|
||||
? that.hint(options.type === 'time' ? lang.timeout.replace(/日期/g, '时间') : lang.timeout)
|
||||
: that.hint(lang.invalidDate);
|
||||
return that.hint(isTimeout ? lang.rangeOrderPrompt : lang.invalidDatePrompt);
|
||||
}
|
||||
} else {
|
||||
if(lay(btn).hasClass(DISABLED)) return that.hint(lang.invalidDate);
|
||||
if(lay(btn).hasClass(DISABLED)) return that.hint(lang.invalidDatePrompt);
|
||||
}
|
||||
|
||||
that.setValue(that.parse());
|
||||
@@ -2604,64 +2705,63 @@
|
||||
};
|
||||
};
|
||||
|
||||
//记录所有实例
|
||||
// 绑定关闭控件事件
|
||||
lay(document).on('mousedown', function(e){
|
||||
if(!laydate.thisId) return;
|
||||
var that = thisModule.getThis(laydate.thisId);
|
||||
if(!that) return;
|
||||
|
||||
var options = that.config;
|
||||
|
||||
if(
|
||||
e.target === options.elem[0] ||
|
||||
e.target === options.eventElem[0] ||
|
||||
e.target === lay(options.closeStop)[0] ||
|
||||
(options.elem[0] && options.elem[0].contains(e.target))
|
||||
) return;
|
||||
|
||||
that.remove();
|
||||
|
||||
}).on('keydown', function(e){
|
||||
if(!laydate.thisId) return;
|
||||
var that = thisModule.getThis(laydate.thisId);
|
||||
if(!that) return;
|
||||
|
||||
// 回车触发确认
|
||||
if(that.config.position === 'static') return;
|
||||
if(e.keyCode === 13){
|
||||
if(lay('#'+ that.elemID)[0] && that.elemID === Class.thisElemDate){
|
||||
e.preventDefault();
|
||||
lay(that.footer).find(ELEM_CONFIRM)[0].click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//自适应定位
|
||||
lay(window).on('resize', function(){
|
||||
if(!laydate.thisId) return;
|
||||
var that = thisModule.getThis(laydate.thisId);
|
||||
if(!that) return;
|
||||
|
||||
if(!that.elem || !lay(ELEM)[0]){
|
||||
return false;
|
||||
}
|
||||
|
||||
that.position();
|
||||
});
|
||||
|
||||
// 记录所有实例
|
||||
thisModule.that = {}; //记录所有实例对象
|
||||
|
||||
//获取当前实例对象
|
||||
thisModule.getThis = function(id){
|
||||
// 获取当前实例对象
|
||||
thisModule.getThis = function(id) {
|
||||
var that = thisModule.that[id];
|
||||
if(!that && isLayui) layui.hint().error(id ? (MOD_NAME +' instance with ID \''+ id +'\' not found') : 'ID argument required');
|
||||
if (!that) {
|
||||
layui.hint().error(id ? (MOD_NAME +' instance with ID \''+ id +'\' not found') : 'ID argument required');
|
||||
}
|
||||
return that;
|
||||
};
|
||||
|
||||
// 初始执行
|
||||
ready.run = function(lay){
|
||||
// 绑定关闭控件事件
|
||||
lay(document).on('mousedown', function(e){
|
||||
if(!laydate.thisId) return;
|
||||
var that = thisModule.getThis(laydate.thisId);
|
||||
if(!that) return;
|
||||
|
||||
var options = that.config;
|
||||
|
||||
if(
|
||||
e.target === options.elem[0] ||
|
||||
e.target === options.eventElem[0] ||
|
||||
e.target === lay(options.closeStop)[0] ||
|
||||
(options.elem[0] && options.elem[0].contains(e.target))
|
||||
) return;
|
||||
|
||||
that.remove();
|
||||
|
||||
}).on('keydown', function(e){
|
||||
if(!laydate.thisId) return;
|
||||
var that = thisModule.getThis(laydate.thisId);
|
||||
if(!that) return;
|
||||
|
||||
// 回车触发确认
|
||||
if(that.config.position === 'static') return;
|
||||
if(e.keyCode === 13){
|
||||
if(lay('#'+ that.elemID)[0] && that.elemID === Class.thisElemDate){
|
||||
e.preventDefault();
|
||||
lay(that.footer).find(ELEM_CONFIRM)[0].click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//自适应定位
|
||||
lay(window).on('resize', function(){
|
||||
if(!laydate.thisId) return;
|
||||
var that = thisModule.getThis(laydate.thisId);
|
||||
if(!that) return;
|
||||
|
||||
if(!that.elem || !lay(ELEM)[0]){
|
||||
return false;
|
||||
}
|
||||
|
||||
that.position();
|
||||
});
|
||||
};
|
||||
|
||||
// 渲染 - 核心接口
|
||||
laydate.render = function(options){
|
||||
var inst = new Class(options);
|
||||
@@ -2747,23 +2847,5 @@
|
||||
return new Date(thisDate.getTime() - 1000*60*60*24).getDate();
|
||||
};
|
||||
|
||||
//加载方式
|
||||
isLayui ? (
|
||||
laydate.ready()
|
||||
,layui.define('lay', function(exports){ //layui 加载
|
||||
laydate.path = layui.cache.dir;
|
||||
ready.run(lay);
|
||||
exports(MOD_NAME, laydate);
|
||||
})
|
||||
) : (
|
||||
(typeof define === 'function' && define.amd) ? define(function(){ //requirejs 加载
|
||||
ready.run(lay);
|
||||
return laydate;
|
||||
}) : function(){ //普通 script 标签加载
|
||||
laydate.ready();
|
||||
ready.run(window.lay);
|
||||
window.laydate = laydate;
|
||||
}()
|
||||
);
|
||||
|
||||
})(window, window.document);
|
||||
exports(MOD_NAME, laydate);
|
||||
});
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
var isLayui = window.layui && layui.define;
|
||||
var $;
|
||||
var win;
|
||||
var i18n = {};
|
||||
var OBJECT_REPLACE_REGEX = /\{(\w+)\}/g;
|
||||
|
||||
var ready = {
|
||||
getPath: function(){
|
||||
var jsPath = (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') ? document.currentScript.src : function(){
|
||||
@@ -27,15 +30,38 @@ var ready = {
|
||||
return GLOBAL.layer_dir || jsPath.substring(0, jsPath.lastIndexOf('/') + 1);
|
||||
}(),
|
||||
config: {
|
||||
removeFocus: true
|
||||
removeFocus: true,
|
||||
lang: {
|
||||
confirm: '确定',
|
||||
cancel: '取消',
|
||||
defaultTitle: '信息',
|
||||
prompt: {
|
||||
InputLengthPrompt: '最多输入 {length} 个字符'
|
||||
},
|
||||
photos: {
|
||||
noData: '没有图片',
|
||||
tools: {
|
||||
rotate: '旋转',
|
||||
scaleX: '水平变换',
|
||||
zoomIn: '放大',
|
||||
zoomOut: '缩小',
|
||||
reset: '还原',
|
||||
close: '关闭'
|
||||
},
|
||||
viewPicture: '查看原图',
|
||||
urlError: {
|
||||
prompt: '当前图片地址异常,\n是否继续查看下一张?',
|
||||
confirm: '下一张',
|
||||
cancel: '不看了'
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
end: {},
|
||||
beforeEnd: {},
|
||||
events: {resize: {}},
|
||||
minStackIndex: 0,
|
||||
minStackArr: [],
|
||||
btn: ['确定', '取消'],
|
||||
|
||||
// 五种原始层模式
|
||||
type: ['dialog', 'page', 'iframe', 'loading', 'tips'],
|
||||
|
||||
@@ -99,6 +125,43 @@ var ready = {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取对象中的值,lodash _.get 简易版
|
||||
* @param {Record<string, any>} obj
|
||||
* @param {string} path
|
||||
* @param {any} defaultValue
|
||||
*/
|
||||
var get = function (obj, path, defaultValue) {
|
||||
// 'a[0].b.c' ==> ['a', '0', 'b', 'c']
|
||||
var casePath = path.replace(/\[(\d+)\]/g, '.$1').split('.');
|
||||
var result = obj;
|
||||
|
||||
for (var i = 0; i < casePath.length; i++) {
|
||||
result = result && result[casePath[i]];
|
||||
if (result === null || result === undefined) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 根据给定的键从国际化消息中获取翻译后的内容
|
||||
i18n.$t = function(key) {
|
||||
// 非 layui 环境去除命名空间前缀,从 config.lang 中取值
|
||||
// TODO 简化版,暂不文档化,不支持配置多个 locale
|
||||
key = key.replace(/^layer\./, '');
|
||||
var result = get(ready.config.lang, key, key);
|
||||
if(typeof result === 'string' && arguments.length > 1) {
|
||||
var opts = arguments[1];
|
||||
return result.replace(OBJECT_REPLACE_REGEX, function(match, key) {
|
||||
return opts[key] !== undefined ? opts[key] : match;
|
||||
})
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
// 默认内置方法。
|
||||
var layer = {
|
||||
v: '3.7.0',
|
||||
@@ -162,7 +225,7 @@ var layer = {
|
||||
}
|
||||
return layer.open($.extend({
|
||||
content: content,
|
||||
btn: ready.btn,
|
||||
btn: [i18n.$t('layer.confirm'), i18n.$t('layer.cancel')],
|
||||
yes: yes,
|
||||
btn2: cancel
|
||||
}, type ? {} : options));
|
||||
@@ -225,6 +288,8 @@ var Class = function(setings){
|
||||
var that = this, creat = function(){
|
||||
that.creat();
|
||||
};
|
||||
// TODO 临时的同步方案
|
||||
ready.config.title = i18n.$t('layer.defaultTitle');
|
||||
that.index = ++layer.index;
|
||||
that.config.maxWidth = $(win).width() - 15*2; // 初始最大宽度:当前屏幕宽,左右留 15px 边距
|
||||
that.config = $.extend({}, that.config, ready.config, setings);
|
||||
@@ -268,7 +333,7 @@ Class.pt.config = {
|
||||
shade: 0.3,
|
||||
fixed: true,
|
||||
move: doms[1],
|
||||
title: '信息',
|
||||
title: i18n.$t('layer.defaultTitle'),
|
||||
offset: 'auto',
|
||||
area: 'auto',
|
||||
closeBtn: 1,
|
||||
@@ -456,7 +521,7 @@ Class.pt.creat = function(){
|
||||
|
||||
switch(config.type){
|
||||
case 0:
|
||||
config.btn = ('btn' in config) ? config.btn : ready.btn[0];
|
||||
config.btn = ('btn' in config) ? config.btn : i18n.$t('layer.confirm');
|
||||
layer.closeAll('dialog');
|
||||
break;
|
||||
case 2:
|
||||
@@ -1444,7 +1509,7 @@ layer.prompt = function(options, yes){
|
||||
|
||||
return layer.open($.extend({
|
||||
type: 1,
|
||||
btn: ['确定','取消'],
|
||||
btn: [i18n.$t('layer.confirm'),i18n.$t('layer.cancel')],
|
||||
content: content,
|
||||
skin: 'layui-layer-prompt' + skin('prompt'),
|
||||
maxWidth: win.width(),
|
||||
@@ -1457,7 +1522,7 @@ layer.prompt = function(options, yes){
|
||||
yes: function(index){
|
||||
var value = prompt.val();
|
||||
if(value.length > (options.maxlength||500)) {
|
||||
layer.tips('最多输入'+ (options.maxlength || 500) +'个字符', prompt, {tips: 1});
|
||||
layer.tips(i18n.$t('layer.prompt.InputLengthPrompt', {length: (options.maxlength || 500)}), prompt, {tips: 1});
|
||||
} else {
|
||||
yes && yes(value, index, prompt);
|
||||
}
|
||||
@@ -1571,7 +1636,7 @@ layer.photos = function(options, loop, key){
|
||||
// 不直接弹出
|
||||
if (!loop) return;
|
||||
} else if (data.length === 0){
|
||||
return layer.msg('没有图片');
|
||||
return layer.msg(i18n.$t('layer.photos.noData'));
|
||||
}
|
||||
|
||||
// 上一张
|
||||
@@ -1716,7 +1781,7 @@ layer.photos = function(options, loop, key){
|
||||
});
|
||||
|
||||
// 滑动切换图片事件,仅限 layui 中
|
||||
if(window.layui || window.lay){
|
||||
if(isLayui || (window.lay && typeof window.lay === 'function')){
|
||||
var lay = window.layui.lay || window.lay;
|
||||
var touchEndCallback = function(e, state){
|
||||
var duration = Date.now() - state.timeStart;
|
||||
@@ -1819,12 +1884,12 @@ layer.photos = function(options, loop, key){
|
||||
if (options.toolbar) {
|
||||
arr.push([
|
||||
'<div class="layui-layer-photos-toolbar layui-layer-photos-header">',
|
||||
'<span toolbar-event="rotate" data-option="90" title="旋转"><i class="layui-icon layui-icon-refresh"></i></span>',
|
||||
'<span toolbar-event="scalex" title="变换"><i class="layui-icon layui-icon-slider"></i></span>',
|
||||
'<span toolbar-event="zoom" data-option="0.1" title="放大"><i class="layui-icon layui-icon-add-circle"></i></span>',
|
||||
'<span toolbar-event="zoom" data-option="-0.1" title="缩小"><i class="layui-icon layui-icon-reduce-circle"></i></span>',
|
||||
'<span toolbar-event="reset" title="还原"><i class="layui-icon layui-icon-refresh-1"></i></span>',
|
||||
'<span toolbar-event="close" title="关闭"><i class="layui-icon layui-icon-close"></i></span>',
|
||||
'<span toolbar-event="rotate" data-option="90" title="'+ i18n.$t('layer.photos.tools.rotate') +'"><i class="layui-icon layui-icon-refresh"></i></span>',
|
||||
'<span toolbar-event="scalex" title="'+ i18n.$t('layer.photos.tools.scaleX') +'"><i class="layui-icon layui-icon-slider"></i></span>',
|
||||
'<span toolbar-event="zoom" data-option="0.1" title="'+ i18n.$t('layer.photos.tools.zoomIn') +'"><i class="layui-icon layui-icon-add-circle"></i></span>',
|
||||
'<span toolbar-event="zoom" data-option="-0.1" title="'+ i18n.$t('layer.photos.tools.zoomOut') +'"><i class="layui-icon layui-icon-reduce-circle"></i></span>',
|
||||
'<span toolbar-event="reset" title="'+ i18n.$t('layer.photos.tools.reset') +'"><i class="layui-icon layui-icon-refresh-1"></i></span>',
|
||||
'<span toolbar-event="close" title="'+ i18n.$t('layer.photos.tools.close') +'"><i class="layui-icon layui-icon-close"></i></span>',
|
||||
'</div>'
|
||||
].join(''));
|
||||
}
|
||||
@@ -1834,7 +1899,7 @@ layer.photos = function(options, loop, key){
|
||||
arr.push(['<div class="layui-layer-photos-toolbar layui-layer-photos-footer">',
|
||||
'<h3>'+ alt +'</h3>',
|
||||
'<em>'+ dict.imgIndex +' / '+ data.length +'</em>',
|
||||
'<a href="'+ data[start].src +'" target="_blank">查看原图</a>',
|
||||
'<a href="'+ data[start].src + '" target="_blank">'+ i18n.$t('layer.photos.viewPicture') +'</a>',
|
||||
'</div>'].join(''));
|
||||
}
|
||||
|
||||
@@ -1856,9 +1921,9 @@ layer.photos = function(options, loop, key){
|
||||
}, options));
|
||||
}, function(){
|
||||
layer.close(dict.loadi);
|
||||
layer.msg('当前图片地址异常,<br>是否继续查看下一张?', {
|
||||
layer.msg('<span style="white-space: pre-line;">' + i18n.$t('layer.photos.urlError.prompt') + '</span>', {
|
||||
time: 30000,
|
||||
btn: ['下一张', '不看了'],
|
||||
btn: [i18n.$t('layer.photos.urlError.confirm'), i18n.$t('layer.photos.urlError.cancel')],
|
||||
yes: function(){
|
||||
data.length > 1 && dict.imgnext(true,true);
|
||||
}
|
||||
@@ -1897,7 +1962,8 @@ ready.run = function(_$){
|
||||
// 加载方式
|
||||
window.layui && layui.define ? (
|
||||
layer.ready(),
|
||||
layui.define(['jquery','lay'], function(exports){ // layui
|
||||
layui.define(['jquery', 'lay', 'i18n'], function(exports) { // layui
|
||||
i18n.$t = layui.i18n.$t;
|
||||
layer.path = layui.cache.dir;
|
||||
ready.run(layui.$);
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
* laypage 分页组件
|
||||
*/
|
||||
|
||||
layui.define(function(exports) {
|
||||
layui.define('i18n', function(exports) {
|
||||
"use strict";
|
||||
|
||||
var i18n = layui.i18n;
|
||||
|
||||
var doc = document;
|
||||
var id = 'getElementById';
|
||||
var tag = 'getElementsByTagName';
|
||||
@@ -72,8 +74,8 @@ layui.define(function(exports) {
|
||||
groups = config.pages;
|
||||
}
|
||||
|
||||
config.prev = 'prev' in config ? config.prev : '上一页'; // 上一页文本
|
||||
config.next = 'next' in config ? config.next : '下一页'; // 下一页文本
|
||||
config.prev = 'prev' in config ? config.prev : i18n.$t('laypage.prev'); // 上一页文本
|
||||
config.next = 'next' in config ? config.next : i18n.$t('laypage.next'); // 下一页文本
|
||||
|
||||
// 计算当前组
|
||||
var index = config.pages > groups
|
||||
@@ -100,7 +102,7 @@ layui.define(function(exports) {
|
||||
|
||||
// 首页
|
||||
if(index > 1 && config.first !== false && groups !== 0){
|
||||
pager.push('<a class="layui-laypage-first" data-page="1" title="首页">'+ (config.first || 1) +'</a>');
|
||||
pager.push('<a class="layui-laypage-first" data-page="1" title="' + i18n.$t('laypage.first') + '">' + (config.first || 1) +'</a>');
|
||||
}
|
||||
|
||||
// 计算当前页码组的起始页
|
||||
@@ -118,7 +120,7 @@ layui.define(function(exports) {
|
||||
|
||||
// 输出左分割符
|
||||
if(config.first !== false && start > 2){
|
||||
pager.push('<span class="layui-laypage-spr">...</span>')
|
||||
pager.push('<span class="layui-laypage-spr">...</span>');
|
||||
}
|
||||
|
||||
// 输出连续页码
|
||||
@@ -137,7 +139,7 @@ layui.define(function(exports) {
|
||||
pager.push('<span class="layui-laypage-spr">...</span>');
|
||||
}
|
||||
if(groups !== 0){
|
||||
pager.push('<a class="layui-laypage-last" title="尾页" data-page="'+ config.pages +'">'+ (config.last || config.pages) +'</a>');
|
||||
pager.push('<a class="layui-laypage-last" title="' + i18n.$t('laypage.last') + '" data-page="'+ config.pages +'">'+ (config.last || config.pages) +'</a>');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,15 +155,18 @@ layui.define(function(exports) {
|
||||
|
||||
// 数据总数
|
||||
count: function(){
|
||||
var countText = typeof config.countText === 'object' ? config.countText : ['共 ', ' 条'];
|
||||
return '<span class="layui-laypage-count">'+ countText[0] + config.count + countText[1] +'</span>'
|
||||
var countText = typeof config.countText === 'object'
|
||||
? config.countText[0] + config.count + config.countText[1]
|
||||
: i18n.$t('laypage.total', {total: config.count});
|
||||
|
||||
return '<span class="layui-laypage-count">'+ countText +'</span>'
|
||||
}(),
|
||||
|
||||
// 每页条数
|
||||
limit: function(){
|
||||
var elemArr = ['<span class="layui-laypage-limits"><select lay-ignore>'];
|
||||
var template = function(item) {
|
||||
var def = item +' 条/页';
|
||||
var def = item + ' ' + i18n.$t('laypage.pagesize');
|
||||
return typeof config.limitTemplet === 'function'
|
||||
? (config.limitTemplet(item) || def)
|
||||
: def;
|
||||
@@ -189,9 +194,9 @@ layui.define(function(exports) {
|
||||
// 跳页区域
|
||||
skip: function(){
|
||||
var skipText = typeof config.skipText === 'object' ? config.skipText : [
|
||||
'到第',
|
||||
'页',
|
||||
'确定'
|
||||
i18n.$t('laypage.goto'),
|
||||
i18n.$t('laypage.page'),
|
||||
i18n.$t('laypage.confirm')
|
||||
];
|
||||
return [
|
||||
'<span class="layui-laypage-skip">'+ skipText[0],
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* 表格组件
|
||||
*/
|
||||
|
||||
layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
|
||||
layui.define(['lay', 'i18n', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
@@ -15,6 +15,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
|
||||
var util = layui.util;
|
||||
var hint = layui.hint();
|
||||
var device = layui.device();
|
||||
var i18n = layui.i18n;
|
||||
|
||||
// api
|
||||
var table = {
|
||||
@@ -192,7 +193,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
|
||||
,'{{# } else { }}'
|
||||
,'<span>{{-item2.title||""}}</span>'
|
||||
,'{{# if(isSort){ }}'
|
||||
,'<span class="layui-table-sort layui-inline"><i class="layui-edge layui-table-sort-asc" title="升序"></i><i class="layui-edge layui-table-sort-desc" title="降序"></i></span>'
|
||||
,'<span class="layui-table-sort layui-inline"><i class="layui-edge layui-table-sort-asc" title="{{= d.i18nMessages.table_sort_asc }}"></i><i class="layui-edge layui-table-sort-desc" title="{{= d.i18nMessages.table_sort_desc }}"></i></span>'
|
||||
,'{{# } }}'
|
||||
,'{{# } }}'
|
||||
,'</div>'
|
||||
@@ -301,9 +302,6 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
|
||||
defaultToolbar: ['filter', 'exports', 'print'], // 工具栏右侧图标
|
||||
defaultContextmenu: true, // 显示默认上下文菜单
|
||||
autoSort: true, // 是否前端自动排序。如果否,则需自主排序(通常为服务端处理好排序)
|
||||
text: {
|
||||
none: '无数据'
|
||||
},
|
||||
cols: []
|
||||
};
|
||||
|
||||
@@ -323,7 +321,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
|
||||
thisTable.that[id] = that; // 记录当前实例对象
|
||||
thisTable.config[id] = options; // 记录当前实例配置项
|
||||
|
||||
//请求参数的自定义格式
|
||||
// 请求参数的自定义格式
|
||||
options.request = $.extend({
|
||||
pageName: 'page',
|
||||
limitName: 'limit'
|
||||
@@ -339,7 +337,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
|
||||
countName: 'count'
|
||||
}, options.response);
|
||||
|
||||
//如果 page 传入 laypage 对象
|
||||
// 如果 page 传入 laypage 对象
|
||||
if(options.page !== null && typeof options.page === 'object'){
|
||||
options.limit = options.page.limit || options.limit;
|
||||
options.limits = options.page.limits || options.limits;
|
||||
@@ -348,7 +346,12 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
|
||||
delete options.page.jump;
|
||||
}
|
||||
|
||||
if(!options.elem[0]) return that;
|
||||
// 加载 i18n 自定义文本
|
||||
options.text = $.extend(true, {
|
||||
none: i18n.$t('table.noData')
|
||||
}, options.text);
|
||||
|
||||
if (!options.elem[0]) return that;
|
||||
|
||||
// 若元素未设 lay-filter 属性,则取实例 id 值
|
||||
if(!options.elem.attr('lay-filter')){
|
||||
@@ -419,7 +422,11 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
|
||||
tagStyle: 'legacy'
|
||||
}).render({
|
||||
data: options,
|
||||
index: that.index //索引
|
||||
index: that.index, //索引
|
||||
i18nMessages: {
|
||||
'table_sort_asc': i18n.$t('table.sort.asc'),
|
||||
'table_sort_desc': i18n.$t('table.sort.desc')
|
||||
}
|
||||
}));
|
||||
|
||||
// 初始化样式
|
||||
@@ -650,7 +657,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
|
||||
// 头部工具栏右上角默认工具
|
||||
var defaultConfig = {
|
||||
filter: {
|
||||
title: '筛选列',
|
||||
title: i18n.$t('table.tools.filter.title'),
|
||||
layEvent: 'LAYTABLE_COLS',
|
||||
icon: 'layui-icon-cols',
|
||||
onClick: function(obj) {
|
||||
@@ -703,7 +710,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
|
||||
}
|
||||
},
|
||||
exports: {
|
||||
title: '导出',
|
||||
title: i18n.$t('table.tools.export.title'),
|
||||
layEvent: 'LAYTABLE_EXPORT',
|
||||
icon: 'layui-icon-export',
|
||||
onClick: function(obj) { // 自带导出
|
||||
@@ -712,16 +719,16 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
|
||||
var openPanel = obj.openPanel;
|
||||
var elem = obj.elem;
|
||||
|
||||
if (!data.length) return layer.tips('当前表格无数据', elem, {tips: 3});
|
||||
if (!data.length) return layer.tips(i18n.$t('table.tools.export.noDataPrompt'), elem, {tips: 3});
|
||||
if(device.ie){
|
||||
layer.tips('导出功能不支持 IE,请用 Chrome 等高级浏览器导出', elem, {
|
||||
layer.tips(i18n.$t('table.tools.export.compatPrompt'), elem, {
|
||||
tips: 3
|
||||
});
|
||||
} else {
|
||||
openPanel({
|
||||
list: function(){
|
||||
return [
|
||||
'<li data-type="csv">导出 CSV 文件</li>'
|
||||
'<li data-type="csv">'+ i18n.$t('table.tools.export.csvText') +'</li>'
|
||||
].join('')
|
||||
}(),
|
||||
done: function(panel, list){
|
||||
@@ -735,7 +742,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
|
||||
}
|
||||
},
|
||||
print: {
|
||||
title: '打印',
|
||||
title: i18n.$t('table.tools.print.title'),
|
||||
layEvent: 'LAYTABLE_PRINT',
|
||||
icon: 'layui-icon-print',
|
||||
onClick: function(obj) {
|
||||
@@ -743,7 +750,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
|
||||
var options = obj.config;
|
||||
var elem = obj.elem;
|
||||
|
||||
if (!data.length) return layer.tips('当前表格无数据', elem, {tips: 3});
|
||||
if (!data.length) return layer.tips(i18n.$t('table.tools.print.noDataPrompt'), elem, {tips: 3});
|
||||
var printWin = window.open('about:blank', '_blank');
|
||||
var style = ['<style>',
|
||||
'body{font-size: 12px; color: #5F5F5F;}',
|
||||
@@ -1219,7 +1226,10 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
|
||||
if(res[response.statusName] != response.statusCode){
|
||||
that.errorView(
|
||||
res[response.msgName] ||
|
||||
('返回的数据不符合规范,正确的成功状态码应为:"'+ response.statusName +'": '+ response.statusCode)
|
||||
i18n.$t('table.dataFormatError', {
|
||||
statusName: response.statusName,
|
||||
statusCode: response.statusCode
|
||||
})
|
||||
);
|
||||
} else {
|
||||
// 当前页不能超过总页数
|
||||
@@ -1246,7 +1256,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
|
||||
that._xhrAbort = false;
|
||||
return;
|
||||
}
|
||||
that.errorView('请求异常,错误提示:'+ msg);
|
||||
that.errorView(i18n.$t('table.xhrError', {msg: msg}));
|
||||
typeof options.error === 'function' && options.error(e, msg);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
* transfer 穿梭框组件
|
||||
*/
|
||||
|
||||
layui.define(['laytpl', 'form'], function(exports) {
|
||||
layui.define(['i18n', 'laytpl', 'form'], function(exports) {
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
var laytpl = layui.laytpl;
|
||||
var form = layui.form;
|
||||
var i18n = layui.i18n;
|
||||
|
||||
// 模块名
|
||||
var MOD_NAME = 'transfer';
|
||||
@@ -71,7 +72,7 @@ layui.define(['laytpl', 'form'], function(exports) {
|
||||
var ELEM_DATA = 'layui-transfer-data';
|
||||
|
||||
// 穿梭框模板
|
||||
var TPL_BOX = function(obj){
|
||||
var TPL_BOX = function(obj) {
|
||||
obj = obj || {};
|
||||
return ['<div class="layui-transfer-box" data-index="'+ obj.index +'">',
|
||||
'<div class="layui-transfer-header">',
|
||||
@@ -80,54 +81,35 @@ layui.define(['laytpl', 'form'], function(exports) {
|
||||
'{{# if(d.data.showSearch){ }}',
|
||||
'<div class="layui-transfer-search">',
|
||||
'<i class="layui-icon layui-icon-search"></i>',
|
||||
'<input type="text" class="layui-input" placeholder="关键词搜索">',
|
||||
'<input type="text" class="layui-input" placeholder="'+ i18n.$t('transfer.searchPlaceholder') +'">',
|
||||
'</div>',
|
||||
'{{# } }}',
|
||||
'<ul class="layui-transfer-data"></ul>',
|
||||
'</div>'].join('');
|
||||
};
|
||||
|
||||
// 主模板
|
||||
var TPL_MAIN = ['<div class="layui-transfer layui-form layui-border-box" lay-filter="LAY-transfer-{{= d.index }}">',
|
||||
TPL_BOX({
|
||||
index: 0,
|
||||
checkAllName: 'layTransferLeftCheckAll'
|
||||
}),
|
||||
'<div class="layui-transfer-active">',
|
||||
'<button type="button" class="layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled" data-index="0">',
|
||||
'<i class="layui-icon layui-icon-next"></i>',
|
||||
'</button>',
|
||||
'<button type="button" class="layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled" data-index="1">',
|
||||
'<i class="layui-icon layui-icon-prev"></i>',
|
||||
'</button>',
|
||||
'</div>',
|
||||
TPL_BOX({
|
||||
index: 1,
|
||||
checkAllName: 'layTransferRightCheckAll'
|
||||
}),
|
||||
'</div>'].join('');
|
||||
|
||||
// 构造器
|
||||
var Class = function(options){
|
||||
var Class = function(options) {
|
||||
var that = this;
|
||||
that.index = ++transfer.index;
|
||||
that.config = $.extend({}, that.config, transfer.config, options);
|
||||
that.config = $.extend({
|
||||
title: i18n.$t('transfer.title'),
|
||||
text: {
|
||||
none: i18n.$t('transfer.noData'),
|
||||
searchNone: i18n.$t('transfer.noMatch')
|
||||
}
|
||||
}, that.config, transfer.config, options);
|
||||
that.render();
|
||||
};
|
||||
|
||||
// 默认配置
|
||||
Class.prototype.config = {
|
||||
title: ['列表一', '列表二'],
|
||||
width: 200,
|
||||
height: 360,
|
||||
data: [], // 数据源
|
||||
value: [], // 选中的数据
|
||||
showSearch: false, // 是否开启搜索
|
||||
id: '', // 唯一索引,默认自增 index
|
||||
text: {
|
||||
none: '无数据',
|
||||
searchNone: '无匹配数据'
|
||||
}
|
||||
};
|
||||
|
||||
// 重载实例
|
||||
@@ -142,6 +124,26 @@ layui.define(['laytpl', 'form'], function(exports) {
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
|
||||
// 主模板
|
||||
var TPL_MAIN = ['<div class="layui-transfer layui-form layui-border-box" lay-filter="LAY-transfer-{{= d.index }}">',
|
||||
TPL_BOX({
|
||||
index: 0,
|
||||
checkAllName: 'layTransferLeftCheckAll'
|
||||
}),
|
||||
'<div class="layui-transfer-active">',
|
||||
'<button type="button" class="layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled" data-index="0">',
|
||||
'<i class="layui-icon layui-icon-next"></i>',
|
||||
'</button>',
|
||||
'<button type="button" class="layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled" data-index="1">',
|
||||
'<i class="layui-icon layui-icon-prev"></i>',
|
||||
'</button>',
|
||||
'</div>',
|
||||
TPL_BOX({
|
||||
index: 1,
|
||||
checkAllName: 'layTransferRightCheckAll'
|
||||
}),
|
||||
'</div>'].join('');
|
||||
|
||||
// 解析模板
|
||||
var thisElem = that.elem = $(laytpl(TPL_MAIN, {
|
||||
open: '{{', // 标签符前缀
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
* tree 树组件
|
||||
*/
|
||||
|
||||
layui.define(['form','util'], function(exports) {
|
||||
layui.define(['i18n', 'form', 'util'], function(exports) {
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
var util = layui.util;
|
||||
var i18n = layui.i18n;
|
||||
|
||||
// 模块名
|
||||
var MOD_NAME = 'tree';
|
||||
@@ -92,7 +93,12 @@ layui.define(['form','util'], function(exports) {
|
||||
var Class = function(options){
|
||||
var that = this;
|
||||
that.index = ++tree.index;
|
||||
that.config = $.extend({}, that.config, tree.config, options);
|
||||
that.config = $.extend({
|
||||
text: {
|
||||
defaultNodeName: i18n.$t('tree.defaultNodeName'), // 节点默认名称
|
||||
none: i18n.$t('tree.noData') // 数据为空时的文本提示
|
||||
}
|
||||
}, that.config, tree.config, options);
|
||||
that.render();
|
||||
};
|
||||
|
||||
@@ -106,11 +112,6 @@ layui.define(['form','util'], function(exports) {
|
||||
onlyIconControl: false, // 是否仅允许节点左侧图标控制展开收缩
|
||||
isJump: false, // 是否允许点击节点时弹出新窗口跳转
|
||||
edit: false, // 是否开启节点的操作图标
|
||||
|
||||
text: {
|
||||
defaultNodeName: '未命名', // 节点默认名称
|
||||
none: '无数据' // 数据为空时的文本提示
|
||||
}
|
||||
};
|
||||
|
||||
// 重载实例
|
||||
@@ -576,7 +577,10 @@ layui.define(['form','util'], function(exports) {
|
||||
|
||||
// 删除
|
||||
} else {
|
||||
layer.confirm('确认删除该节点 "<span style="color: #999;">'+ (item[customName.title] || '') +'</span>" 吗?', function(index){
|
||||
var i18nText = i18n.$t('tree.deleteNodePrompt', {
|
||||
name: item[customName.title] || ''
|
||||
});
|
||||
layer.confirm(i18nText, function(index){
|
||||
options.operate && options.operate(returnObj); // 节点删除的回调
|
||||
returnObj.status = 'remove'; // 标注节点删除
|
||||
|
||||
|
||||
@@ -400,7 +400,7 @@ layui.define(['table'], function (exports) {
|
||||
Class.prototype.getTreeNode = function (data) {
|
||||
var that = this;
|
||||
if (!data) {
|
||||
return hint.error('找不到节点数据');
|
||||
return hint.error('Node data not found');
|
||||
}
|
||||
var options = that.getOptions();
|
||||
var treeOptions = options.tree;
|
||||
@@ -422,7 +422,7 @@ layui.define(['table'], function (exports) {
|
||||
var that = this;
|
||||
var treeNodeData = that.getNodeDataByIndex(index);
|
||||
if (!treeNodeData) {
|
||||
return hint.error('找不到节点数据');
|
||||
return hint.error('Node data not found by index: ' + index);
|
||||
}
|
||||
var options = that.getOptions();
|
||||
var treeOptions = options.tree;
|
||||
@@ -886,7 +886,7 @@ layui.define(['table'], function (exports) {
|
||||
* */
|
||||
treeTable.expandAll = function (id, expandFlag) {
|
||||
if (layui.type(expandFlag) !== 'boolean') {
|
||||
return hint.error('expandAll 的展开状态参数只接收true/false')
|
||||
return hint.error('treeTable.expandAll param "expandFlag" must be a boolean value.')
|
||||
}
|
||||
|
||||
var that = getThisTable(id);
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
* 上传组件
|
||||
*/
|
||||
|
||||
layui.define(['lay', 'layer'], function(exports) {
|
||||
layui.define(['lay', 'i18n', 'layer'], function(exports) {
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
var lay = layui.lay;
|
||||
var layer = layui.layer;
|
||||
var device = layui.device();
|
||||
var i18n = layui.i18n;
|
||||
|
||||
// 模块名
|
||||
var MOD_NAME = 'upload';
|
||||
@@ -524,11 +525,11 @@ layui.define(['lay', 'layer'], function(exports) {
|
||||
|
||||
// 文件类型名称
|
||||
var typeName = ({
|
||||
file: '文件',
|
||||
images: '图片',
|
||||
video: '视频',
|
||||
audio: '音频'
|
||||
})[options.accept] || '文件';
|
||||
file: i18n.$t('upload.fileType.file'),
|
||||
images: i18n.$t('upload.fileType.image'),
|
||||
video: i18n.$t('upload.fileType.video'),
|
||||
audio: i18n.$t('upload.fileType.audio')
|
||||
})[options.accept] || i18n.$t('upload.fileType.file');
|
||||
|
||||
// 校验文件格式
|
||||
value = value.length === 0
|
||||
@@ -572,7 +573,7 @@ layui.define(['lay', 'layer'], function(exports) {
|
||||
|
||||
// 校验失败提示
|
||||
if(check){
|
||||
that.msg(text['check-error'] || ('选择的'+ typeName +'中包含不支持的格式'));
|
||||
that.msg(text['check-error'] || i18n.$t('upload.validateMessages.fileExtensionError', {fileType: typeName}));
|
||||
return elemFile.value = '';
|
||||
}
|
||||
|
||||
@@ -598,8 +599,9 @@ layui.define(['lay', 'layer'], function(exports) {
|
||||
return that.msg(typeof text['limit-number'] === 'function'
|
||||
? text['limit-number'](options, that.fileLength)
|
||||
: (
|
||||
'同时最多只能上传: '+ options.number + ' 个文件'
|
||||
+'<br>您当前已经选择了: '+ that.fileLength +' 个文件'
|
||||
i18n.$t('upload.validateMessages.filesOverLengthLimit', {length: options.number})
|
||||
+ '<br/>'
|
||||
+ i18n.$t('upload.validateMessages.currentFilesLength', {length: that.fileLength})
|
||||
));
|
||||
}
|
||||
|
||||
@@ -615,9 +617,10 @@ layui.define(['lay', 'layer'], function(exports) {
|
||||
limitSize = size;
|
||||
}
|
||||
});
|
||||
if(limitSize) return that.msg(typeof text['limit-size'] === 'function'
|
||||
? text['limit-size'](options, limitSize)
|
||||
: '文件大小不能超过 '+ limitSize);
|
||||
if(limitSize) return that.msg(
|
||||
typeof text['limit-size'] === 'function'
|
||||
? text['limit-size'](options, limitSize)
|
||||
: i18n.$t('upload.validateMessages.fileOverSizeLimit', {size: limitSize}));
|
||||
}
|
||||
|
||||
send();
|
||||
@@ -642,7 +645,7 @@ layui.define(['lay', 'layer'], function(exports) {
|
||||
var elemFile = that.elemFile;
|
||||
var item = options.item ? options.item : options.elem;
|
||||
var value = files.length > 1
|
||||
? files.length + '个文件'
|
||||
? i18n.$t('upload.chooseText', {length: files.length})
|
||||
: ((files[0] || {}).name || (elemFile[0].value.match(/[^\/\\]+\..+/g)||[]) || '');
|
||||
|
||||
if(elemFile.next().hasClass(ELEM_CHOOSE)){
|
||||
|
||||
@@ -2,11 +2,18 @@
|
||||
* util 工具组件
|
||||
*/
|
||||
|
||||
layui.define('jquery', function(exports) {
|
||||
layui.define(['lay', 'i18n', 'jquery'], function(exports) {
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
var hint = layui.hint();
|
||||
var i18n = layui.i18n;
|
||||
var lay = layui.lay;
|
||||
|
||||
// 引用自 dayjs
|
||||
// https://github.com/iamkun/dayjs/blob/v1.11.9/src/constant.js#L30
|
||||
var REGEX_FORMAT = /\[([^\]]+)]|y{1,4}|M{1,2}|d{1,2}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|SSS/g;
|
||||
var REGEX_PARSE = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[T\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/i;
|
||||
|
||||
// 外部接口
|
||||
var util = {
|
||||
@@ -230,15 +237,15 @@ layui.define('jquery', function(exports) {
|
||||
|
||||
// 30 天以内,返回「多久前」
|
||||
if(stamp >= 1000*60*60*24){
|
||||
return ((stamp/1000/60/60/24)|0) + ' 天前';
|
||||
return i18n.$t('util.timeAgo.days', {days: (stamp/1000/60/60/24)|0});
|
||||
} else if(stamp >= 1000*60*60){
|
||||
return ((stamp/1000/60/60)|0) + ' 小时前';
|
||||
return i18n.$t('util.timeAgo.hours', {hours: (stamp/1000/60/60)|0});
|
||||
} else if(stamp >= 1000*60*3){ // 3 分钟以内为:刚刚
|
||||
return ((stamp/1000/60)|0) + ' 分钟前';
|
||||
return i18n.$t('util.timeAgo.minutes', {minutes: (stamp/1000/60)|0});
|
||||
} else if(stamp < 0){
|
||||
return '未来';
|
||||
return i18n.$t('util.timeAgo.future');
|
||||
} else {
|
||||
return '刚刚';
|
||||
return i18n.$t('util.timeAgo.justNow');
|
||||
}
|
||||
},
|
||||
|
||||
@@ -258,10 +265,6 @@ layui.define('jquery', function(exports) {
|
||||
// 若 null 或空字符,则返回空字符
|
||||
if(time === null || time === '') return '';
|
||||
|
||||
// 引用自 dayjs
|
||||
// https://github.com/iamkun/dayjs/blob/v1.11.9/src/constant.js#L30
|
||||
var REGEX_FORMAT = /\[([^\]]+)]|y{1,4}|M{1,2}|d{1,2}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|SSS/g;
|
||||
var REGEX_PARSE = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[T\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/i;
|
||||
var that = this;
|
||||
|
||||
var normalizeDate = function(date) {
|
||||
@@ -302,21 +305,7 @@ layui.define('jquery', function(exports) {
|
||||
var seconds = date.getSeconds();
|
||||
var milliseconds = date.getMilliseconds();
|
||||
|
||||
var defaultMeridiem = function(hours, minutes){
|
||||
var hm = hours * 100 + minutes;
|
||||
if (hm < 600) {
|
||||
return '凌晨';
|
||||
} else if (hm < 900) {
|
||||
return '早上';
|
||||
} else if (hm < 1100) {
|
||||
return '上午';
|
||||
} else if (hm < 1300) {
|
||||
return '中午';
|
||||
} else if (hm < 1800) {
|
||||
return '下午';
|
||||
}
|
||||
return '晚上';
|
||||
};
|
||||
var defaultMeridiem = i18n.$t('util.toDateString.meridiem');
|
||||
|
||||
var meridiem = (options && options.customMeridiem) || defaultMeridiem;
|
||||
|
||||
@@ -347,26 +336,10 @@ layui.define('jquery', function(exports) {
|
||||
},
|
||||
|
||||
// 转义 html
|
||||
escape: function(html){
|
||||
var exp = /[<"'>]|&(?=#?[a-zA-Z0-9]+)/g;
|
||||
if (html === undefined || html === null) return '';
|
||||
|
||||
html += '';
|
||||
if (!exp.test(html)) return html;
|
||||
|
||||
return html.replace(/&(?=#?[a-zA-Z0-9]+;?)/g, '&')
|
||||
.replace(/</g, '<').replace(/>/g, '>')
|
||||
.replace(/'/g, ''').replace(/"/g, '"');
|
||||
},
|
||||
escape: lay.escape,
|
||||
|
||||
// 还原转义的 html
|
||||
unescape: function(html){
|
||||
if (html === undefined || html === null) return '';
|
||||
|
||||
return String(html).replace(/\"/g, '"').replace(/\'/g, '\'')
|
||||
.replace(/\>/g, '>').replace(/\</g, '<')
|
||||
.replace(/\&/g, '&');
|
||||
},
|
||||
unescape: lay.unescape,
|
||||
|
||||
// 打开新窗口
|
||||
openWin: function(options){
|
||||
|
||||
Reference in New Issue
Block a user