앱 언어를 일본어로 바꿨는데 상단 티커는 일본어, 공지 목록은 이전 언어로 남는 일이 있었다. 두 화면 모두 다국어 데이터를 사용했지만 티커는 언어 변경 때 다시 요청했고 공지는 앱 시작 캐시를 계속 사용했다. 번역 UI 문제가 아니라 데이터 갱신 정책의 차이였다.
같은 언어 설정을 보더라도 데이터가 만들어진 시점이 달랐다.
언어가 누락된 캐시 키
공지 캐시는 항목 ID만 키로 사용해 어느 언어로 받은 내용인지 알 수 없었다. 언어와 콘텐츠 버전을 키에 포함했다.
string NoticeCacheKey(string language, long version)
=> $"notice:{language}:{version}";
서버가 번역을 제공하지 않는 언어에서는 기준 언어로 대체됐다는 상태도 같이 저장했다.
데이터 이벤트로서의 언어 변경
텍스트 컴포넌트만 다시 그리지 않고 언어에 의존하는 데이터 공급자에게 갱신을 요청했다.
언어 변경
-> 정적 UI 문구 갱신
-> 공지 캐시 전환 또는 재조회
-> 티커 스트림 재구독
-> 현재 상세 화면 재바인딩
진행 중인 이전 언어 요청은 취소하거나 응답 적용 시 언어를 비교해 버렸다.
실시간 티커는 연결을 다시 맺는 동안 동일 항목이 중복으로 들어올 수 있었다. 항목 ID와 언어 버전을 기준으로 교체하고, 이전 구독이 완전히 끝났는지 확인했다. 정적 조회와 스트림은 갱신 방식이 달라도 최종 화면 상태 규칙은 같아야 했다.
언어 전환 중 혼합 상태 정책
새 공지를 받는 동안 이전 언어 내용을 유지하면 화면이 빠르지만 언어가 섞인다. 이 화면에서는 짧은 로딩 상태를 보여주고 완성된 새 언어 데이터로 한 번에 교체했다. 네트워크 실패 시에는 기준 언어로 대체됐음을 작게 알렸다.
공지 상세에서 목록으로 돌아올 때도 현재 언어의 캐시를 다시 사용하도록 확인했다.
언어를 연속으로 두 번 바꾸기, 오프라인에서 바꾸기, 상세 화면을 연 상태에서 바꾸기를 재현 시나리오로 만들었다. 단순한 한 번의 변경보다 요청 완료 순서가 뒤바뀌는 조건에서 문제가 잘 드러났다.
다중 시스템의 화면 언어 계약
처음에는 전역 언어 값 하나를 바꾸면 모든 것이 따라올 거라 생각했다. 실제로는 정적 문자열, 캐시 API, 실시간 스트림이 각자 언어를 소비했다. 하나라도 갱신 규칙이 다르면 혼합 화면이 됐다.
이 경험 뒤 언어에 영향을 받는 자산과 데이터 경로를 목록으로 관리한다. 언어 변경은 UI 이벤트이면서 캐시 무효화와 네트워크 재구독을 포함하는 상태 전환이었다.
공식 문서 기반의 추가 정리
이 문제를 고친 뒤 관련 공식 자료를 찾아 읽으면서, 당시 코드에서 우연히 맞았던 부분과 규칙으로 남겨야 할 부분을 나눠 봤다.
W3C 일본어 조판 요구사항을 보면 번역은 문자열 치환보다 행 구성과 줄바꿈 규칙까지 포함한 레이아웃 입력이다. 같은 의미라도 문자 폭과 금칙 처리 때문에 버튼·티커·팝업의 높이가 달라진다.
WCAG의 reflow 기준처럼 확대와 좁은 폭에서도 조작 순서와 내용이 유지되는지 보면, 특정 번역 하나에 맞춘 고정 높이를 줄일 수 있다.
다음에 공지·티커 언어 불일치 같은 문제를 보면 아래 순서부터 확인하려고 한다.
- 최장 번역과 줄바꿈 금칙
- 빈 값과 key 누락의 fallback
- 팝업·티커·버튼의 높이 변화
- 언어 변경 중 열린 화면 갱신
문구 key 누락, 빈 문자열, 예상보다 긴 번역을 서로 다른 상태로 다루고 fallback 언어가 레이아웃을 망가뜨리지 않는지 확인해야 한다.
공식 참고 자료
- W3C 일본어 조판 요구사항 — 일본어 줄바꿈·문자 배치·행 구성
- W3C WCAG 2.1 — 확대·reflow·orientation·입력 접근성