Skip to content
Closed
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
15 changes: 14 additions & 1 deletion i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const messages = {
"nav.forks": "Fork",
"nav.references": "참고문헌",
"nav.work": "작업",
"nav.opensInNewTab": "(새 창에서 열림)",
"nav.skipToContent": "본문으로 건너뛰기",
"hero.title": "맥락지혜 연구실",
"hero.labName": "Contextual Wisdom Lab",
Expand Down Expand Up @@ -164,6 +165,7 @@ const messages = {
"nav.forks": "Forks",
"nav.references": "References",
"nav.work": "Work",
"nav.opensInNewTab": "(Opens in a new tab)",
"nav.skipToContent": "Skip to main content",
"hero.title": "Contextual Wisdom Lab",
"hero.labName": "Research Lab",
Expand Down Expand Up @@ -312,6 +314,7 @@ function preferredLanguage() {

// ⚡ Bolt: Cache DOM queries and current state to prevent redundant lookups and layout thrashing
let i18nNodes = null;
let i18nTitleNodes = null;
let langButtons = null;
let metaDesc = null;
let ogDesc = null;
Expand Down Expand Up @@ -361,7 +364,7 @@ function setLanguage(lang) {
}

// ⚡ Bolt: 기본 언어로 초기 로드 시 불필요한 DOM 텍스트 읽기 및 탐색 생략 (성능 개선)
const isInitialDefault = lang === "ko" && !i18nNodes;
const isInitialDefault = lang === "ko" && !i18nNodes && !i18nTitleNodes;

if (!isInitialDefault) {
if (!i18nNodes) {
Expand All @@ -375,6 +378,16 @@ function setLanguage(lang) {
node.textContent = newText;
}
});

if (!i18nTitleNodes) {
i18nTitleNodes = document.querySelectorAll("[data-i18n-title]");
}
i18nTitleNodes.forEach((node) => {
const newText = dict[node.dataset.i18nTitle];
if (newText && node.getAttribute("title") !== newText) {
node.setAttribute("title", newText);
}
});
}

langButtons.forEach((button) => {
Expand Down
32 changes: 16 additions & 16 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<a href="#projects" data-i18n="nav.projects">프로젝트</a>
<a href="#forks" data-i18n="nav.forks">Fork</a>
<a href="#work" data-i18n="nav.work">작업</a>
<a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab">GitHub</a>
<a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab" data-i18n-title="nav.opensInNewTab" title="(새 창에서 열림)">GitHub</a>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Expose the new-tab notice without relying on title

For keyboard and touch users, these links still provide no dependable advance warning because browsers generally expose title only as a pointer-hover tooltip and do not display it on keyboard focus; screen-reader announcement of a title on an already named link is also inconsistent. Since every changed link uses only this attribute, provide the localized notice as visible or visually hidden link text, or associate it using aria-describedby, rather than relying solely on title.

Useful? React with 👍 / 👎.

</nav>
<div class="language-switch" role="group" aria-label="Language">
<button type="button" data-lang="ko" lang="ko" aria-pressed="true" aria-label="한국어">KO</button>
Expand All @@ -59,7 +59,7 @@ <h1 data-i18n="hero.title">맥락지혜 연구실</h1>
구슬이 서 말이어도 꿰어야 보배이듯, 문서, 메일, 로그, 회의록을 맥락 안에서 엮어 사람이 무엇을 결정하고 무엇을 실행할지 보이게 하는 AI 의사결정 지원 시스템을 연구하고 만듭니다.
</p>
<div class="hero-actions" role="group" aria-label="Homepage actions">
<a target="_blank" rel="noopener noreferrer" class="button primary" href="https://github.com/ContextualWisdomLab" data-i18n="hero.primaryCta">GitHub 보기</a>
<a target="_blank" rel="noopener noreferrer" class="button primary" href="https://github.com/ContextualWisdomLab" data-i18n="hero.primaryCta" data-i18n-title="nav.opensInNewTab" title="(새 창에서 열림)">GitHub 보기</a>
<a class="button secondary" href="#dikw" data-i18n="hero.secondaryCta">DIKW 보기</a>
</div>
</div>
Expand Down Expand Up @@ -254,19 +254,19 @@ <h2 data-i18n="references.title">참고문헌</h2>
<ol class="reference-list">
<li>
<span data-i18n="references.ackoff">Ackoff, R. L. (1989). From data to wisdom. Journal of Applied Systems Analysis, 16(1), 3-9.</span>
<a target="_blank" rel="noopener noreferrer" href="https://faculty.ung.edu/kmelton/documents/datawisdom.pdf">https://faculty.ung.edu/kmelton/documents/datawisdom.pdf</a>
<a target="_blank" rel="noopener noreferrer" href="https://faculty.ung.edu/kmelton/documents/datawisdom.pdf" data-i18n-title="nav.opensInNewTab" title="(새 창에서 열림)">https://faculty.ung.edu/kmelton/documents/datawisdom.pdf</a>
</li>
<li>
<span data-i18n="references.baskarada">Baskarada, S., &amp; Koronios, A. (2013). Data, information, knowledge, wisdom (DIKW): A semiotic theoretical and empirical exploration of the hierarchy and its quality dimension. Australasian Journal of Information Systems, 18(1).</span>
<a target="_blank" rel="noopener noreferrer" href="https://doi.org/10.3127/ajis.v18i1.748">https://doi.org/10.3127/ajis.v18i1.748</a>
<a target="_blank" rel="noopener noreferrer" href="https://doi.org/10.3127/ajis.v18i1.748" data-i18n-title="nav.opensInNewTab" title="(새 창에서 열림)">https://doi.org/10.3127/ajis.v18i1.748</a>
</li>
<li>
<span data-i18n="references.fricke">Frické, M. (2009). The knowledge pyramid: A critique of the DIKW hierarchy. Journal of Information Science, 35(2), 131-142.</span>
<a target="_blank" rel="noopener noreferrer" href="https://doi.org/10.1177/0165551508094050">https://doi.org/10.1177/0165551508094050</a>
<a target="_blank" rel="noopener noreferrer" href="https://doi.org/10.1177/0165551508094050" data-i18n-title="nav.opensInNewTab" title="(새 창에서 열림)">https://doi.org/10.1177/0165551508094050</a>
</li>
<li>
<span data-i18n="references.brienza">Brienza, J. P., Kung, F. Y. H., Santos, H. C., Bobocel, D. R., &amp; Grossmann, I. (2018). Wisdom, bias, and balance: Toward a process-sensitive measurement of wisdom-related cognition. Journal of Personality and Social Psychology, 115(6), 1093-1126.</span>
<a target="_blank" rel="noopener noreferrer" href="https://doi.org/10.1037/pspp0000171">https://doi.org/10.1037/pspp0000171</a>
<a target="_blank" rel="noopener noreferrer" href="https://doi.org/10.1037/pspp0000171" data-i18n-title="nav.opensInNewTab" title="(새 창에서 열림)">https://doi.org/10.1037/pspp0000171</a>
</li>
</ol>
</section>
Expand Down Expand Up @@ -327,39 +327,39 @@ <h2 data-i18n="projects.title">공개 프로젝트</h2>
</div>
<div class="naruon-grid project-grid">
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/naruon" data-i18n="projects.naruonTitle">Naruon</a></h3>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/naruon" data-i18n="projects.naruonTitle" data-i18n-title="nav.opensInNewTab" title="(새 창에서 열림)">Naruon</a></h3>
<p data-i18n="projects.naruonBody">메일, 첨부, 일정, 작업을 맥락으로 묶어 판단과 실행으로 연결하는 AI 이메일 워크스페이스입니다.</p>
</article>
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/pg-erd-cloud" data-i18n="projects.pgErdTitle">pg-erd-cloud</a></h3>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/pg-erd-cloud" data-i18n="projects.pgErdTitle" data-i18n-title="nav.opensInNewTab" title="(새 창에서 열림)">pg-erd-cloud</a></h3>
<p data-i18n="projects.pgErdBody">PostgreSQL 스키마를 리버스 엔지니어링하고 ERD와 DDL 공유 흐름으로 관리하는 클라우드 MVP입니다.</p>
</article>
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/bandscope" data-i18n="projects.bandscopeTitle">BandScope</a></h3>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/bandscope" data-i18n="projects.bandscopeTitle" data-i18n-title="nav.opensInNewTab" title="(새 창에서 열림)">BandScope</a></h3>
<p data-i18n="projects.bandscopeBody">곡을 섹션, 역할, 템포, 연습 우선순위로 분석하는 로컬 우선 리허설 앱입니다.</p>
</article>
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/codec-carver" data-i18n="projects.codecCarverTitle">codec-carver</a></h3>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/codec-carver" data-i18n="projects.codecCarverTitle" data-i18n-title="nav.opensInNewTab" title="(새 창에서 열림)">codec-carver</a></h3>
<p data-i18n="projects.codecCarverBody">긴 녹음을 메타데이터를 보존한 FLAC/Opus 조각으로 변환하는 Python CLI입니다.</p>
</article>
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/newsdom-api" data-i18n="projects.newsdomTitle">newsdom-api</a></h3>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/newsdom-api" data-i18n="projects.newsdomTitle" data-i18n-title="nav.opensInNewTab" title="(새 창에서 열림)">newsdom-api</a></h3>
<p data-i18n="projects.newsdomBody">스캔된 일본어 신문 PDF를 기사, 제목, 본문, 이미지 구조의 DOM형 JSON으로 파싱하는 API입니다.</p>
</article>
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/scopeweave" data-i18n="projects.scopeweaveTitle">scopeweave</a></h3>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/scopeweave" data-i18n="projects.scopeweaveTitle" data-i18n-title="nav.opensInNewTab" title="(새 창에서 열림)">scopeweave</a></h3>
<p data-i18n="projects.scopeweaveBody">트리 편집, 진행률 계산, CSV/JSON, 주간 Gantt를 지원하는 정적 HTML/CSS/JS WBS 플래너입니다.</p>
</article>
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/VibeSec" data-i18n="projects.vibesecTitle">VibeSec</a></h3>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/VibeSec" data-i18n="projects.vibesecTitle" data-i18n-title="nav.opensInNewTab" title="(새 창에서 열림)">VibeSec</a></h3>
<p data-i18n="projects.vibesecBody">바이브코딩 앱을 위한 보안 가드레일입니다. AI 개발 도구 규칙, 정적 점검, 리뷰와 수정 프롬프트를 다룹니다.</p>
</article>
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/fast-mlsirm" data-i18n="projects.fastMlsirmTitle">fast-mlsirm</a></h3>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/fast-mlsirm" data-i18n="projects.fastMlsirmTitle" data-i18n-title="nav.opensInNewTab" title="(새 창에서 열림)">fast-mlsirm</a></h3>
<p data-i18n="projects.fastMlsirmBody">MLSIRM/MLS2PLM 모형의 시뮬레이션, 적합, 복원 진단을 빠르게 수행하는 Python/Rust 패키지입니다.</p>
</article>
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/waf-ids-ai-soc" data-i18n="projects.wafIdsTitle">waf-ids-ai-soc</a></h3>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/waf-ids-ai-soc" data-i18n="projects.wafIdsTitle" data-i18n-title="nav.opensInNewTab" title="(새 창에서 열림)">waf-ids-ai-soc</a></h3>
<p data-i18n="projects.wafIdsBody">DNSBL 게시 기능을 갖춘 Rust 우선 WAF/IDS/AI SOC 게이트웨이입니다.</p>
</article>
</div>
Expand Down Expand Up @@ -431,7 +431,7 @@ <h2 data-i18n="work.title">연구에서 제품으로</h2>
>
<p>
<span data-i18n="footer.founded">Founded by</span>
<a target="_blank" rel="noopener noreferrer" href="https://github.com/seonghobae">Seongho Bae</a>.
<a target="_blank" rel="noopener noreferrer" href="https://github.com/seonghobae" data-i18n-title="nav.opensInNewTab" title="(새 창에서 열림)">Seongho Bae</a>.
<span data-i18n="footer.line">Context into judgment. Judgment into action.</span>
</p>
</footer>
Expand Down
10 changes: 10 additions & 0 deletions tests/test_i18n_title.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""Test i18n title functionality presence."""

def test_i18n_title_query_selector_present() -> None:
"""Test that data-i18n-title is queried correctly in i18n.js."""
with open("i18n.js", "r", encoding="utf-8") as f:
content = f.read()

assert "querySelectorAll(\"[data-i18n-title]\")" in content
assert "getAttribute(\"title\")" in content
assert "setAttribute(\"title\"" in content
Loading