sync from local backup

This commit is contained in:
chunyu
2026-08-05 23:59:22 +08:00
commit a59f46b894
409 changed files with 166027 additions and 0 deletions
+364
View File
@@ -0,0 +1,364 @@
const fs = require('fs');
const path = require('path');
const localesDir = path.join(__dirname, 'src', 'locales');
const translations = {
'zh': {
"timestamp": {
"pageTitle": "时间戳转换",
"pageDescription": "Unix时间戳与日期时间快速互转",
"pageCategory": "开发",
"backToTools": "返回工具列表",
"timezoneLabel": "时区选择",
"tsToDate": "时间戳转日期",
"dateToTs": "日期转时间戳",
"tsInputPlaceholder": "请输入时间戳,如 1700000000",
"tsEmptyHint": "输入时间戳后自动显示转换结果",
"dateEmptyHint": "选择日期后自动显示时间戳",
"getCurrentTime": "获取当前时间",
"clear": "清空",
"copied": "已复制到剪贴板",
"result": {
"localTime": "本地时间",
"utcTime": "UTC 时间",
"iso8601": "ISO 8601",
"relative": "相对时间",
"weekday": "星期",
"secondsTs": "秒级时间戳",
"msTs": "毫秒级时间戳",
"isoString": "ISO 字符串",
"invalidDate": "无效日期",
"unknown": "未知"
},
"timezone": {
"local": "本地时间",
"utc": "UTC",
"shanghai": "Asia/Shanghai (北京)",
"tokyo": "Asia/Tokyo (东京)",
"newyork": "America/New_York (纽约)",
"london": "Europe/London (伦敦)",
"losangeles": "America/Los_Angeles (洛杉矶)"
},
"badge": {
"seconds": "秒级",
"ms": "毫秒级"
}
}
},
'en': {
"timestamp": {
"pageTitle": "Timestamp Converter",
"pageDescription": "Quick conversion between Unix timestamps and datetime",
"pageCategory": "Dev",
"backToTools": "Back to Tools",
"timezoneLabel": "Timezone",
"tsToDate": "Timestamp to Date",
"dateToTs": "Date to Timestamp",
"tsInputPlaceholder": "Enter a timestamp, e.g. 1700000000",
"tsEmptyHint": "Conversion results will appear after entering a timestamp",
"dateEmptyHint": "Timestamp will appear after selecting a date",
"getCurrentTime": "Get Current Time",
"clear": "Clear",
"copied": "Copied to clipboard",
"result": {
"localTime": "Local Time",
"utcTime": "UTC Time",
"iso8601": "ISO 8601",
"relative": "Relative Time",
"weekday": "Weekday",
"secondsTs": "Seconds Timestamp",
"msTs": "Milliseconds Timestamp",
"isoString": "ISO String",
"invalidDate": "Invalid Date",
"unknown": "Unknown"
},
"timezone": {
"local": "Local Time",
"utc": "UTC",
"shanghai": "Asia/Shanghai (Beijing)",
"tokyo": "Asia/Tokyo (Tokyo)",
"newyork": "America/New_York (New York)",
"london": "Europe/London (London)",
"losangeles": "America/Los_Angeles (Los Angeles)"
},
"badge": {
"seconds": "Seconds",
"ms": "Milliseconds"
}
}
},
'ja': {
"timestamp": {
"pageTitle": "タイムスタンプ変換",
"pageDescription": "Unixタイムスタンプと日時を素早く相互変換",
"pageCategory": "開発",
"backToTools": "ツール一覧に戻る",
"timezoneLabel": "タイムゾーン",
"tsToDate": "タイムスタンプ → 日付",
"dateToTs": "日付 → タイムスタンプ",
"tsInputPlaceholder": "タイムスタンプを入力してください(例: 1700000000)",
"tsEmptyHint": "タイムスタンプを入力すると変換結果が表示されます",
"dateEmptyHint": "日付を選択するとタイムスタンプが表示されます",
"getCurrentTime": "現在の時刻を取得",
"clear": "クリア",
"copied": "クリップボードにコピーしました",
"result": {
"localTime": "ローカル時間",
"utcTime": "UTC 時間",
"iso8601": "ISO 8601",
"relative": "相対時間",
"weekday": "曜日",
"secondsTs": "秒単位タイムスタンプ",
"msTs": "ミリ秒単位タイムスタンプ",
"isoString": "ISO 文字列",
"invalidDate": "無効な日付",
"unknown": "不明"
},
"timezone": {
"local": "ローカル時間",
"utc": "UTC",
"shanghai": "Asia/Shanghai (北京)",
"tokyo": "Asia/Tokyo (東京)",
"newyork": "America/New_York (ニューヨーク)",
"london": "Europe/London (ロンドン)",
"losangeles": "America/Los_Angeles (ロサンゼルス)"
},
"badge": {
"seconds": "秒単位",
"ms": "ミリ秒単位"
}
}
},
'ko': {
"timestamp": {
"pageTitle": "타임스탬프 변환",
"pageDescription": "Unix 타임스탬프와 날짜/시간을 빠르게 상호 변환",
"pageCategory": "개발",
"backToTools": "도구 목록으로 돌아가기",
"timezoneLabel": "시간대",
"tsToDate": "타임스탬프 → 날짜",
"dateToTs": "날짜 → 타임스탬프",
"tsInputPlaceholder": "타임스탬프를 입력하세요 (예: 1700000000)",
"tsEmptyHint": "타임스탬프를 입력하면 변환 결과가 표시됩니다",
"dateEmptyHint": "날짜를 선택하면 타임스탬프가 표시됩니다",
"getCurrentTime": "현재 시간 가져오기",
"clear": "지우기",
"copied": "클립보드에 복사됨",
"result": {
"localTime": "로컬 시간",
"utcTime": "UTC 시간",
"iso8601": "ISO 8601",
"relative": "상대 시간",
"weekday": "요일",
"secondsTs": "초 단위 타임스탬프",
"msTs": "밀리초 단위 타임스탬프",
"isoString": "ISO 문자열",
"invalidDate": "유효하지 않은 날짜",
"unknown": "알 수 없음"
},
"timezone": {
"local": "로컬 시간",
"utc": "UTC",
"shanghai": "Asia/Shanghai (베이징)",
"tokyo": "Asia/Tokyo (도쿄)",
"newyork": "America/New_York (뉴욕)",
"london": "Europe/London (런던)",
"losangeles": "America/Los_Angeles (로스앤젤레스)"
},
"badge": {
"seconds": "초 단위",
"ms": "밀리초 단위"
}
}
},
'ru': {
"timestamp": {
"pageTitle": "Преобразование временных меток",
"pageDescription": "Быстрая конвертация между Unix-временными метками и датой/временем",
"pageCategory": "Разработка",
"backToTools": "Назад к списку инструментов",
"timezoneLabel": "Часовой пояс",
"tsToDate": "Метка → Дата",
"dateToTs": "Дата → Метка",
"tsInputPlaceholder": "Введите временную метку, например 1700000000",
"tsEmptyHint": "Результаты появятся после ввода временной метки",
"dateEmptyHint": "Временная метка появится после выбора даты",
"getCurrentTime": "Получить текущее время",
"clear": "Очистить",
"copied": "Скопировано в буфер обмена",
"result": {
"localTime": "Местное время",
"utcTime": "Время UTC",
"iso8601": "ISO 8601",
"relative": "Относительное время",
"weekday": "День недели",
"secondsTs": "Метка в секундах",
"msTs": "Метка в миллисекундах",
"isoString": "ISO-строка",
"invalidDate": "Недопустимая дата",
"unknown": "Неизвестно"
},
"timezone": {
"local": "Местное время",
"utc": "UTC",
"shanghai": "Asia/Shanghai (Пекин)",
"tokyo": "Asia/Tokyo (Токио)",
"newyork": "America/New_York (Нью-Йорк)",
"london": "Europe/London (Лондон)",
"losangeles": "America/Los_Angeles (Лос-Анджелес)"
},
"badge": {
"seconds": "В секундах",
"ms": "В миллисекундах"
}
}
},
'zh-TW': {
"timestamp": {
"pageTitle": "時間戳轉換",
"pageDescription": "Unix時間戳與日期時間快速互轉",
"pageCategory": "開發",
"backToTools": "返回工具列表",
"timezoneLabel": "時區選擇",
"tsToDate": "時間戳轉日期",
"dateToTs": "日期轉時間戳",
"tsInputPlaceholder": "請輸入時間戳,如 1700000000",
"tsEmptyHint": "輸入時間戳後自動顯示轉換結果",
"dateEmptyHint": "選擇日期後自動顯示時間戳",
"getCurrentTime": "取得目前時間",
"clear": "清空",
"copied": "已複製到剪貼簿",
"result": {
"localTime": "本地時間",
"utcTime": "UTC 時間",
"iso8601": "ISO 8601",
"relative": "相對時間",
"weekday": "星期",
"secondsTs": "秒級時間戳",
"msTs": "毫秒級時間戳",
"isoString": "ISO 字串",
"invalidDate": "無效日期",
"unknown": "未知"
},
"timezone": {
"local": "本地時間",
"utc": "UTC",
"shanghai": "Asia/Shanghai (北京)",
"tokyo": "Asia/Tokyo (東京)",
"newyork": "America/New_York (紐約)",
"london": "Europe/London (倫敦)",
"losangeles": "America/Los_Angeles (洛杉磯)"
},
"badge": {
"seconds": "秒級",
"ms": "毫秒級"
}
}
}
};
function formatNested(obj, indent) {
const pad = ' '.repeat(indent);
const innerPad = ' '.repeat(indent + 2);
const keys = Object.keys(obj);
let result = '{\n';
keys.forEach((key, idx) => {
const val = obj[key];
if (typeof val === 'object' && val !== null) {
result += innerPad + '"' + key + '": ' + formatNested(val, indent + 2);
} else {
const escaped = String(val).replace(/"/g, '\\"');
result += innerPad + '"' + key + '": "' + escaped + '"';
}
if (idx < keys.length - 1) result += ',';
result += '\n';
});
result += pad + '}';
return result;
}
function formatTimestampBlock(obj) {
const pad2 = ' ';
const pad4 = ' ';
const keys = Object.keys(obj);
let result = pad2 + '"timestamp": {\n';
keys.forEach((key, idx) => {
const val = obj[key];
if (typeof val === 'object' && val !== null) {
const subKeys = Object.keys(val);
result += pad4 + '"' + key + '": {\n';
subKeys.forEach((sk, sIdx) => {
const sv = val[sk];
result += ' "' + sk + '": "' + String(sv).replace(/"/g, '\\"') + '"';
if (sIdx < subKeys.length - 1) result += ',';
result += '\n';
});
result += pad4 + '}';
} else {
result += pad4 + '"' + key + '": "' + String(val).replace(/"/g, '\\"') + '"';
}
if (idx < keys.length - 1) result += ',';
result += '\n';
});
result += pad2 + '}';
return result;
}
// Find the LAST line containing the final `}` - we need to:
// 1. Skip any closing } that closes a nested object inside an already-closed outer block
// 2. The actual outer } has nothing but whitespace/comments after it.
// Strategy: Find the position of last `}` at the end of file.
// Since JSON can have nested closing braces, we use brace-counting from the end.
function insertTimestampBeforeFinalBrace(content, timestampBlock) {
// Normalize line endings
const c = content.replace(/\r\n/g, '\n');
// Remove trailing whitespace/newlines
const trimmed = c.replace(/\s+$/, '');
// The last character should be '}'
if (!trimmed.endsWith('}')) {
throw new Error('File does not end with }');
}
// Find content before the final '}'
// Find last '}' position
const lastCloseIdx = trimmed.lastIndexOf('}');
const beforeClosing = trimmed.slice(0, lastCloseIdx);
// Remove trailing whitespace/newlines from beforeClosing to get to the last property
const beforeTrimmed = beforeClosing.replace(/\s+$/, '');
// Determine if we need a comma: check if the last char of beforeTrimmed ends with a comma
// But also: if beforeTrimmed ends with } (closing of nested object at top-level),
// we may still need a comma. E.g.: "xxx": { ... } } -> beforeTrimmed ends with "..."xxx": { ... }
// In that case beforeTrimmed ends with } (of a nested obj), we need to add comma before adding our timestamp
const needsComma = !beforeTrimmed.endsWith(',');
const result = beforeTrimmed + (needsComma ? ',' : '') + '\n' + timestampBlock + '\n}';
return result;
}
['zh', 'en', 'ja', 'ko', 'ru', 'zh-TW'].forEach(lang => {
const filePath = path.join(localesDir, lang + '.json');
const content = fs.readFileSync(filePath, 'utf8');
// Check if already has timestamp (by string pattern)
if (content.indexOf('"timestamp"') !== -1) {
console.log(lang + '.json already has "timestamp" entry, skipping');
return;
}
const timestampBlock = formatTimestampBlock(translations[lang].timestamp);
try {
const newContent = insertTimestampBeforeFinalBrace(content, timestampBlock);
fs.writeFileSync(filePath, newContent + '\n', 'utf8');
console.log(lang + '.json: updated OK');
} catch (e) {
console.error(lang + '.json: FAILED - ' + e.message);
}
});
console.log('Done.');