마지막 업데이트 2026-08-10
게스트(아동) 접속 화면에서 브라우저 자동 번역이 개입해 안내 Alert 문구가 의도와 다르게 바뀌던 문제를 차단한다. 근본 원인은 root layout이 한국어 콘텐츠를 <html lang="en">으로 선언하고 있던 것이고, 이번 PR은 ① lang 값을 ko로 정정하고 ② client-guest 서브트리에 번역 제외 표시를 추가하는 2단 방어다.
리뷰 시 가장 먼저 볼 지점은 apps/web/app/layout.tsx의 lang 변경이 앱 전역(admin 포함)에 적용된다는 점, 그리고 google: "notranslate" 메타가 Chrome/Google 계열 전용 규약이라 iPad Safari 커버를 translate="no"에 의존한다는 점이다.
PPI 게스트 화면의 모든 텍스트는 한국어인데, root layout은 Next.js 기본 스캐폴드 값인 lang="en"을 그대로 유지하고 있었다. 브라우저는 이 선언을 보고 "사용자 언어와 다른 페이지"로 판정해 번역 배너를 띄우거나, 자동 번역 설정이 켜진 기기에서는 조용히 번역해 버린다. 그 결과 기획된 안내 문구(FormAlert 등)가 재번역된 문장으로 바뀌어 아동에게 잘못된 안내가 전달될 수 있었다.
lang 변경은 전역이지만 렌더링에는 영향이 없다. 브라우저 언어 판정·스크린리더 발음·하이픈네이션 등 접근성 메타데이터만 정상화된다. 번역 제외 표시는 /client-guest 서브트리로 한정된다.lang 정정만으로도 번역 유도는 대부분 사라지지만, 사용자가 수동으로 번역을 실행하거나 브라우저가 콘텐츠 기반으로 판정하는 경우가 남는다. 명시적 translate="no"가 그 잔여 경로를 막는다.client-guest/layout.tsx는 이미 viewport(핀치줌 차단)를 세그먼트 단위로 선언하고 있었다. 이번 metadata 추가는 같은 자리에 같은 방식으로 얹은 것이라 새 추상화가 없다.div에 display: contents를 줘서 flex/grid 레이아웃 계산에 새 박스가 끼어들지 않는다.페이지 언어 선언 확인
apps/web/app/layout.tsx
<html lang>이 사용자 브라우저 언어와 다르면 번역 후보로 판정. en → ko로 정정해 이 단계에서 탈락시킨다.
문서 단위 번역 제외 메타
apps/web/app/client-guest/layout.tsx — metadata.other
<meta name="google" content="notranslate">가 head에 렌더. Chrome/Google 번역이 문서 전체를 대상에서 제외.
엘리먼트 단위 번역 제외 속성
client-guest 서브트리 래퍼 — translate="no"
HTML 표준 속성이라 Google 규약을 따르지 않는 브라우저(Safari 등)에도 신호가 전달된다. 게스트 화면 텍스트 전체가 대상.
이 한 줄이 번역 유발의 시작점이다. 나머지 변경은 이 위에 얹는 보강이다.
Next.js Metadata API에 번역 제어 전용 필드가 없어 other로 임의 메타를 주입한다. client-guest/layout.tsx는 "use client"가 없는 서버 컴포넌트라 metadata export가 유효하고, 하위 page.tsx 2개는 모두 client component라 metadata override 충돌도 없다.
display: contents가 핵심이다. 이게 없으면 게스트 화면의 flex/grid 레이아웃 사이에 익명 블록이 끼어들어 기존 스타일이 깨질 수 있다.
| 레이어 | 파일 | 핵심 변경 |
|---|---|---|
| 앱 전역 레이아웃 | apps/web/app/layout.tsx |
<html lang="en"> → <html lang="ko">. 번역 유발 근본 원인 제거 (+1/−1) |
| 게스트 세그먼트 레이아웃 | apps/web/app/client-guest/layout.tsx |
metadata.other.google = "notranslate" 추가 + 하위 트리를 translate="no"/notranslate 래퍼로 감쌈 (+14/−2) |
iPad Safari 실기기 검증이 필수. <meta name="google" content="notranslate">는 Google이 정의한 규약이라 Safari 번역 기능이 이를 존중한다는 보장이 없다. 아동측 주 사용 기기가 iPad인 만큼, Safari에서의 실효는 lang="ko" + translate="no" 조합에 달려 있다. 자동번역 ON 상태로 /client-guest에 접속해 안내 Alert 원문이 유지되는지 직접 확인해야 한다.
lang 변경은 게스트 화면뿐 아니라 admin(/main/*) 전체에 적용된다. 렌더링 로직에는 관여하지 않지만, 브라우저 기본 폰트 폴백·하이픈네이션·IME 힌트·스크린리더 발음이 영향을 받는다. 모든 화면이 한국어이므로 의미상 정확한 값이라 되돌릴 이유는 없으나, 배포 후 admin 화면도 한 번 훑어보는 편이 안전하다.
방어가 게스트 세그먼트에만 걸려 있다. 진행자 모니터(/main/meet, monitor-dashboard)는 번역 제외 표시가 없어 lang="ko" 정정에만 의존한다. 진행자는 성인이고 번역을 수동으로 끌 수 있으므로 현재 범위 판단은 합리적이지만, 동일 증상이 모니터에서 보고되면 같은 래퍼를 재사용할 수 있도록 컴포넌트화 여지를 남겨둘 만하다.
롤백이 단순하다. 두 변경 모두 부수효과 없는 선언적 속성이고, 상태·네트워크·미디어 경로를 건드리지 않는다. display: contents 덕분에 레이아웃 영향도 없어 문제 시 커밋 revert만으로 원복된다. tsc --noEmit 통과 확인됨.
translate="no"는 번역 실행을 막는 신호일 뿐 강제 차단이 아니다. 사용자가 명시적으로 "이 페이지 번역"을 실행하는 경로까지 100% 막지는 못하는 브라우저가 있을 수 있다. 아동이 직접 그 조작을 할 가능성은 낮지만, 보호자 기기 설정에 따라 재발 신고가 들어올 여지는 남는다.
| 항목 | 확인 경로 | 상태 |
|---|---|---|
| 타입 체크 | tsc --noEmit | 통과 |
| iPad Safari 자동번역 ON — 안내 Alert 원문 유지 | /client-guest | 미확인 |
| Android Chrome 자동번역 ON — 동일 확인 | /client-guest | 미확인 |
| 수업 진행 중 텍스트 번역 안 됨 | /client-guest/session | 미확인 |
| 번역 배너 자체가 뜨지 않음 (lang 반영 확인) | 전 화면 | 미확인 |
| lang 전역 변경 후 admin 화면 이상 없음 | /main/meet 외 | 미확인 |
/client-guest 진입 경로의 전체 흐름.PR #976 · 브랜치 PPI-1186 → develop · 커밋 c8831da7