Skip to content

refactor(core,afternote,receiver,onboarding): 화면 노출 문자열 33건을 리소스로 옮긴다 (#1469) - #1472

Merged
1hyok merged 6 commits into
developfrom
refactor/1469-content-description-resources
Aug 29, 2026
Merged

1hyok merged 6 commits into
developfrom
refactor/1469-content-description-resources

Conversation

@1hyok

@1hyok 1hyok commented Aug 29, 2026 •

Copy link
Copy Markdown
Collaborator

화면에 노출되는 문자열이 리소스를 거치지 않고 코드에 박혀 있던 33건을 옮긴다. TalkBack 이 낭독하는 contentDescription 과 화면에 그려지는 Text 는 성격이 같아 함께 다뤘다.

Closes #1469

절반 가까이는 신설이 아니라 「이미 있는 리소스의 미사용」이었다

이 PR 에서 가장 중요한 부분이다. 리소스가 멀쩡히 있는데 같은 문구를 코드에 다시 적어 둔 곳이 계속 나왔다.

문구 이미 있던 키 하드코딩돼 있던 곳
영상 재생 content_description_video_play 추억 노트 상세 · 수신 추억 노트 상세
장례식에 남길 영상 afternote_editor_funeral_video_label 추억 노트 상세 · 수신 상세(LABEL_VIDEO_SECTION 상수)
추억 플레이리스트 afternote_editor_playlist_screen_title 추억 노트 상세 · MemorialPlaylist 기본값 · 수신 상세
영상을 재생할 수 있는 앱이 없습니다. receiver_memorial_video_no_app 수신 상세 Toast

약관 상세는 더 노골적이었다 — 본문 6개는 onboarding_terms_detail_section_N 리소스인데 제목 6개만 코드에 남아 있었다.

커밋 2개로 나눠 뒀다

  • 6ade9b024 — contentDescription 6건
  • 9cc6f8a6b — 화면 노출 텍스트 27건 (core:ui 2 · afternote 8 · receiver 11 · onboarding 6)

리뷰어에게 — 판단이 들어간 5곳

기계적 치환이 아닌 곳만 추립니다.

"Play" 는 리소스로 옮기지 않고 없앴다. 수신 상세에서 영상이 없을 때만 그리는 else 분기 플레이스홀더다. clickable 이 없어 재생 액션이 실제로 없는데 "Play" 로 읽히면 스크린리더 사용자에게 없는 어포던스를 알린다. 맥락은 바로 위 ReceiverSectionHeader() 가 이미 읽어 준다.

nav_afternote 는 참조 0건인 죽은 키였다. 값이 같은 키를 새로 만들면 #1069 가 지적한 중복이 다시 생기므로, afternote_home_title 로 리네임해 실제 쓰이게 했다. 키 수는 늘지 않는다.

MemorialPlaylist(label = "추억 플레이리스트") 는 인자 자체를 지웠다. 기본값이 이미 그 리소스라 같은 값을 다시 넘기고 있었다.

요일 라벨은 string-array 로 뒀다. 레포에 선례가 없지만 순서·개수가 고정된 집합이고, 개별 키 7개로 두면 호출부에서 listOf 로 다시 조립해야 해 순서가 어긋날 여지를 남긴다.

수신자 홈 건수 문장의 끝 공백에 주의. rememberCountLine 이 숫자 앞부분과 뒷문장을 서로 다른 스타일로 그려서 리소스도 그 경계대로 둘로 나눴다. "%1$s개 " 의 끝 공백이 렌더 결과에 유효하므로 XML 에서 따옴표로 감쌌고, 결합 결과를 단언하는 기존 테스트로 확인했다(ReceiverHomeCountFallbackTest — "22개 마음의 기록이 있습니다." 3건 통과).

제외한 것 — 노출 문자열이 아니다

대상 제외 근거
SaveAfternotePayloadBuilder.MEMORIAL_DEFAULT_TITLE 서버로 보내는 serviceName 값. 옮기면 로케일에 따라 전송값이 바뀐다
AfternoteService.displayKey 21건 enum 이 stringResId 를 따로 갖고 있다. 표시는 그쪽이 하고 이건 카탈로그 매칭용 식별자 — Text 로 그려지는 곳 0건
BaseResponse.fallbackMessage 등 KDoc 이 «클라이언트 진단 문구» 로 규정. 사용자 노출은 serverMessage 가 맡는다
@Preview 인자·프리뷰 데이터 TextFieldShort.kt:403 · MemorialDetailScreen 의 "서영"
label = "IndicatorOffset" 류 animateFloatAsState 의 디버그 라벨

네이밍 — 신규만 afternote_, 기존 리네임은 안 한다

#1079 가 이 모듈 리소스를 afternote_ 로 통일하기로 정해 놓아서 신규 키는 처음부터 그 규약을 따랐다. 반면 기존 무접두 키(content_description_video_play 등)의 리네임은 하지 않았다 — #1079 의 일괄 처리 몫이고 지금 손대면 충돌한다. 그래서 이 PR 안에 두 네이밍이 섞여 보이는데 의도된 것이다.

범위 밖 — 별도 이슈로 넘겼다

레포 전체 contentDescription 하드코딩 34건 중 내 담당은 6건이고, 나머지는 담당자 몫이라 0줄이다.

검증

로컬 실측 (워크트리 격리, 2429e0823 기준):

검증 결과
ktlintCheck (core:ui · afternote · receiver · onboarding, --rerun-tasks) BUILD SUCCESSFUL
:app:compileDebugUnitTestKotlin · :app:compileDebugAndroidTestKotlin BUILD SUCCESSFUL (4개 변경 모듈 전부 UP-TO-DATE 아닌 실제 컴파일 확인)
단위 테스트 4개 모듈 219건 실행 · 실패 0
건수 문장 공백 보존 ReceiverHomeCountFallbackTest 3건 통과 (XML 실행 증거 확인)
내 모듈 잔여 하드코딩 0건 (제외 판정 2건 제외)

화면 렌더 결과는 바뀌지 않는다. 바뀌는 건 문자열의 출처(코드 → 리소스)와, 플레이스홀더 1건의 낭독 여부다.

CI Test Plan

{
  "androidTest": {
    "mode": "none",
    "reason": "변경은 문자열 리소스 참조 치환과 장식 아이콘의 contentDescription 제거뿐이다. navigation·AndroidManifest·MainActivity·androidTest 소스 어느 것도 건드리지 않아 계측 경계 밖이고, 렌더 트리와 클릭 동작이 그대로라 계측을 돌려도 판별력이 없다. 결합 문구의 공백 보존처럼 실제로 깨질 수 있는 축은 Robolectric 단위 테스트가 이미 단언하며 219건 전량 통과를 확인했다."
  }
}

TalkBack 이 그대로 낭독하는 사용자 노출 문자열인데 코드에 박혀 있었다.

「영상 재생」은 content_description_video_play 가 이미 있고
MemorialVideoUpload 는 그걸 쓰는데, 추억 노트 상세 두 곳만 같은 문구를
리터럴로 다시 적고 있었다. 신설이 아니라 미사용 리소스 연결이다.

영상 썸네일 라벨은 신설하되 #1079 가 정한 afternote_ 프리픽스를 처음부터
따른다. 기존 무접두 키의 리네임은 그 이슈의 일괄 처리 몫이라 건드리지 않는다.

수신 상세의 "Play" 는 리소스화하지 않고 없앤다. 영상이 없을 때만 그리는
플레이스홀더라 clickable 이 없는데 재생으로 읽히면 없는 어포던스를 알린다.
맥락은 바로 위 섹션 헤더가 이미 읽어 준다.

에디터 섹션 라벨은 "$text, $필수항목" 조합을 포맷 리소스 한 개로 합쳤다.
구분자가 로케일에 딸린 문자열이라 코드에 두면 번역이 갈린다.
@github-actions

Copy link
Copy Markdown
Contributor

🚧 리뷰 적체 가드 — 이 PR 을 닫습니다

리뷰 응답을 기다리는 PR 이 2건 남아 있습니다.

PR 열린 날 경과 제목
#1468 2026-08-29 0일 fix(receiver): 수신자 홈 헤더에서 회원 설정 진입점을 내린다 (#613)
#1449 2026-08-29 0일 fix(mindrecord): 본문 링크에 스킴 제한과 이스케이프를 세운다 (#1067)

이 저장소는 리뷰 응답을 기다리는 PR 이 1건이라도 남아 있으면 새 PR 을 열 수 없습니다 (#1136).

각 PR 에 필요한 리뷰는 한 건입니다 — 누구든 먼저 판정을 내면 그 PR 은 모두의 목록에서 빠집니다. 승인 뒤 변경을 다시 볼 의무는 없고, 변경요청도 작성자가 같은 리뷰어에게 재요청한 뒤 반영 커밋을 올린 경우에만 다시 리뷰어의 몫이 됩니다.

되살리는 법

위 리뷰를 끝낸 뒤 이 PR 을 다시 여세요. 브랜치는 지워지지 않았고 커밋도 그대로입니다.

gh pr reopen 1472

리뷰보다 이 PR 이 급하면 review-debt-exempt 라벨을 붙이고 다시 열면 통과합니다.

@github-actions github-actions Bot closed this Aug 29, 2026
contentDescription 만 보던 범위를 화면에 그려지는 문자열 전체로 넓혔다.
성격이 같은데 앞 커밋에서 빠져 있었다.

절반 가까이가 신설이 아니라 이미 있는 리소스의 미사용이었다.
「장례식에 남길 영상」·「추억 플레이리스트」·「영상을 재생할 수 있는 앱이
없습니다.」는 리소스가 있는데 같은 문구를 리터럴로 다시 적고 있었고,
약관 상세는 본문 6개가 리소스인데 제목 6개만 코드에 남아 있었다.

nav_afternote 는 참조 0건인 죽은 키였다. 값이 같은 키를 새로 만드는 대신
afternote_home_title 로 이름을 바꿔 실제 쓰이게 했다 — 키 수는 그대로다.

MemorialPlaylist 의 label 은 기본값이 이미 그 리소스라 호출부에서 같은 값을
다시 넘기던 인자를 지웠다. 두 화면이 쓰던 「현재 N개의 노래가 담겨 있습니다.」는
문구가 완전히 같아 키 하나로 묶었다.

요일 라벨은 순서·개수가 고정된 집합이라 string-array 로 뒀다. 개별 키 7개는
호출부에서 listOf 로 다시 조립해야 해 순서가 어긋날 여지를 남긴다.

수신자 홈의 건수 문장은 rememberCountLine 이 숫자 앞부분과 뒷문장을 서로 다른
스타일로 그려 리소스도 그 경계대로 둘로 나눴다. 끝 공백이 렌더 결과에 유효해
XML 에서 따옴표로 감쌌고, 결합 결과를 단언하는 기존 테스트로 확인했다.

제외 2건은 노출 문자열이 아니다 — TextFieldShort 의 것은 @Preview 인자이고,
SaveAfternotePayloadBuilder 의 MEMORIAL_DEFAULT_TITLE 은 서버로 보내는
serviceName 값이라 리소스로 옮기면 로케일에 따라 전송값이 바뀐다.
@1hyok 1hyok changed the title refactor(afternote,receiver): contentDescription 하드코딩 6건을 문자열 리소스로 옮긴다 (#1469) refactor(core,afternote,receiver,onboarding): 화면 노출 문자열 33건을 리소스로 옮긴다 (#1469) Aug 29, 2026
@1hyok 1hyok reopened this Aug 29, 2026
@github-actions github-actions Bot added the conflict base 와 충돌 — CI 가 트리거되지 않는다. base 를 병합하면 자동으로 떨어진다 label Aug 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

이 PR 은 develop 와 충돌 상태이고, 그래서 CI 가 돌지 않는다.

pull_request 워크플로는 base 와 head 를 합친 가상 머지 커밋(refs/pull/<N>/merge)에서
실행되는데, 충돌이면 GitHub 이 그 ref 를 만들지 못해 워크플로가 트리거조차 되지 않는다.
체크가 실패하는 것이 아니라 아예 생성되지 않으므로, 새 커밋을 올려도 no checks reported
인 채 최신 커밋이 한 번도 검증되지 않은 상태로 남는다 (#1028).

develop 를 병합해 충돌을 풀면 검증이 다시 돈다. 해소되면 이 라벨은 자동으로 떨어진다.

develop 이 수신 애프터노트 화면을 afternote 모듈로 되옮기면서(#1464) 이 브랜치가 리소스화한
두 자리와 겹쳤다.

- MemorialReceivedDetailScreen: 리소스화(content_description_video_play)를 살리고, 같은 모듈
  안이 됐으므로 AfternoteR alias 를 로컬 R 로 바꾼다
- strings.xml: 양쪽 키 집합이 서로 달라 둘 다 유지한다

:app:compileDebugKotlin · :feature:afternote:presentation:ktlintCheck BUILD SUCCESSFUL
@github-actions github-actions Bot added conflict base 와 충돌 — CI 가 트리거되지 않는다. base 를 병합하면 자동으로 떨어진다 and removed conflict base 와 충돌 — CI 가 트리거되지 않는다. base 를 병합하면 자동으로 떨어진다 labels Aug 29, 2026
충돌 3곳을 develop 쪽 표시로 맞춰 푼다.

- 추억 노트 상세 제목 꼬리: develop 이 0dc1c28 로 같은 문자열을 먼저
  리소스화했고, 그 문구에는 줄바꿈(\n)이 들어 있다. 이 브랜치가 분기한
  뒤 develop 에 들어온 표시 변경이므로 develop 판
  feature_afternote_memorial_detail_title_suffix{,_no_name} 을 남긴다.
- 그래서 중복이 된 afternote_detail_record_suffix_{anonymous,named} 2건을
  걷는다. 이 두 키의 참조는 위 한 곳뿐이었다.
- core/ui strings.xml 은 양쪽이 서로 다른 문자열을 끝에 덧붙인 것이라
  둘 다 남긴다.
@github-actions github-actions Bot removed the conflict base 와 충돌 — CI 가 트리거되지 않는다. base 를 병합하면 자동으로 떨어진다 label Aug 29, 2026
@github-actions github-actions Bot added the conflict base 와 충돌 — CI 가 트리거되지 않는다. base 를 병합하면 자동으로 떨어진다 label Aug 29, 2026
develop 의 #1395(영상 스킴 가드)와 같은 자리를 건드려 충돌했다. 구조는 develop 의
launchReceivedMemorialVideo 를 그대로 두고, 이 PR 이 리소스로 뺀 문자열만 다시 끼운다.

- onUnavailable 문구는 R.string.receiver_memorial_video_no_app (noVideoAppMessage) 로 복원.
- onRejected 문구는 develop 이 새로 들인 문자열이라 리터럴로 둔다. 이 토스트 2종의
  채널 전환·리소스화는 develop 주석대로 #1391 건 3 의 몫이다.
@github-actions github-actions Bot removed the conflict base 와 충돌 — CI 가 트리거되지 않는다. base 를 병합하면 자동으로 떨어진다 label Aug 29, 2026
@1hyok
1hyok enabled auto-merge August 29, 2026 14:54
@1hyok
1hyok added this pull request to the merge queue Aug 29, 2026
Merged via the queue into develop with commit 8f5f1e5 Aug 29, 2026
19 checks passed
@1hyok
1hyok deleted the refactor/1469-content-description-resources branch August 29, 2026 15:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor(afternote): 담당 모듈 화면 노출 문자열 33건 리소스화 — 절반이 「이미 있는 리소스의 미사용」

2 participants