Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2024-06-20 - Unnecessary initial DOM updates for default language
**Learning:** The simple static i18n implementation runs `node.textContent = dict[node.dataset.i18n]` for every translatable node on the initial script load, even when the HTML is already written in the target language (Korean). This creates unnecessary layout/paint operations and blocking time on the main thread for elements that don't need text changes.
**Action:** Always check if the current value matches the desired value before updating the DOM (`node.textContent !== newText`), and add early exits when setting state to the same value to avoid redundant DOM traversal and writes.

## 2024-06-26 - 초기 언어 로드를 위한 빠른 경로(Fast path) 적용
**Learning:** 초기 페이지 로드 시 요청된 기본 언어가 이미 렌더링된 HTML과 완벽하게 일치함에도 불구하고, 정적 i18n 구현이 무거운 DOM 쿼리(`querySelectorAll`)와 트리 순회를 실행하고 있었습니다.
**Action:** 초기 상태가 이미 요청된 상태와 일치하는지 항상 확인해야 합니다. `currentLang`이 null이고 `document.documentElement.lang`이 요청된 언어와 일치할 때 DOM 쿼리를 우회하도록 `setLanguage`에 빠른 종료(early exit)를 추가했으며, 실제 언어 전환이 일어날 때만 노드를 쿼리하도록 지연(lazy) 처리했습니다.
36 changes: 36 additions & 0 deletions i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,42 @@ let currentLang = null;
function setLanguage(lang) {
if (currentLang === lang) return; // Skip if already in the requested language

// ⚡ Bolt: 대상 언어가 HTML 문서 언어와 일치하는 초기 로드 시 빠른 경로 적용
// HTML에 이미 렌더링된 언어인 경우 무거운 DOM 쿼리(querySelectorAll)를 완전히 생략합니다
if (currentLang === null && document.documentElement.lang === lang) {
currentLang = lang;

Comment thread
seonghobae marked this conversation as resolved.
// 이후 언어 전환을 위해 노드 초기화는 필요합니다
if (!i18nNodes) {
// requestIdleCallback을 사용하여 메인 스레드가 유휴 상태일 때까지 무거운 DOM 쿼리를 지연시킵니다
if (typeof window !== 'undefined' && 'requestIdleCallback' in window) {
window.requestIdleCallback(() => {
i18nNodes = document.querySelectorAll("[data-i18n]");
langButtons = document.querySelectorAll("[data-lang]");
metaDesc = document.querySelector('meta[name="description"]');
ogDesc = document.querySelector('meta[property="og:description"]');
footerLogo = document.querySelector("#footer-logo");
});
} else if (typeof window !== 'undefined') {
setTimeout(() => {
i18nNodes = document.querySelectorAll("[data-i18n]");
langButtons = document.querySelectorAll("[data-lang]");
metaDesc = document.querySelector('meta[name="description"]');
ogDesc = document.querySelector('meta[property="og:description"]');
footerLogo = document.querySelector("#footer-logo");
}, 1);
} else {
// Fallback for tests or non-browser environments
i18nNodes = document.querySelectorAll("[data-i18n]");
langButtons = document.querySelectorAll("[data-lang]");
metaDesc = document.querySelector('meta[name="description"]');
ogDesc = document.querySelector('meta[property="og:description"]');
footerLogo = document.querySelector("#footer-logo");
}
}
return; // 버튼은 HTML에서 이미 올바르게 설정되어 있습니다
}

const dict = messages[lang] || messages.ko;

if (!i18nNodes) {
Expand Down
Loading