Kaynağa Gözat

Add i18n support to Clock widget for all 6 arozos locales

- Create Clock/locale/clock.json with translations for en-us, zh-cn,
  zh-tw, zh-hk, ja-jp, and ko-kr covering UI labels, status strings,
  window titles, button tooltips, and the timezone search placeholder
- Load applocale.js and initialise it at boot; boot is deferred into
  the applocale callback so translate() runs before any dynamic render
- Add locale/title/placeholder attributes to all static HTML strings
  (tab labels, countdown units, world-clock toolbar, tz-sheet header,
  stopwatch status, empty state)
- Introduce getStr() helper for dynamically generated strings
  (stopwatch status, "No results", window titles, remove-button title)
- Introduce getDateLocale() that maps the stored global_language
  preference to a BCP-47 tag so weekday/date strings displayed in
  the digital clock and world-clock hero card respect the UI locale

https://claude.ai/code/session_019JJo6yrD9D6Cp4trTr8SHa
Claude 2 hafta önce
ebeveyn
işleme
4e8d80b6d7
2 değiştirilmiş dosya ile 315 ekleme ve 33 silme
  1. 70 33
      src/web/Clock/index.html
  2. 245 0
      src/web/Clock/locale/clock.json

+ 70 - 33
src/web/Clock/index.html

@@ -6,6 +6,7 @@
     <title>Clock</title>
     <script src="../script/jquery.min.js"></script>
     <script src="../script/ao_module.js"></script>
+    <script src="../script/applocale.js"></script>
     <style>
         *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
 
@@ -406,19 +407,19 @@
     <div class="tab-bar">
         <button class="tab-btn active" id="tab-clock-btn" onclick="switchTab('clock')">
             <img class="theme-icon" data-icon="clock" src="img/icons/clock_black.svg">
-            Clock
+            <span locale="clock/tab-clock">Clock</span>
         </button>
         <button class="tab-btn" id="tab-world-btn" onclick="switchTab('world')">
             <img class="theme-icon" data-icon="globe" src="img/icons/globe_black.svg">
-            World
+            <span locale="clock/tab-world">World</span>
         </button>
         <button class="tab-btn" id="tab-countdown-btn" onclick="switchTab('countdown')">
             <img class="theme-icon" data-icon="countdown" src="img/icons/countdown_black.svg">
-            Countdown
+            <span locale="clock/tab-countdown">Countdown</span>
         </button>
         <button class="tab-btn" id="tab-stopwatch-btn" onclick="switchTab('stopwatch')">
             <img class="theme-icon" data-icon="timer" src="img/icons/timer_black.svg">
-            Stopwatch
+            <span locale="clock/tab-stopwatch">Stopwatch</span>
         </button>
     </div>
 
@@ -455,19 +456,19 @@
 
         <!-- Toolbar -->
         <div class="wc-toolbar">
-            <span class="wc-section-lbl">Other Clocks</span>
+            <span class="wc-section-lbl" locale="clock/other-clocks">Other Clocks</span>
             <button class="wc-add-btn" onclick="tzPickerShow()">
                 <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3.5" stroke-linecap="round">
                     <line x1="12" y1="4" x2="12" y2="20"/><line x1="4" y1="12" x2="20" y2="12"/>
                 </svg>
-                Add City
+                <span locale="clock/add-city">Add City</span>
             </button>
         </div>
 
         <!-- Empty state -->
         <div id="wc-empty" style="display:none;">
             <img class="theme-icon" data-icon="globe" src="img/icons/globe_black.svg" width="44" height="44">
-            No clocks yet.<br>Tap <b>+ Add City</b> to get started.
+            <span locale="clock/no-clocks-empty">No clocks yet.<br>Tap <b>+ Add City</b> to get started.</span>
         </div>
 
         <!-- Clock list -->
@@ -496,11 +497,11 @@
             <span></span>
             <button class="cd-arrow" id="cd-dn-s" onclick="cdAdjust('s',-1)">▼</button>
 
-            <div class="cd-lbl">Hours</div>
+            <div class="cd-lbl" locale="clock/cd-hours">Hours</div>
             <span></span>
-            <div class="cd-lbl">Minutes</div>
+            <div class="cd-lbl" locale="clock/cd-minutes">Minutes</div>
             <span></span>
-            <div class="cd-lbl">Seconds</div>
+            <div class="cd-lbl" locale="clock/cd-seconds">Seconds</div>
         </div>
 
         <div class="cd-progress-wrap">
@@ -528,7 +529,7 @@
             <span id="sw-hm">00:00</span><span class="sw-dim">:</span><span id="sw-s">00</span><span class="sw-dim sw-cs">.<span id="sw-cs-val">00</span></span>
         </div>
 
-        <div class="sw-status" id="sw-status">Ready</div>
+        <div class="sw-status" id="sw-status" locale="clock/status-ready">Ready</div>
 
         <div class="ctrl-row">
             <button id="sw-btn-toggle" class="ctrl-btn btn-play" onclick="swToggle()" title="Start / Pause">
@@ -551,7 +552,7 @@
 <div id="tz-overlay" onclick="if(event.target===this)tzPickerHide()">
     <div class="tz-sheet">
         <div class="tz-sheet-header">
-            <span class="tz-sheet-title">Choose a City</span>
+            <span class="tz-sheet-title" locale="clock/tz-sheet-title">Choose a City</span>
             <button class="tz-sheet-close" onclick="tzPickerHide()">✕</button>
         </div>
         <input class="tz-search" id="tz-search" type="search" placeholder="Search city or region…" oninput="tzFilter(this.value)">
@@ -563,10 +564,29 @@
 // ════════════════════════════════════════════════════════════════════════
 //  SETUP
 // ════════════════════════════════════════════════════════════════════════
-ao_module_setWindowTitle('Clock');
 ao_module_setFixedWindowSize();
 ao_module_setWindowSize(420, 450);
 
+function getStr(key, fallback) {
+    return (typeof applocale !== 'undefined' && applocale) ? applocale.getString(key, fallback) : fallback;
+}
+
+// Returns BCP-47 locale string for date/time formatting based on the user's
+// arozos language preference, falling back to the browser's locale.
+function getDateLocale() {
+    var lang = (localStorage.getItem('global_language') || 'default').toLowerCase();
+    if (lang === 'default' || lang === '') return navigator.language;
+    var map = {
+        'en-us': 'en-US',
+        'zh-cn': 'zh-CN',
+        'zh-tw': 'zh-TW',
+        'zh-hk': 'zh-HK',
+        'ja-jp': 'ja-JP',
+        'ko-kr': 'ko-KR'
+    };
+    return map[lang] || lang;
+}
+
 function pad(n){ return n < 10 ? '0'+n : String(n); }
 function htmlEsc(s){
     return s.replace(/&/g,'&amp;').replace(/"/g,'&quot;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
@@ -615,8 +635,13 @@ function switchTab(id){
         document.getElementById('tab-'+t+'-btn').classList.toggle('active', t === id);
         document.getElementById('panel-'+t).classList.toggle('active', t === id);
     });
-    var labels = { clock:'Clock', world:'World Clock', countdown:'Countdown', stopwatch:'Stopwatch' };
-    ao_module_setWindowTitle('Clock — ' + labels[id]);
+    var labels = {
+        clock:     getStr('clock/wintitle-main',      'Clock'),
+        world:     getStr('clock/wintitle-world',     'World Clock'),
+        countdown: getStr('clock/wintitle-countdown', 'Countdown'),
+        stopwatch: getStr('clock/wintitle-stopwatch', 'Stopwatch')
+    };
+    ao_module_setWindowTitle(getStr('clock/wintitle-main', 'Clock') + ' — ' + labels[id]);
 }
 
 // ════════════════════════════════════════════════════════════════════════
@@ -628,9 +653,9 @@ function updateDigitalClock(){
     document.getElementById('dc-m').textContent    = pad(now.getMinutes());
     document.getElementById('dc-s').textContent    = pad(now.getSeconds());
     document.getElementById('dc-day').textContent  =
-        now.toLocaleDateString('en-US', { weekday: 'long' });
+        now.toLocaleDateString(getDateLocale(), { weekday: 'long' });
     document.getElementById('dc-date').textContent =
-        now.toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' });
+        now.toLocaleDateString(getDateLocale(), { month: 'long', day: 'numeric', year: 'numeric' });
 }
 
 // ════════════════════════════════════════════════════════════════════════
@@ -656,7 +681,7 @@ function updateLocalClock(){
     document.getElementById('lc-sec').textContent  = ':' + pad(s);
     // Date
     document.getElementById('lc-date').textContent =
-        now.toLocaleDateString('en-US', { weekday:'short', month:'short', day:'numeric' });
+        now.toLocaleDateString(getDateLocale(), { weekday:'short', month:'short', day:'numeric' });
 }
 
 function initLocalClock(){
@@ -780,7 +805,7 @@ function wcRender(){
                 '<span class="wc-time" id="wc-hm-'+i+'">--:--</span>' +
                 '<span class="wc-secs" id="wc-sec-'+i+'"></span>' +
             '</div>' +
-            '<button class="wc-remove" onclick="wcRemove('+i+')" title="Remove">×</button>' +
+            '<button class="wc-remove" onclick="wcRemove('+i+')" title="'+getStr('clock/btn-remove','Remove')+'">×</button>' +
         '</div>';
     }).join('');
     wcRefresh();
@@ -865,7 +890,7 @@ function tzGetOffset(tz){
 function tzRenderList(){
     var listEl = document.getElementById('tz-list');
     if (!tzFiltered.length){
-        listEl.innerHTML = '<div class="tz-noresults">No results</div>';
+        listEl.innerHTML = '<div class="tz-noresults">'+getStr('clock/no-results','No results')+'</div>';
         return;
     }
     var ORDER = ['Americas','Europe','Asia','Africa','Australia','Pacific','UTC'];
@@ -925,7 +950,7 @@ function cdStart(){
     document.getElementById('cd-btn-pause').disabled = false;
     document.getElementById('cd-progress').style.background = 'var(--accent)';
     cdTimer = setInterval(cdTick, 200);
-    ao_module_setWindowTitle('Clock — Countdown');
+    ao_module_setWindowTitle(getStr('clock/wintitle-main','Clock') + '' + getStr('clock/wintitle-countdown','Countdown'));
 }
 
 function cdTick(){
@@ -962,7 +987,7 @@ function cdPause(){
     cdArrows(false);
     document.getElementById('cd-btn-play').disabled  = false;
     document.getElementById('cd-btn-pause').disabled = true;
-    ao_module_setWindowTitle('Clock — Countdown (Paused)');
+    ao_module_setWindowTitle(getStr('clock/wintitle-main','Clock') + '' + getStr('clock/wintitle-countdown-paused','Countdown (Paused)'));
 }
 
 function cdReset(){
@@ -975,11 +1000,11 @@ function cdReset(){
     document.getElementById('cd-progress').style.background = 'var(--accent)';
     ['cd-h','cd-m','cd-s'].forEach(function(id){ document.getElementById(id).classList.remove('alarm'); });
     if (cdAlarm){ cdAlarm.pause(); cdAlarm=null; }
-    ao_module_setWindowTitle('Clock — Countdown');
+    ao_module_setWindowTitle(getStr('clock/wintitle-main','Clock') + '' + getStr('clock/wintitle-countdown','Countdown'));
 }
 
 function cdFireAlarm(){
-    ao_module_setWindowTitle("Clock — ⏰ Time's up!");
+    ao_module_setWindowTitle(getStr('clock/wintitle-main','Clock') + ' — ' + getStr('clock/wintitle-times-up',"⏰ Time's up!"));
     try {
         cdAlarm = new Audio('sound/imuslab_theme.mp3');
         cdAlarm.volume = 0.3;
@@ -1005,16 +1030,16 @@ function swToggle(){
         document.getElementById('sw-ico-play').style.display  = '';
         document.getElementById('sw-ico-pause').style.display = 'none';
         document.getElementById('sw-btn-toggle').className    = 'ctrl-btn btn-play';
-        document.getElementById('sw-status').textContent      = 'Paused';
-        ao_module_setWindowTitle('Clock — Stopwatch (Paused)');
+        document.getElementById('sw-status').textContent      = getStr('clock/status-paused','Paused');
+        ao_module_setWindowTitle(getStr('clock/wintitle-main','Clock') + '' + getStr('clock/wintitle-stopwatch-paused','Stopwatch (Paused)'));
     } else {
         swStartTs=Date.now(); swRunning=true;
         swTimer=setInterval(swTick, 47);
         document.getElementById('sw-ico-play').style.display  = 'none';
         document.getElementById('sw-ico-pause').style.display = '';
         document.getElementById('sw-btn-toggle').className    = 'ctrl-btn btn-pause';
-        document.getElementById('sw-status').textContent      = 'Running';
-        ao_module_setWindowTitle('Clock — Stopwatch');
+        document.getElementById('sw-status').textContent      = getStr('clock/status-running','Running');
+        ao_module_setWindowTitle(getStr('clock/wintitle-main','Clock') + '' + getStr('clock/wintitle-stopwatch','Stopwatch'));
     }
 }
 
@@ -1023,9 +1048,9 @@ function swReset(){
     document.getElementById('sw-ico-play').style.display  = '';
     document.getElementById('sw-ico-pause').style.display = 'none';
     document.getElementById('sw-btn-toggle').className    = 'ctrl-btn btn-play';
-    document.getElementById('sw-status').textContent      = 'Ready';
+    document.getElementById('sw-status').textContent      = getStr('clock/status-ready','Ready');
     swDraw(0);
-    ao_module_setWindowTitle('Clock — Stopwatch');
+    ao_module_setWindowTitle(getStr('clock/wintitle-main','Clock') + '' + getStr('clock/wintitle-stopwatch','Stopwatch'));
 }
 
 function swTick(){ swDraw(swElapsed + (swRunning ? Date.now()-swStartTs : 0)); }
@@ -1051,10 +1076,22 @@ setInterval(function(){
 //  BOOT
 // ════════════════════════════════════════════════════════════════════════
 loadTheme();
-updateDigitalClock();
-initLocalClock();
-wcLoad();
 swDraw(0);
+
+if (typeof applocale !== 'undefined' && applocale) {
+    applocale.init("locale/clock.json", function(){
+        applocale.translate();
+        ao_module_setWindowTitle(getStr('clock/wintitle-main', 'Clock'));
+        updateDigitalClock();
+        initLocalClock();
+        wcLoad();
+    });
+} else {
+    ao_module_setWindowTitle('Clock');
+    updateDigitalClock();
+    initLocalClock();
+    wcLoad();
+}
 </script>
 </body>
 </html>

+ 245 - 0
src/web/Clock/locale/clock.json

@@ -0,0 +1,245 @@
+{
+    "author": "tobychui",
+    "version": "1.0",
+    "keys": {
+        "en-us": {
+            "name": "English (US)",
+            "strings": {
+                "clock/tab-clock": "Clock",
+                "clock/tab-world": "World",
+                "clock/tab-countdown": "Countdown",
+                "clock/tab-stopwatch": "Stopwatch",
+                "clock/other-clocks": "Other Clocks",
+                "clock/add-city": "Add City",
+                "clock/no-clocks-empty": "No clocks yet.<br>Tap <b>+ Add City</b> to get started.",
+                "clock/cd-hours": "Hours",
+                "clock/cd-minutes": "Minutes",
+                "clock/cd-seconds": "Seconds",
+                "clock/tz-sheet-title": "Choose a City",
+                "clock/status-ready": "Ready",
+                "clock/status-running": "Running",
+                "clock/status-paused": "Paused",
+                "clock/no-results": "No results",
+                "clock/wintitle-main": "Clock",
+                "clock/wintitle-world": "World Clock",
+                "clock/wintitle-countdown": "Countdown",
+                "clock/wintitle-stopwatch": "Stopwatch",
+                "clock/wintitle-countdown-paused": "Countdown (Paused)",
+                "clock/wintitle-times-up": "⏰ Time's up!",
+                "clock/wintitle-stopwatch-paused": "Stopwatch (Paused)",
+                "clock/btn-remove": "Remove"
+            },
+            "titles": {
+                "Start": "Start",
+                "Pause": "Pause",
+                "Reset": "Reset",
+                "Start / Pause": "Start / Pause",
+                "Toggle dark / light theme": "Toggle dark / light theme",
+                "Remove": "Remove"
+            },
+            "placeholder": {
+                "Search city or region…": "Search city or region…"
+            }
+        },
+        "zh-cn": {
+            "name": "简体中文",
+            "fontFamily": "\"Microsoft YaHei\", \"PingFang SC\", \"SimHei\", sans-serif",
+            "strings": {
+                "clock/tab-clock": "时钟",
+                "clock/tab-world": "世界",
+                "clock/tab-countdown": "倒计时",
+                "clock/tab-stopwatch": "秒表",
+                "clock/other-clocks": "其他时钟",
+                "clock/add-city": "添加城市",
+                "clock/no-clocks-empty": "还没有时钟。<br>点击 <b>+ 添加城市</b> 开始。",
+                "clock/cd-hours": "小时",
+                "clock/cd-minutes": "分钟",
+                "clock/cd-seconds": "秒",
+                "clock/tz-sheet-title": "选择城市",
+                "clock/status-ready": "就绪",
+                "clock/status-running": "运行中",
+                "clock/status-paused": "已暂停",
+                "clock/no-results": "无结果",
+                "clock/wintitle-main": "时钟",
+                "clock/wintitle-world": "世界时钟",
+                "clock/wintitle-countdown": "倒计时",
+                "clock/wintitle-stopwatch": "秒表",
+                "clock/wintitle-countdown-paused": "倒计时(已暂停)",
+                "clock/wintitle-times-up": "⏰ 时间到!",
+                "clock/wintitle-stopwatch-paused": "秒表(已暂停)",
+                "clock/btn-remove": "删除"
+            },
+            "titles": {
+                "Start": "开始",
+                "Pause": "暂停",
+                "Reset": "重置",
+                "Start / Pause": "开始 / 暂停",
+                "Toggle dark / light theme": "切换深色 / 浅色主题",
+                "Remove": "删除"
+            },
+            "placeholder": {
+                "Search city or region…": "搜索城市或地区…"
+            }
+        },
+        "zh-tw": {
+            "name": "繁體中文(台灣)",
+            "fontFamily": "\"Microsoft JhengHei\", \"Apple LiGothic Medium\", \"STHeiti\", sans-serif",
+            "strings": {
+                "clock/tab-clock": "時鐘",
+                "clock/tab-world": "世界",
+                "clock/tab-countdown": "倒數計時",
+                "clock/tab-stopwatch": "碼錶",
+                "clock/other-clocks": "其他時鐘",
+                "clock/add-city": "新增城市",
+                "clock/no-clocks-empty": "尚無時鐘。<br>點擊 <b>+ 新增城市</b> 開始。",
+                "clock/cd-hours": "小時",
+                "clock/cd-minutes": "分鐘",
+                "clock/cd-seconds": "秒",
+                "clock/tz-sheet-title": "選擇城市",
+                "clock/status-ready": "就緒",
+                "clock/status-running": "執行中",
+                "clock/status-paused": "已暫停",
+                "clock/no-results": "無結果",
+                "clock/wintitle-main": "時鐘",
+                "clock/wintitle-world": "世界時鐘",
+                "clock/wintitle-countdown": "倒數計時",
+                "clock/wintitle-stopwatch": "碼錶",
+                "clock/wintitle-countdown-paused": "倒數計時(已暫停)",
+                "clock/wintitle-times-up": "⏰ 時間到!",
+                "clock/wintitle-stopwatch-paused": "碼錶(已暫停)",
+                "clock/btn-remove": "移除"
+            },
+            "titles": {
+                "Start": "開始",
+                "Pause": "暫停",
+                "Reset": "重置",
+                "Start / Pause": "開始 / 暫停",
+                "Toggle dark / light theme": "切換深色 / 淺色主題",
+                "Remove": "移除"
+            },
+            "placeholder": {
+                "Search city or region…": "搜尋城市或地區…"
+            }
+        },
+        "zh-hk": {
+            "name": "繁體中文(香港)",
+            "fontFamily": "\"Microsoft JhengHei\", \"Apple LiGothic Medium\", \"STHeiti\", sans-serif",
+            "strings": {
+                "clock/tab-clock": "時鐘",
+                "clock/tab-world": "世界",
+                "clock/tab-countdown": "倒數計時",
+                "clock/tab-stopwatch": "秒錶",
+                "clock/other-clocks": "其他時鐘",
+                "clock/add-city": "新增城市",
+                "clock/no-clocks-empty": "暫時冇時鐘。<br>點擊 <b>+ 新增城市</b> 開始。",
+                "clock/cd-hours": "小時",
+                "clock/cd-minutes": "分鐘",
+                "clock/cd-seconds": "秒",
+                "clock/tz-sheet-title": "選擇城市",
+                "clock/status-ready": "就緒",
+                "clock/status-running": "運行中",
+                "clock/status-paused": "已暫停",
+                "clock/no-results": "無結果",
+                "clock/wintitle-main": "時鐘",
+                "clock/wintitle-world": "世界時鐘",
+                "clock/wintitle-countdown": "倒數計時",
+                "clock/wintitle-stopwatch": "秒錶",
+                "clock/wintitle-countdown-paused": "倒數計時(已暫停)",
+                "clock/wintitle-times-up": "⏰ 時間到!",
+                "clock/wintitle-stopwatch-paused": "秒錶(已暫停)",
+                "clock/btn-remove": "移除"
+            },
+            "titles": {
+                "Start": "開始",
+                "Pause": "暫停",
+                "Reset": "重置",
+                "Start / Pause": "開始 / 暫停",
+                "Toggle dark / light theme": "切換深色 / 淺色主題",
+                "Remove": "移除"
+            },
+            "placeholder": {
+                "Search city or region…": "搜尋城市或地區…"
+            }
+        },
+        "ja-jp": {
+            "name": "日本語",
+            "fontFamily": "\"Hiragino Kaku Gothic Pro\", \"Meiryo\", \"MS Gothic\", sans-serif",
+            "strings": {
+                "clock/tab-clock": "時計",
+                "clock/tab-world": "世界",
+                "clock/tab-countdown": "カウントダウン",
+                "clock/tab-stopwatch": "ストップウォッチ",
+                "clock/other-clocks": "その他の時計",
+                "clock/add-city": "都市を追加",
+                "clock/no-clocks-empty": "時計がありません。<br><b>+ 都市を追加</b> をタップして開始してください。",
+                "clock/cd-hours": "時間",
+                "clock/cd-minutes": "分",
+                "clock/cd-seconds": "秒",
+                "clock/tz-sheet-title": "都市を選択",
+                "clock/status-ready": "準備完了",
+                "clock/status-running": "実行中",
+                "clock/status-paused": "一時停止中",
+                "clock/no-results": "結果なし",
+                "clock/wintitle-main": "時計",
+                "clock/wintitle-world": "世界時計",
+                "clock/wintitle-countdown": "カウントダウン",
+                "clock/wintitle-stopwatch": "ストップウォッチ",
+                "clock/wintitle-countdown-paused": "カウントダウン(一時停止中)",
+                "clock/wintitle-times-up": "⏰ 時間切れ!",
+                "clock/wintitle-stopwatch-paused": "ストップウォッチ(一時停止中)",
+                "clock/btn-remove": "削除"
+            },
+            "titles": {
+                "Start": "開始",
+                "Pause": "一時停止",
+                "Reset": "リセット",
+                "Start / Pause": "開始 / 一時停止",
+                "Toggle dark / light theme": "ダーク / ライトテーマ切替",
+                "Remove": "削除"
+            },
+            "placeholder": {
+                "Search city or region…": "都市または地域を検索…"
+            }
+        },
+        "ko-kr": {
+            "name": "한국어",
+            "fontFamily": "\"Malgun Gothic\", \"Apple SD Gothic Neo\", sans-serif",
+            "strings": {
+                "clock/tab-clock": "시계",
+                "clock/tab-world": "세계",
+                "clock/tab-countdown": "카운트다운",
+                "clock/tab-stopwatch": "스톱워치",
+                "clock/other-clocks": "다른 시계",
+                "clock/add-city": "도시 추가",
+                "clock/no-clocks-empty": "시계가 없습니다.<br><b>+ 도시 추가</b>를 탭하여 시작하세요.",
+                "clock/cd-hours": "시간",
+                "clock/cd-minutes": "분",
+                "clock/cd-seconds": "초",
+                "clock/tz-sheet-title": "도시 선택",
+                "clock/status-ready": "준비됨",
+                "clock/status-running": "실행 중",
+                "clock/status-paused": "일시 정지됨",
+                "clock/no-results": "결과 없음",
+                "clock/wintitle-main": "시계",
+                "clock/wintitle-world": "세계 시계",
+                "clock/wintitle-countdown": "카운트다운",
+                "clock/wintitle-stopwatch": "스톱워치",
+                "clock/wintitle-countdown-paused": "카운트다운 (일시 정지됨)",
+                "clock/wintitle-times-up": "⏰ 시간 초과!",
+                "clock/wintitle-stopwatch-paused": "스톱워치 (일시 정지됨)",
+                "clock/btn-remove": "제거"
+            },
+            "titles": {
+                "Start": "시작",
+                "Pause": "일시 정지",
+                "Reset": "초기화",
+                "Start / Pause": "시작 / 일시 정지",
+                "Toggle dark / light theme": "다크 / 라이트 테마 전환",
+                "Remove": "제거"
+            },
+            "placeholder": {
+                "Search city or region…": "도시 또는 지역 검색…"
+            }
+        }
+    }
+}