diff --git a/logs/2026/06/2026-06-13.md b/logs/2026/06/2026-06-13.md index a8ce5a5..737dc39 100644 --- a/logs/2026/06/2026-06-13.md +++ b/logs/2026/06/2026-06-13.md @@ -1,14 +1,14 @@ # 2026-06-13 · KiriMonoLog ## 今日素材 -- **情绪短句**:Brush your teeth the moment you get up.(AdviceSlip) -- **趣味小知识**:Dogs and cats consume over $11 billion worth of pet food a year(djtech.net) -- **治愈文案**:等待,不是为了你能回来,而是找个借口不离开。(九ちのセカィ) +- **情绪短句**:Cars are bad investments.(AdviceSlip) +- **趣味小知识**:There are 1,575 steps from the ground floor to the top of the Empire State building.(djtech.net) +- **治愈文案**:我于杀戮之中盛放,亦如黎明中的花朵。(英雄联盟) ## 今日心情日志(双语) - +
中文原版多语言版本
2026-06-13的日记。
桐雾(Kiri)在想,幸福大概就是这些细碎的、不完美的日常。试着对镜子里的自己笑了一下,感觉还不错。
等待,不是为了你能回来,而是找个借口不离开。
2026年6月13日の日記。
キリは、幸福とはおそらく、これらの美しく不完全な日常のことであると考えています。鏡の中の自分に微笑んでみてください。気持ちいいです。
待っていることは、あなたが戻ってくることではなく、去らないという言い訳を見つけることです。
2026-06-13的日记。
桐雾(Kiri)在想,幸福大概就是这些细碎的、不完美的日常。试着对镜子里的自己笑了一下,感觉还不错。
我于杀戮之中盛放,亦如黎明中的花朵。
2026年6月13日の日記。
キリは、幸福とはおそらく、これらの美しく不完全な日常のことであると考えています。鏡の中の自分に微笑んでみてください。気持ちいいです。
私は夜明けの花のように、屠殺の真っ只中に咲く。
-> 本日随机语种:**日本語** +> 本日内容语种:**ZH + JP** diff --git a/scripts/kirimonolog/composer.py b/scripts/kirimonolog/composer.py index c857c4d..2dc77e9 100644 --- a/scripts/kirimonolog/composer.py +++ b/scripts/kirimonolog/composer.py @@ -15,7 +15,7 @@ import random from typing import Dict, List, Tuple -from kirimonolog.config import LANGUAGE_OPTIONS +from kirimonolog.config import LANGUAGE_OPTIONS, LANGUAGE_SHORT_NAMES # Material 类型别名 Material = Dict[str, str] @@ -31,6 +31,20 @@ def choose_target_language() -> Tuple[str, str]: return code, LANGUAGE_OPTIONS[code] +def build_language_tag(lang_code: str) -> str: + """生成前端显示用的语言标签。 + + 每日日志包含中文和一种随机语言,标签格式为 "ZH + XX"。 + + Args: + lang_code: 目标语言 ISO 代码(如 "en"/"ja"/"ko") + + Returns: + 语言标签字符串,如 "ZH + JP" + """ + return f"ZH + {LANGUAGE_SHORT_NAMES.get(lang_code, lang_code.upper())}" + + def _materials_block(materials: List[Material]) -> str: """将素材列表渲染为 Markdown 无序列表。 @@ -54,20 +68,20 @@ def _to_html_lines(text: str) -> str: return "
".join(html.escape(line) for line in text.splitlines() if line.strip()) -def render_markdown(date_value: dt.date, materials: List[Material], zh_text: str, lang_name: str, translated_text: str) -> str: +def render_markdown(date_value: dt.date, materials: List[Material], zh_text: str, lang_code: str, translated_text: str) -> str: """渲染完整的日志 Markdown 文档。 输出结构: 1. 标题:# YYYY-MM-DD · KiriMonoLog 2. 今日素材:无序列表 3. 今日心情日志(双语):HTML 表格,左栏中文,右栏翻译 - 4. 随机语种标注 + 4. 内容语种标注(格式:ZH + XX) Args: date_value : 日志日期 materials : 当日素材列表 zh_text : 中文日记正文 - lang_name : 目标语言名称(用于标注) + lang_code : 目标语言 ISO 代码(如 "en"/"ja"/"ko") translated_text: 翻译后的文本 Returns: @@ -77,6 +91,7 @@ def render_markdown(date_value: dt.date, materials: List[Material], zh_text: str # 将纯文本转为 HTML 行,适配表格单元格内的多行排版 zh_html = _to_html_lines(zh_text) translated_html = _to_html_lines(translated_text) + lang_tag = build_language_tag(lang_code) return ( f"# {date_str} · KiriMonoLog\n\n" @@ -87,5 +102,5 @@ def render_markdown(date_value: dt.date, materials: List[Material], zh_text: str " 中文原版多语言版本\n" f" {zh_html}{translated_html}\n" "\n\n" - f"> 本日随机语种:**{lang_name}**\n" + f"> 本日内容语种:**{lang_tag}**\n" ) diff --git a/scripts/kirimonolog/config.py b/scripts/kirimonolog/config.py index ff53674..4b66cdf 100644 --- a/scripts/kirimonolog/config.py +++ b/scripts/kirimonolog/config.py @@ -35,6 +35,31 @@ "ko": "한국어", } +# 语言短名称映射(用于前端标签显示) +# 每日日志内容包含中文和一种随机语言,标签格式为 "ZH + XX" +LANGUAGE_SHORT_NAMES = { + "en": "EN", + "ja": "JP", + "ko": "KO", + "zh": "ZH", +} + +# 旧版语言名称映射(兼容旧日志格式) +# 旧日志使用语言全称(如 "日本語"、"English"),需转为短名称 +LEGACY_LANGUAGE_NAMES = { + "English": "EN", + "日本語": "JP", + "한국어": "KO", +} + +# 短名称到语言全称映射(用于前端显示) +SHORT_TO_FULL_NAME = { + "EN": "English", + "JP": "日本語", + "KO": "한국어", + "ZH": "中文", +} + # ── 3. AI 接口配置(Pollinations) ── # Pollinations.ai 提供免费的文本生成 API,无需注册和 API Key。 # POLLINATIONS_TEXT_API : API 基础 URL diff --git a/scripts/kirimonolog/web_exporter.py b/scripts/kirimonolog/web_exporter.py index 141aa93..1fcc840 100644 --- a/scripts/kirimonolog/web_exporter.py +++ b/scripts/kirimonolog/web_exporter.py @@ -1,4 +1,19 @@ -"""网页日志数据导出模块。""" +"""网页日志数据导出模块。 + +本模块负责扫描 logs/ 目录下的日志文件,提取关键信息并导出为 web/logs.json, +供前端主页渲染使用。 + +数据流: + logs/YYYY/MM/YYYY-MM-DD.md → _parse_log() → web/logs.json + +提取字段: + - date: 日志日期(YYYY-MM-DD) + - log_path: 相对路径(用于链接跳转) + - mood_record: 情绪短句素材 + - zh_diary: 中文日记正文 + - translated_diary: 翻译后的日记内容 + - language_tag: 内容语种标签(格式:ZH + XX) +""" from __future__ import annotations @@ -9,46 +24,153 @@ from pathlib import Path from typing import Any +from kirimonolog.config import LEGACY_LANGUAGE_NAMES + +# ── 正则表达式 ── + +# 匹配双栏表格,提取中文原版和多语言版本两个单元格 +# 使用非贪婪匹配 (.*?) 确保正确提取每个 的内容 ZH_TABLE_PATTERN = ( - r"## 今日心情日志(双语)\s*.*?\s*
中文原版多语言版本
(.*?)" + r"## 今日心情日志(双语)\s*.*?\s*" + r"" ) -# 日志素材可能出现全角(中文)或半角(英文)括号,统一兼容两种结束符。 + +# 匹配情绪短句素材,兼容全角(中文)和半角(英文)括号 MOOD_PATTERN = r"- \*\*情绪短句\*\*:(.+?)(?:(|\(|$)" +# 新版语言标签格式:提取 "ZH + XX" 中的语言部分 +LANGUAGE_TAG_PATTERN = r"> 本日内容语种:\*\*(.+?)\*\*" + +# 旧版语言标签格式:提取语言名称(如 "日本語"、"English") +LEGACY_LANGUAGE_PATTERN = r"> 本日随机语种:\*\*(.+?)\*\*" + -def _extract(pattern: str, content: str) -> str: +def _extract(pattern: str, content: str) -> str | tuple[str, str, ...]: + """从内容中提取正则匹配值。 + + 根据正则中的捕获组数量返回不同值: + - 无捕获组或匹配失败:返回空字符串 "" + - 单个捕获组:返回匹配的字符串 + - 多个捕获组:返回匹配的字符串元组 + + Args: + pattern: 正则表达式模式 + content: 要搜索的文本内容 + + Returns: + 匹配的字符串或字符串元组,匹配失败返回空字符串 + """ match = re.search(pattern, content, flags=re.DOTALL) - return match.group(1).strip() if match else "" + if not match: + return "" + # 多个捕获组时返回元组 + if match.lastindex and match.lastindex >= 2: + return tuple(match.group(i).strip() for i in range(1, match.lastindex + 1)) + return match.group(1).strip() def _clean_html_cell(text: str) -> str: + """清理 HTML 单元格内容,转换为纯文本。 + + 处理流程: + 1. 将
标签替换为换行符 + 2. 移除所有 HTML 标签 + 3. 解码 HTML 实体(如 & → &) + 4. 去除首尾空白 + + Args: + text: 包含 HTML 的单元格内容 + + Returns: + 清理后的纯文本 + """ no_break = text.replace("
", "\n") plain = re.sub(r"<[^>]+>", "", no_break) return html.unescape(plain).strip() +def _parse_language_tag(raw: str) -> str: + """解析日志文件中的语言标签。 + + 兼容新旧两种格式: + - 新版:"> 本日内容语种:**ZH + JP**" → "ZH + JP" + - 旧版:"> 本日随机语种:**日本語**" → "ZH + JP"(转为短名称) + + Args: + raw: 日志文件原始内容 + + Returns: + 标准化的语言标签(格式:ZH + XX) + """ + # 尝试匹配新版格式 + new_tag = _extract(LANGUAGE_TAG_PATTERN, raw) + if new_tag: + return new_tag + + # 回退到旧版格式,将语言全称转为短名称 + old_lang = _extract(LEGACY_LANGUAGE_PATTERN, raw) + if old_lang: + short_name = LEGACY_LANGUAGE_NAMES.get(old_lang, old_lang) + return f"ZH + {short_name}" + + return "ZH + ?" + + def _parse_log(path: Path, repo_root: Path) -> dict[str, str]: + """解析单个日志文件,提取结构化数据。 + + Args: + path: 日志文件路径 + repo_root: 仓库根目录路径 + + Returns: + 包含日期、路径、心情记录、双语日记和语言标签的字典 + """ raw = path.read_text(encoding="utf-8") date_text = path.stem - zh_cell = _extract(ZH_TABLE_PATTERN, raw) + + # 提取双栏表格内容 + table_cells = _extract(ZH_TABLE_PATTERN, raw) + if isinstance(table_cells, tuple) and len(table_cells) == 2: + zh_cell, translated_cell = table_cells + else: + zh_cell, translated_cell = "", "" zh_diary = _clean_html_cell(zh_cell) + translated_diary = _clean_html_cell(translated_cell) + # 提取情绪短句素材 mood_record = html.unescape(_extract(MOOD_PATTERN, raw)) - random_language = _extract(r"> 本日随机语种:\*\*(.+?)\*\*", raw) + + # 解析语言标签 + language_tag = _parse_language_tag(raw) + return { "date": date_text, "log_path": path.relative_to(repo_root).as_posix(), "mood_record": mood_record or "今日心情记录已归档", "zh_diary": zh_diary or "暂无日志内容", - "random_language": random_language or "Unknown", + "translated_diary": translated_diary or "暂无翻译内容", + "language_tag": language_tag, } def export_web_logs_data(repo_root: Path) -> Path: + """扫描日志目录并导出为 JSON 数据文件。 + + 遍历 logs/ 下所有 YYYY/MM/YYYY-MM-DD.md 文件,提取结构化数据, + 按日期降序排列,输出到 web/logs.json。 + + Args: + repo_root: 仓库根目录路径 + + Returns: + 输出文件路径 + """ logs_root = repo_root / "logs" output_dir = repo_root / "web" output_dir.mkdir(parents=True, exist_ok=True) output_path = output_dir / "logs.json" + # 按日期降序排列所有日志文件 records: list[dict[str, str]] = [] for path in sorted(logs_root.glob("*/*/*.md"), reverse=True): records.append(_parse_log(path, repo_root)) diff --git a/scripts/run_daily_log.py b/scripts/run_daily_log.py index b3414f4..6dfe17d 100644 --- a/scripts/run_daily_log.py +++ b/scripts/run_daily_log.py @@ -79,7 +79,7 @@ def main() -> int: translated = translate_text(zh_text, lang_code, lang_name) # Step 4: 渲染 Markdown - markdown = render_markdown(target_date, materials, zh_text, lang_name, translated) + markdown = render_markdown(target_date, materials, zh_text, lang_code, translated) # Step 5: 写入文件 output = build_log_path(repo_root, target_date) diff --git a/web/app.js b/web/app.js index 8a13a53..a3eb411 100644 --- a/web/app.js +++ b/web/app.js @@ -1,9 +1,31 @@ -// 页面核心节点:右侧记录列表、北京时间显示和主题切换按钮。 +/** + * KiriMonoLog 前端交互模块 + * + * 功能: + * 1. 实时显示北京时间 + * 2. 加载 web/logs.json 并渲染每日记录卡片 + * 3. 支持白天/黑夜主题切换(偏好保存在 localStorage) + * 4. 双语日记分栏显示(中文 + 翻译版本) + */ + +// 语言短名称到全称映射(用于显示翻译部分的语言标签) +const SHORT_TO_FULL_NAME = { + EN: "English", + JP: "日本語", + KO: "한국어", + ZH: "中文", +}; + +// 页面核心节点 const bjTimeEl = document.getElementById("bj-time"); const recordsEl = document.getElementById("records"); const themeToggleEl = document.getElementById("theme-toggle"); const THEME_KEY = "kiri-theme"; +/** + * 获取北京时间各组成部分。 + * @returns {Object} 包含 year, month, day, hour, minute, second 的对象 + */ function getBeijingParts() { const fmt = new Intl.DateTimeFormat("zh-CN", { timeZone: "Asia/Shanghai", @@ -19,31 +41,71 @@ function getBeijingParts() { return parts; } +/** + * 根据北京时间判断应该使用白天还是黑夜主题。 + * 6:00-18:00 为白天,其余时间为黑夜。 + * @param {Object} parts - 北京时间组成部分 + * @returns {"day" | "night"} 主题名称 + */ function getThemeByBeijingTime(parts) { const hour = Number(parts.hour); return hour >= 6 && hour < 18 ? "day" : "night"; } +/** + * 更新主题切换按钮的文本。 + * @param {string} theme - 当前主题("day" 或 "night") + */ function updateThemeButton(theme) { themeToggleEl.textContent = theme === "night" ? "切换到白天" : "切换到黑夜"; } -// 使用北京时间推导默认主题,但一旦用户手动切换,就以 localStorage 中的偏好为准。 +/** + * 应用主题到页面。 + * 使用北京时间推导默认主题,但一旦用户手动切换,就以 localStorage 中的偏好为准。 + * @param {string} theme - 主题名称("day" 或 "night") + */ function applyTheme(theme) { document.body.dataset.theme = theme; updateThemeButton(theme); } +/** + * 同步北京时间显示。 + * @returns {Object} 北京时间组成部分 + */ function syncBeijingClock() { const parts = getBeijingParts(); bjTimeEl.textContent = `北京时间:${parts.year}-${parts.month}-${parts.day} ${parts.hour}:${parts.minute}:${parts.second}`; return parts; } +/** + * 从语言标签中提取翻译语言短名称,并转为全称。 + * 例如:"ZH + JP" → "日本語" + * @param {string} languageTag - 语言标签(格式:ZH + XX) + * @returns {string} 语言全称 + */ +function getLanguageFullName(languageTag) { + const shortName = languageTag.replace("ZH + ", ""); + return SHORT_TO_FULL_NAME[shortName] || shortName; +} + +/** + * 渲染单条记录卡片。 + * 卡片结构: + * - 头部:日期 + 语言标签 + * - 心情记录 + * - 双语内容区:中文原版 + 多语言版本 + * - 查看原始日志链接 + * @param {Object} record - 记录对象 + * @returns {HTMLElement} 卡片元素 + */ function renderRecord(record) { const card = document.createElement("article"); card.className = "card"; + // 头部:日期 + 语言标签 const header = document.createElement("div"); header.className = "card-header"; @@ -53,27 +115,57 @@ function renderRecord(record) { const language = document.createElement("span"); language.className = "card-language"; - language.textContent = record.random_language; + language.textContent = record.language_tag; header.append(date, language); + // 心情记录 const mood = document.createElement("p"); mood.className = "mood"; mood.textContent = `心情记录:${record.mood_record}`; - const diary = document.createElement("p"); - diary.className = "diary"; - diary.textContent = record.zh_diary; - + // 双语显示区域:中文原版 + 多语言版本 + const bilingualContainer = document.createElement("div"); + bilingualContainer.className = "bilingual"; + + // 中文部分 + const zhSection = document.createElement("div"); + zhSection.className = "bilingual-section"; + const zhLabel = document.createElement("span"); + zhLabel.className = "bilingual-label"; + zhLabel.textContent = "中文"; + const zhContent = document.createElement("p"); + zhContent.className = "diary"; + zhContent.textContent = record.zh_diary; + zhSection.append(zhLabel, zhContent); + + // 翻译部分 + const translatedSection = document.createElement("div"); + translatedSection.className = "bilingual-section"; + const translatedLabel = document.createElement("span"); + translatedLabel.className = "bilingual-label"; + translatedLabel.textContent = getLanguageFullName(record.language_tag); + const translatedContent = document.createElement("p"); + translatedContent.className = "diary"; + translatedContent.textContent = record.translated_diary; + translatedSection.append(translatedLabel, translatedContent); + + bilingualContainer.append(zhSection, translatedSection); + + // 查看原始日志链接 const logPath = document.createElement("a"); logPath.className = "log-link"; logPath.href = record.log_path; logPath.textContent = `查看原始日志:${record.log_path}`; - card.append(header, mood, diary, logPath); + card.append(header, mood, bilingualContainer, logPath); return card; } +/** + * 加载日志数据并渲染记录列表。 + * 从 web/logs.json 获取数据,按日期降序渲染卡片。 + */ async function loadLogs() { try { const resp = await fetch("web/logs.json", { cache: "no-store" }); @@ -90,15 +182,20 @@ async function loadLogs() { } } +// 初始化:同步时钟、应用主题、设置定时器 const initialParts = syncBeijingClock(); const savedTheme = localStorage.getItem(THEME_KEY); applyTheme(savedTheme || getThemeByBeijingTime(initialParts)); +// 主题切换事件 themeToggleEl.addEventListener("click", () => { const nextTheme = document.body.dataset.theme === "night" ? "day" : "night"; localStorage.setItem(THEME_KEY, nextTheme); applyTheme(nextTheme); }); +// 每秒更新时钟 setInterval(syncBeijingClock, 1000); + +// 加载日志数据 loadLogs(); diff --git a/web/logs.json b/web/logs.json index dcd3fa3..e42f729 100644 --- a/web/logs.json +++ b/web/logs.json @@ -1,208 +1,237 @@ { - "generated_at_utc": "2026-06-14T16:48:26.815704+00:00", + "generated_at_utc": "2026-06-15T01:55:57.215920+00:00", "records": [ { "date": "2026-06-14", "log_path": "logs/2026/06/2026-06-14.md", "mood_record": "Don't eat non-snow-coloured snow.", "zh_diary": "今天是2026-06-14,一个淡淡阳光洒进窗台的日子。桐雾(Kiri)翻着今天收集的小碎片,「Don't eat non-snow-coloured snow.」——这是我今天最想记住的一句话。安静地度过一天,也是一种了不起的事。", - "random_language": "日本語" + "translated_diary": "今日は2026年6月14日、かすかな日差しが窓辺にこぼれ落ちる日です。キリは今日集めた小片をひっくり返し、「雪色のない雪は食べてはいけません。\"--これは私が今日最も覚えておきたい引用です。安らかな1日を過ごすことも素晴らしいことです。", + "language_tag": "ZH + JP" }, { "date": "2026-06-13", "log_path": "logs/2026/06/2026-06-13.md", - "mood_record": "Brush your teeth the moment you get up.", - "zh_diary": "2026-06-13的日记。\n桐雾(Kiri)在想,幸福大概就是这些细碎的、不完美的日常。试着对镜子里的自己笑了一下,感觉还不错。\n等待,不是为了你能回来,而是找个借口不离开。", - "random_language": "日本語" + "mood_record": "Cars are bad investments.", + "zh_diary": "2026-06-13的日记。\n桐雾(Kiri)在想,幸福大概就是这些细碎的、不完美的日常。试着对镜子里的自己笑了一下,感觉还不错。\n我于杀戮之中盛放,亦如黎明中的花朵。", + "translated_diary": "2026年6月13日の日記。\nキリは、幸福とはおそらく、これらの美しく不完全な日常のことであると考えています。鏡の中の自分に微笑んでみてください。気持ちいいです。\n私は夜明けの花のように、屠殺の真っ只中に咲く。", + "language_tag": "ZH + JP" }, { "date": "2026-06-12", "log_path": "logs/2026/06/2026-06-12.md", "mood_record": "There is no reason at all to believe that White Wine is any different to water when it comes to removing Red Wine stains.", "zh_diary": "叮——2026-06-12的桐雾(Kiri)报道!翻开今天的笔记本,发现值得记住的事真不少!A female ferret will die if it goes into heat and cannot find a mate.今天先好好休息吧,明天见~", - "random_language": "日本語" + "translated_diary": "ディン- 2026年6月12日のキリレポート!今日のノートを開いてみると、覚えておくべきことがたくさんあることがわかりました!メスのフェレットは、熱くなっても仲間が見つからないと死んでしまいます。今日はゆっくり休んで、また明日ね~", + "language_tag": "ZH + JP" }, { "date": "2026-06-11", "log_path": "logs/2026/06/2026-06-11.md", "mood_record": "Opinions are like arseholes, everyone has one.", "zh_diary": "2026-06-11。风穿过窗缝,带来了远方的声音。桐雾(Kiri)今天想起了一句话:「Ramses brand condom is named after the great pharaoh Ramses II who fathered over 160 children.」——这句话在今天的空气里显得格外温柔。", - "random_language": "日本語" + "translated_diary": "2026 -06 -11風が窓の縫い目を通過し、遠くから音をもたらす。キリは今日、次の文を思い出しました。「ラムセスブランドのコンドームは、160人以上の子供をもうけた偉大なファラオのラムセス2世にちなんで名付けられました。\"--この文は今日の空気の中では非常に優しい。", + "language_tag": "ZH + JP" }, { "date": "2026-06-10", "log_path": "logs/2026/06/2026-06-10.md", "mood_record": "Don't cross the streams.", "zh_diary": "2026-06-10,桐雾(Kiri)在窗边记录今天的思绪。今天没有特别的事,但就是莫名的心情很好。我不道啊。", - "random_language": "日本語" + "translated_diary": "2026 -06 -10、キリは今日の考えを窓際に記録する。今日は特別なことは何もありませんが、気分は良いです。何とも言えません。", + "language_tag": "ZH + JP" }, { "date": "2026-06-09", "log_path": "logs/2026/06/2026-06-09.md", "mood_record": "When painting a room, preparation is key. The actual painting should account for about 40% of the work.", "zh_diary": "2026-06-09的日记。\n桐雾(Kiri)在想,幸福大概就是这些细碎的、不完美的日常。试着对镜子里的自己笑了一下,感觉还不错。\n我会一直喜欢到你不再需要我喜欢你为止。", - "random_language": "English" + "translated_diary": "Diary of 2026-06-09.\nKiri is thinking that happiness is probably these fine, imperfect everyday things.Try to smile at yourself in the mirror, it feels good.\nI will always like it until you no longer need me to like you.", + "language_tag": "ZH + EN" }, { "date": "2026-06-08", "log_path": "logs/2026/06/2026-06-08.md", "mood_record": "Cars are bad investments.", "zh_diary": "叮——2026-06-08的桐雾(Kiri)报道!翻开今天的笔记本,发现值得记住的事真不少!如果喜欢和合适撞个满怀多好。今天先好好休息吧,明天见~", - "random_language": "English" + "translated_diary": "Ding - Reported by Kiri on 06/08/2026! Opening today's notebook, I found that there are a lot of things worth remembering! How nice it would be to have a bump full of likes and fit. Take a good rest today, see you tomorrow ~", + "language_tag": "ZH + EN" }, { "date": "2026-06-07", "log_path": "logs/2026/06/2026-06-07.md", "mood_record": "Value the people in your life.", "zh_diary": "2026-06-07。风穿过窗缝,带来了远方的声音。桐雾(Kiri)今天想起了一句话:「不是我熬夜,是黑夜需要我这颗璀璨明亮的星。」——这句话在今天的空气里显得格外温柔。", - "random_language": "日本語" + "translated_diary": "2026 -06 -07.風が窓の縫い目を通過し、遠くから音をもたらします。キリは今日の言葉を思い出しました。「遅くまで起きているのは私ではなく、私の明るい星を必要としているのは夜です。\"--この文は今日の空気の中では非常に優しい。", + "language_tag": "ZH + JP" }, { "date": "2026-06-06", "log_path": "logs/2026/06/2026-06-06.md", "mood_record": "Be brave. Even if you're not, pretend to be. No one can tell the difference.", "zh_diary": "2026-06-06,桐雾(Kiri)在窗边记录今天的思绪。今天没有特别的事,但就是莫名的心情很好。Be brave. Even if you're not, pretend to be. No one can tell the difference.", - "random_language": "日本語" + "translated_diary": "2026 -06 -06、きりは今日の思いを窓際に記録する。今日は特別なことは何もありませんが、気分は良いです。勇気を出しましょう。勇気がなくても、勇気を出したふりをしてください。違いは誰にもわかりません。", + "language_tag": "ZH + JP" }, { "date": "2026-06-05", "log_path": "logs/2026/06/2026-06-05.md", "mood_record": "Some of life's best lessons are learnt at the worst times.", "zh_diary": "今天是2026-06-05,一个风很轻很轻的日子。桐雾(Kiri)翻着今天收集的小碎片,「知道活着的痛苦处的人就能对人温柔,这和软弱是不一样的。」——这是我今天最想记住的一句话。有时候最好的治愈,就是允许自己什么都不做。", - "random_language": "日本語" + "translated_diary": "今日は2026年6月5日、非常に軽い日であり、非常に軽い風が吹いています。きりは、今日集めた小片をひっくり返し、「生きていることの痛みを知っている人が他の人に優しくできるのは、弱さとは違います。\"--これは私が今日最も覚えておきたい引用です。時には最善の治療法は、何もしないようにすることです。", + "language_tag": "ZH + JP" }, { "date": "2026-06-04", "log_path": "logs/2026/06/2026-06-04.md", "mood_record": "When something goes wrong in life, just shout \"plot twist!\" and carry on.", "zh_diary": "2026-06-04的日记。\n桐雾(Kiri)在想,成长不是突然变好,而是一点一点靠近光亮。有时候,「就这样也挺好」是最棒的答案。\n我不甘心,明明你为我做了那么多,我却什么都不能为你做。", - "random_language": "한국어" + "translated_diary": "Diary on 06/04/2026.\n키리는 성장이 갑자기 나아지는 것이 아니라 조금씩 빛에 가까워지는 것이라고 생각하고 있습니다.때로는 그것이 최선의 대답입니다.\n나는 원하지 않습니다, 당신은 나를 위해 너무 많은 일을했지만, 나는 당신을 위해 아무것도 할 수 없습니다.", + "language_tag": "ZH + KO" }, { "date": "2026-06-03", "log_path": "logs/2026/06/2026-06-03.md", "mood_record": "Be brave. Even if you're not, pretend to be. No one can tell the difference.", "zh_diary": "叮——2026-06-03的桐雾(Kiri)报道!今天也是被美食和好天气宠爱的一天呢!In 1986 Congress & President Ronald Reagan signed Public Law 99-359, which changed Daylight Saving Time from the last Sunday in April to the first Sunday in April.  It was estimated to save the nation about 300,000 barrels of oil each year by adding most of the month April to D.S.T.每一天都是新的故事,我们一起慢慢写。", - "random_language": "English" + "translated_diary": "Ding - Reported by Kiri on 06/03/2026! Today is also a day that is loved by good food and good weather! In 1986 Congress & President Ronald Reagan signed Public Law 99-359, which changed Daylight Saving Time from the last Sunday in April to the first Sunday in April. It was estimated to save the nation about 300,000 barrels of oil each year by adding most of the month April to D.S.T. Every day is a new story, and we write it slowly together.", + "language_tag": "ZH + EN" }, { "date": "2026-06-02", "log_path": "logs/2026/06/2026-06-02.md", "mood_record": "When you're looking up at birds flying overhead, keep your mouth closed.", "zh_diary": "2026-06-02。午后的光影在地板上缓缓移动。桐雾(Kiri)今天想起了一句话:「把温柔和心软留给值得的人。」——有些道理离我们很近,只是平时太忙,没空听见它们。", - "random_language": "English" + "translated_diary": "2026-06-02. The afternoon light and shadow move slowly on the floor. Kiri remembered a quote today: “Leave gentleness and softness of heart to those who deserve it.\" --Some truths are very close to us, but they are usually too busy to hear them.", + "language_tag": "ZH + EN" }, { "date": "2026-06-01", "log_path": "logs/2026/06/2026-06-01.md", "mood_record": "Don't feed Mogwais after midnight.", "zh_diary": "2026-06-01,桐雾(Kiri)在黄昏的光里写下一段话。偶然听到一首歌,旋律像极了某个久远的午后。The sound of E.T. walking was made by someone squishing her hands in jelly.", - "random_language": "한국어" + "translated_diary": "2026-06-01, Kiri는 황혼에 비추어 문장을 씁니다. 우연히 노래를 들었는데, 멜로디가 긴 오후 같았다. E.T. 가 걷는 소리는 누군가 젤리에 손을 집어넣어서 내는 소리였다.", + "language_tag": "ZH + KO" }, { "date": "2026-05-31", "log_path": "logs/2026/05/2026-05-31.md", "mood_record": "The quieter you become, the more you can hear.", "zh_diary": "叮——2026-05-31的桐雾(Kiri)报道!伸个大大的懒腰,和今天的自己说嗨~The quieter you become, the more you can hear.明天也要元气满满哦!", - "random_language": "English" + "translated_diary": "Ding—this is Kiri (2026‑05‑31) reporting! Stretching out with a long, lazy sigh, I greet the self of today. The quieter you become, the more you can hear. Let tomorrow be brimming with vitality as well.", + "language_tag": "ZH + EN" }, { "date": "2026-05-30", "log_path": "logs/2026/05/2026-05-30.md", "mood_record": "To cleanly remove the seed from an Avocado, lay a knife firmly across it, and twist.", "zh_diary": "2026-05-30。云在慢慢走,时间也是。桐雾(Kiri)今天想起了一句话:「缘起,我在人群中看见你;缘落,我看见你在人群中。」——把它记下来,也许未来的哪一天会再遇见它。", - "random_language": "English" + "translated_diary": "2026-05-30. The clouds are walking slowly, and so is time. Kiri remembered a sentence today: \"I saw you in the crowd from the beginning; I saw you in the crowd from the end.” -Jot it down, and maybe some day in the future you'll see it again.", + "language_tag": "ZH + EN" }, { "date": "2026-05-29", "log_path": "logs/2026/05/2026-05-29.md", "mood_record": "One of the single best things about being an adult, is being able to buy as much LEGO as you want.", "zh_diary": "2026-05-29\n今天天气有些微凉,楼下的雾气像旧书页的松脆。今天在午后的咖啡店里,偶然听到一个笑话——哈里·S.·杜鲁门的中间点F不代表任何东西,原来是名字的无特指随意。让我想起成长的无名时光,人生也许就是一连串无意识的名字。忙碌间,我把温柔收藏在小手提包里。离家不远的玩具店灯光闪烁,孩子们的笑声像石子一样在空气里跳跃,让我明白,成年的一大乐趣,正是买到想要的乐高积木,沉浸在自己的宇宙里。傍晚,我拿起冰镇可乐,清凉顺口,甜与", - "random_language": "English" + "translated_diary": "2026-05-29\nThe weather is a little cool today, and the fog downstairs is as crisp as an old book page.In the afternoon coffee shop today, I overheard a joke - Harry S.· Truman's midpoint F does not represent anything, it turns out that it is an unspecified name.Reminds me of the nameless days of growing up, life may be a series of unconscious names.While I was busy, I collected the gentleness in a small handbag.The lights of the toy store not far from home flashed, and the laughter of the children jumped in the air like a stone, which made me understand that one of the great joys of adulthood is to buy the Lego bricks you want and immerse yourself in your own universe.In the evening, I picked up the chilled Coke, which was cool and smooth, sweet and", + "language_tag": "ZH + EN" }, { "date": "2026-05-28", "log_path": "logs/2026/05/2026-05-28.md", "mood_record": "Try going commando to an important meeting, NB: don't wear a skirt.", "zh_diary": "2026-05-28的日记。\n桐雾(Kiri)在想,很多事情没有标准答案,重要的是你怎样看待它。今天学到的新功课:休息不是偷懒,是为下一段路积蓄力量。\nTry going commando to an important meeting, NB: don't wear a skirt.", - "random_language": "English" + "translated_diary": "Diary of 2026-05-28.\nKiri is thinking that a lot of things don't have a standard answer, what matters is how you think about it.A new lesson learned today: Rest isn't laziness, it's about building strength for the next step.\nTry going commando to an important meeting, NB: don't wear a skirt.", + "language_tag": "ZH + EN" }, { "date": "2026-05-27", "log_path": "logs/2026/05/2026-05-27.md", "mood_record": "Life is short enough, don't race to the finish.", "zh_diary": "叮——2026-05-27的桐雾(Kiri)报道!伸个大大的懒腰,和今天的自己说嗨~Life is short enough, don't race to the finish.明天也要元气满满哦!", - "random_language": "English" + "translated_diary": "Ding - Reported by Kiri on May 27, 2026! Stretch out and say hi to yourself today ~ Life is short enough, don't race to the finish. Tomorrow will also be full of energy!", + "language_tag": "ZH + EN" }, { "date": "2026-05-26", "log_path": "logs/2026/05/2026-05-26.md", "mood_record": "Make choices and dont look back.", "zh_diary": "2026-05-26\n今天的天空像抹淡淡的蓝灰,轻轻的风拂过窗台,太阳的光斑碎碎在木地板上,随手拍一张记录小确幸的小照——一只小猫的尾巴在午后的光里摇晃。走在回家的小径上,我忽然想起一则趣味小知识:李小龙的动作快得连慢动作摄像机都得放慢快门才能清晰捕捉。想到这里,心里暗暗佩服那种速度与精准的结合,也不免激起我对选择的思考。Make choices and dont look back。或许每一步都值得把握,也许每一次回望都会带走一丝温柔。\n我在电脑上打起字时,意识到隔着屏幕轻易产生感情的你,肯定很孤独吧。于是写下这句治愈文案,提醒自己也要给内心留一片轻柔的空间。不论今天多么平凡,都值得被温柔记录。温柔的夜色悄然降临,我把笔轻轻收起来,期待明日的轻风。", - "random_language": "한국어" + "translated_diary": "2026-05-26\n오늘의 하늘은 희미한 푸른 회색과 같고, 창틀을 가로질러 부드러운 바람이 불고, 나무 바닥에 태양의 반점이 부서지며, 기록의 작은 사진을 찍을 수 있습니다. 새끼 고양이의 꼬리가 오후의 빛에 흔들립니다.집으로 가는 길을 걷다 문득 재미있는 작은 지식이 떠올랐다. 브루스 리의 움직임이 너무 빨라 슬로우 모션 카메라조차 셔터를 선명하게 캡처하려면 셔터 속도를 늦춰야 했다.이런 생각에 내 마음은 은근히 스피드와 정밀함의 조합에 감탄했고, 내 선택에 대해서도 생각해보게 했다.선택을 하고 뒤돌아보지 마세요.어쩌면 모든 발걸음이 파악할 가치가 있을 수도 있고, 뒤를 돌아볼 때마다 약간의 온유함이 사라질 수도 있습니다.\n컴퓨터를 입력하면 화면을 통해 쉽게 감정을 느낄 수 있다는 것을 깨닫고 매우 외로워해야합니다.그래서 그는 마음에 온화한 공간을 남겨두라고 상기시키며 이 치유 사본을 썼습니다.오늘날 아무리 평범하더라도 부드럽게 기록해야 마땅합니다.고요한 밤이 찾아와 내일의 가벼운 바람을 바라보며 부드럽게 펜을 치웠다.", + "language_tag": "ZH + KO" }, { "date": "2026-05-25", "log_path": "logs/2026/05/2026-05-25.md", "mood_record": "Life is short enough, don't race to the finish.", "zh_diary": "2026-05-25,桐雾(Kiri)在夜晚的灯光下整理心情。翻开日历才发现,时间真的过得比想象中快。The 3 most valuable brand names on earth are Marlboro, Coca-Cola, and Budweiser (in that order).", - "random_language": "日本語" + "translated_diary": "2026年5月25日、桐雾(Kiri)は夜の灯りの中で心をほぐす。日历をめくると、時間が想像よりも速く過ぎ去ったことに気付く。地球上の価値あるブランド名の中で、最も価値が高いのは順にマールボロ、コカ・コーラ、バドワイザーである。", + "language_tag": "ZH + JP" }, { "date": "2026-05-24", "log_path": "logs/2026/05/2026-05-24.md", "mood_record": "今日心情记录已归档", "zh_diary": "2026年5月24日,今天的天空像轻纱一样柔和,我在阳台上慢慢喝咖啡,听见一声轻响。原来是办公室的复印机因为有人误把尾巴放进纸盒,笑声随之绽放——据统计,这类错误占全球复印机故障的23%。这让我想起了春天的慢热,春天来得很慢,春天才有浪漫。外面偶尔有一只小鸟翩翩落在窗台边,轻扫枝头,究竟是星光在眺望还是心事在呼唤,谁知道呢。我把这点点宁静留在心底,像种子一样静静等待盛开。", - "random_language": "日本語" + "translated_diary": "2026年5月24日、空は明るいベールのように柔らかく、私はバルコニーでゆっくりとコーヒーを飲み、柔らかい音が聞こえました。統計によると、オフィスのコピー機は、誰かが誤って紙箱に尾を入れたために笑ったことが判明しました。これは、世界中のコピー機の失敗の23 %を占める間違いです。これは春のゆっくりとした暑さを思い出させ、春はゆっくりとやってきて、春はロマンチックです。時折、小さな鳥が外の窓の敷居に落ちて枝を掃除していました。星の光が見ているのか、心が呼んでいるのかは誰にもわかりません。私はこの小さな静けさを心の底に残し、それが種のように咲くのを静かに待っています。", + "language_tag": "ZH + JP" }, { "date": "2026-05-23", "log_path": "logs/2026/05/2026-05-23.md", "mood_record": "One of the top five regrets people have is that they didn't stay in contact with friends.", "zh_diary": "2026-05-23的日记。\n桐雾(Kiri)在想,幸福大概就是这些细碎的、不完美的日常。试着对镜子里的自己笑了一下,感觉还不错。\n幸福的家庭都是相似的,不幸的家庭各有各的不幸。", - "random_language": "한국어" + "translated_diary": "2026-05-23의 일기.\n키리는 행복은 아무래도 멀쩡하고 불완전한 일상일 거라고 생각해요.거울에 비친 자신에게 미소를 지어보세요. 기분이 좋습니다.\n행복한 가정은 비슷하고, 불행한 가정은 자신의 불행이 있습니다.", + "language_tag": "ZH + KO" }, { "date": "2026-05-22", "log_path": "logs/2026/05/2026-05-22.md", "mood_record": "Turn jeans inside out when washing them to help preserve their colour.", "zh_diary": "叮——2026-05-22的桐雾(Kiri)报道!翻开今天的笔记本,发现值得记住的事真不少!The electric chair was invented by a dentist.今天先好好休息吧,明天见~", - "random_language": "English" + "translated_diary": "Ding - Reported by Kiri on May 22, 2026! Opening today's notebook, I found that there are a lot of things worth remembering! The electric chair was invented by a dentist. Take a good rest today, see you tomorrow ~", + "language_tag": "ZH + EN" }, { "date": "2026-05-21", "log_path": "logs/2026/05/2026-05-21.md", "mood_record": "If it ain't broke don't fix it.", "zh_diary": "2026-05-21 \n今天的天空像一张轻纱,微风带着棕榈林的香气。记起那句“懂得爱,拥有爱,追寻爱,感受爱,与爱相伴,被爱治愈”(来源: 落雨),让我在此刻觉得温暖。偶然看到一条趣味小知识:Nutmeg if injected intravenously is extremely poisonous(来源: djtech.net)。晚上睡前脑海里浮现一句俏皮的话:“If it ain't broke don't fix it”(来源: AdviceSlip),提醒我放慢节奏,不必给宁静加上标签。把这份轻盈写进日记,又像拾起一粒细小温柔的碎光。", - "random_language": "한국어" + "translated_diary": "2026-05-21 \n오늘 하늘은 가볍게 휘날리는 장막처럼 보였고, 부드러운 바람이 야자수 향을 실어 보냈다. \n“사랑을 아는 것, 사랑을 갖는 것, 사랑을 찾는 것, 사랑을 느끼는 것, 사랑과 함께 있는 것, 사랑에 치유되는 것”이라는 말이 떠올라, 그 순간이 부드러운 온기로 가득했다. \n정작 우연히 발견한 작은 재미있는 사실이 있었다: \n> 정맥 주사로 육두구를 주입하면 극히 독성이 강하다 (출처: djtech.net) \n밤에 잠들기 전에 머릿속을 스쳐간 유쾌한 문구는 다음과 같았다: \n> 고장 낫지 않은 것은 고치지 말라 (출처: AdviceSlip) \n이처럼 가벼운 느낌을 일기에 적으며, 작은 부드러운 빛 조각을 주워 담아 보듯 느꼈다.", + "language_tag": "ZH + KO" }, { "date": "2026-05-20", "log_path": "logs/2026/05/2026-05-20.md", "mood_record": "Don't wear clean trousers when walking your dog in the park.", "zh_diary": "2026-05-20,桐雾(Kiri)在窗边记录今天的思绪。今天没有特别的事,但就是莫名的心情很好。Don't wear clean trousers when walking your dog in the park.", - "random_language": "日本語" + "translated_diary": "2026 -05 -20、キリは今日の考えを窓際に記録する。今日は特別なことは何もありませんが、気分は良いです。公園で犬を散歩させるときは、清潔なズボンを着用しないでください。", + "language_tag": "ZH + JP" }, { "date": "2026-05-19", "log_path": "logs/2026/05/2026-05-19.md", "mood_record": "A problem shared is a problem halved.", "zh_diary": "2026-05-19 \n天空柔软,月光洒在旧屋角落,像抹淡粉的泪珠。早起时听朋友说,猫尿在黑光下会发光,仿佛它们把一条彩虹留给路人。 \n我坚信:“把问题说出来,问题就会减半。”于是我把这份小担忧悄悄分给日记页,感觉整整变轻了许多。 \n午后行走在河边,忽然朗朗上口“春潮带雨晚来急,野渡无人舟自横”,像是一首温柔的老歌,提醒我即使风景寂静,心中仍旧有春天。 \n今天的点滴,我用最温柔的文字记录,让每一个小确幸都成为心里一条微光的丝线。", - "random_language": "한국어" + "translated_diary": "2026-05-19 \n하늘은 부드럽고, 달빛은 가루로 얼룩진 눈물처럼 옛 집 모퉁이에 뿌려진다.일찍 일어났을 때 지나가는 사람들에게 무지개를 남긴 것처럼 검은 빛에 고양이 소변이 빛났다는 친구들의 이야기를 들었습니다. \n나는 단호하게 믿는다. \"문제를 말하면 문제는 반으로 줄어들 것이다.\"그래서 나는 이 작은 걱정을 훨씬 가벼워진 느낌으로 일기장에 조용히 나눠주었다. \n오후에 강가를 거닐다 문득 “봄 물결은 비와 밤으로 불안하고, 광야는 배가 없다” 고 말하며 온화한 옛 노래처럼 풍경이 고요해도 마음속에는 여전히 봄이 있다는 것을 일깨워 주었다. \n오늘, 나는 가장 온화한 단어를 사용하여 모든 작은 재산이 내 마음 속에 반짝이는 비단 실이되도록 기록합니다.", + "language_tag": "ZH + KO" }, { "date": "2026-05-18", "log_path": "logs/2026/05/2026-05-18.md", "mood_record": "Your smile could make someone's day, don't forget to wear it.", "zh_diary": "叮——2026-05-18的桐雾(Kiri)报道!翻开今天的笔记本,发现值得记住的事真不少!只顾眼前的利益而任人摆布……我已经……受够了……今天先好好休息吧,明天见~", - "random_language": "日本語" + "translated_diary": "叮—2026年5月18日の桐雾(Kiri)からご報告です。今日のノートを開いたら、記憶に留めておきたい出来事がとても多いと気づきました。眼前の利益だけを追い、他人に操られてしまうままに…もう、もう十分です。今日はゆっくり休んで、また明日お会いしましょう。", + "language_tag": "ZH + JP" }, { "date": "2026-05-14", "log_path": "logs/2026/05/2026-05-14.md", "mood_record": "Never regret. If it's good, it's wonderful. If it's bad, it's experience.", "zh_diary": "2026年5月14日,天空像浅蓝的纸,轻轻抖动着雾气。 \n今天在咖啡店里,旁边的姑娘低声说:“Never regret. If it's good, it's wonderful. If it's bad, it's experience.” 这句提醒我,回忆不再是负担,而是温柔的光。 \n午后翻开笔记本,惊讶地看到一个小小趣闻:Saturday Night Live 的第一位女司仪竟是 Candace Bergen。想到她在聚光灯下的坚定,我不禁感受到自己的小小勇气。 \n夕风拂过窗台,若你是在我阴郁时爱上我,那我无话可说;但今天的阳光让我有力地笑着说“谢谢”,把这份温暖收进心坎。", - "random_language": "English" + "translated_diary": "May 14, 2026 \nThe sky lay like a sheet of pale blue paper, quivering softly under a mist that barely stirred. \nIn a café today, a girl beside me whispered, “Never regret. If it’s good, it’s wonderful. If it’s bad, it’s experience.” Those words shifted my memory from a heavy burden into a gentle light. \nLater, I opened my notebook and found a small anecdote that surprised me: the first female host of *Saturday Night Live* was, in fact, Candace Bergen. Thinking of her poised stance beneath the spotlight made me feel a quiet surge of courage in myself. \nA breeze brushed the windowsill. If you had fallen for me in the midst of my gloom, I have nothing left to say; but today’s sunshine let me laugh openly, “Thank you,” and tuck that warmth deep into my heart.", + "language_tag": "ZH + EN" } ] } diff --git a/web/styles.css b/web/styles.css index 7ded8ce..905c8a6 100644 --- a/web/styles.css +++ b/web/styles.css @@ -208,10 +208,31 @@ body { } .diary { - margin: 0 0 16px; + margin: 0; white-space: pre-wrap; } +.bilingual { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 16px; + margin-bottom: 16px; +} + +.bilingual-section { + display: flex; + flex-direction: column; + gap: 8px; +} + +.bilingual-label { + font-size: 12px; + font-weight: 600; + color: var(--subtext); + text-transform: uppercase; + letter-spacing: 0.1em; +} + .log-link { color: var(--accent); text-decoration: none;
中文原版多语言版本
(.*?)(.*?)