fix(chat-room): 접근성 라벨 및 다국어 문자열 적용
- 레이아웃 contentDescription 하드코딩 제거 및 strings 리소스화 - ChatMessageAdapter 접근성 문구를 리소스 기반으로 변환 - values-en 추가로 안내/버튼/접근성/상태 문구 영문화 - 타이핑 인디케이터 접근성 라벨 추가
This commit is contained in:
		@@ -323,11 +323,12 @@ class ChatMessageAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
 | 
				
			|||||||
            // 그룹 내부 간격 최소화 (상단 패딩 축소)
 | 
					            // 그룹 내부 간격 최소화 (상단 패딩 축소)
 | 
				
			||||||
            adjustTopPadding(isGrouped)
 | 
					            adjustTopPadding(isGrouped)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 접근성: 상태 포함 설명
 | 
					            // 접근성: 상태 포함 설명 (리소스 기반)
 | 
				
			||||||
 | 
					            val ctx = binding.root.context
 | 
				
			||||||
            val statusDesc = when (data.status) {
 | 
					            val statusDesc = when (data.status) {
 | 
				
			||||||
                MessageStatus.SENDING -> "전송 중"
 | 
					                MessageStatus.SENDING -> ctx.getString(R.string.status_sending)
 | 
				
			||||||
                MessageStatus.FAILED -> "전송 실패"
 | 
					                MessageStatus.FAILED -> ctx.getString(R.string.status_failed)
 | 
				
			||||||
                MessageStatus.SENT -> "전송 완료"
 | 
					                MessageStatus.SENT -> ctx.getString(R.string.status_sent)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            val timeDesc = if (showTime) {
 | 
					            val timeDesc = if (showTime) {
 | 
				
			||||||
@@ -336,8 +337,9 @@ class ChatMessageAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
 | 
				
			|||||||
                ""
 | 
					                ""
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val myPrefix = ctx.getString(R.string.a11y_my_message_prefix)
 | 
				
			||||||
            binding.root.contentDescription =
 | 
					            binding.root.contentDescription =
 | 
				
			||||||
                "내 메시지 ${binding.tvMessage.text}, $statusDesc, $timeDesc"
 | 
					                "$myPrefix ${binding.tvMessage.text}, $statusDesc, $timeDesc"
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private fun adjustTopPadding(isGrouped: Boolean) {
 | 
					        private fun adjustTopPadding(isGrouped: Boolean) {
 | 
				
			||||||
@@ -379,13 +381,16 @@ class ChatMessageAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
 | 
				
			|||||||
            // 그룹 내부 간격 최소화 (상단 패딩 축소)
 | 
					            // 그룹 내부 간격 최소화 (상단 패딩 축소)
 | 
				
			||||||
            adjustTopPadding(isGrouped)
 | 
					            adjustTopPadding(isGrouped)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 접근성
 | 
					            // 접근성: 다국어 대응
 | 
				
			||||||
 | 
					            val ctx = itemView.context
 | 
				
			||||||
 | 
					            val messageWord = ctx.getString(R.string.a11y_message_word)
 | 
				
			||||||
            itemView.contentDescription = buildString {
 | 
					            itemView.contentDescription = buildString {
 | 
				
			||||||
                if (!isGrouped && !binding.tvName.text.isNullOrEmpty()) {
 | 
					                if (!isGrouped && !binding.tvName.text.isNullOrEmpty()) {
 | 
				
			||||||
                    append(binding.tvName.text)
 | 
					                    append(binding.tvName.text)
 | 
				
			||||||
                    append(" ")
 | 
					                    append(" ")
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                append("메시지 ")
 | 
					                append(messageWord)
 | 
				
			||||||
 | 
					                append(" ")
 | 
				
			||||||
                append(binding.tvMessage.text)
 | 
					                append(binding.tvMessage.text)
 | 
				
			||||||
                if (showTime) {
 | 
					                if (showTime) {
 | 
				
			||||||
                    append(", ")
 | 
					                    append(", ")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,7 @@
 | 
				
			|||||||
        app:layout_constraintBottom_toBottomOf="parent"
 | 
					        app:layout_constraintBottom_toBottomOf="parent"
 | 
				
			||||||
        app:layout_constraintStart_toStartOf="parent"
 | 
					        app:layout_constraintStart_toStartOf="parent"
 | 
				
			||||||
        app:layout_constraintEnd_toEndOf="parent"
 | 
					        app:layout_constraintEnd_toEndOf="parent"
 | 
				
			||||||
        android:contentDescription="프로필 배경 이미지" />
 | 
					        android:contentDescription="@string/a11y_profile_background" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <!-- 딤 처리 (activity_character_detail.xml의 view_character_dim 스타일 참조) -->
 | 
					    <!-- 딤 처리 (activity_character_detail.xml의 view_character_dim 스타일 참조) -->
 | 
				
			||||||
    <View
 | 
					    <View
 | 
				
			||||||
@@ -58,7 +58,7 @@
 | 
				
			|||||||
            android:layout_width="24dp"
 | 
					            android:layout_width="24dp"
 | 
				
			||||||
            android:layout_height="24dp"
 | 
					            android:layout_height="24dp"
 | 
				
			||||||
            android:src="@drawable/ic_back"
 | 
					            android:src="@drawable/ic_back"
 | 
				
			||||||
            android:contentDescription="뒤로가기"
 | 
					            android:contentDescription="@string/a11y_back"
 | 
				
			||||||
            app:layout_constraintStart_toStartOf="parent"
 | 
					            app:layout_constraintStart_toStartOf="parent"
 | 
				
			||||||
            app:layout_constraintTop_toTopOf="parent"
 | 
					            app:layout_constraintTop_toTopOf="parent"
 | 
				
			||||||
            app:layout_constraintBottom_toBottomOf="parent" />
 | 
					            app:layout_constraintBottom_toBottomOf="parent" />
 | 
				
			||||||
@@ -69,7 +69,7 @@
 | 
				
			|||||||
            android:layout_height="36dp"
 | 
					            android:layout_height="36dp"
 | 
				
			||||||
            android:layout_marginStart="12dp"
 | 
					            android:layout_marginStart="12dp"
 | 
				
			||||||
            android:src="@drawable/ic_placeholder_profile"
 | 
					            android:src="@drawable/ic_placeholder_profile"
 | 
				
			||||||
            android:contentDescription="프로필 이미지"
 | 
					            android:contentDescription="@string/a11y_profile_image"
 | 
				
			||||||
            app:layout_constraintStart_toEndOf="@id/iv_back"
 | 
					            app:layout_constraintStart_toEndOf="@id/iv_back"
 | 
				
			||||||
            app:layout_constraintTop_toTopOf="parent"
 | 
					            app:layout_constraintTop_toTopOf="parent"
 | 
				
			||||||
            app:layout_constraintBottom_toBottomOf="parent" />
 | 
					            app:layout_constraintBottom_toBottomOf="parent" />
 | 
				
			||||||
@@ -126,7 +126,7 @@
 | 
				
			|||||||
            android:layout_height="20dp"
 | 
					            android:layout_height="20dp"
 | 
				
			||||||
            android:src="@android:drawable/ic_dialog_info"
 | 
					            android:src="@android:drawable/ic_dialog_info"
 | 
				
			||||||
            app:tint="#FFFFFFFF"
 | 
					            app:tint="#FFFFFFFF"
 | 
				
			||||||
            android:contentDescription="안내"
 | 
					            android:contentDescription="@string/a11y_notice"
 | 
				
			||||||
            app:layout_constraintStart_toStartOf="parent"
 | 
					            app:layout_constraintStart_toStartOf="parent"
 | 
				
			||||||
            app:layout_constraintTop_toTopOf="parent"
 | 
					            app:layout_constraintTop_toTopOf="parent"
 | 
				
			||||||
            app:layout_constraintBottom_toBottomOf="parent" />
 | 
					            app:layout_constraintBottom_toBottomOf="parent" />
 | 
				
			||||||
@@ -139,7 +139,7 @@
 | 
				
			|||||||
            android:layout_marginEnd="8dp"
 | 
					            android:layout_marginEnd="8dp"
 | 
				
			||||||
            android:textColor="#FFFFFFFF"
 | 
					            android:textColor="#FFFFFFFF"
 | 
				
			||||||
            android:textSize="12sp"
 | 
					            android:textSize="12sp"
 | 
				
			||||||
            android:text="AI Clone은 크리에이터의 정보를 기반으로 대화하지만, 모든 정보를 완벽하게 반영하거나 실제 대화와 일치하지 않을 수 있습니다."
 | 
					            android:text="@string/chat_notice_clone"
 | 
				
			||||||
            app:layout_constraintStart_toEndOf="@id/iv_notice_icon"
 | 
					            app:layout_constraintStart_toEndOf="@id/iv_notice_icon"
 | 
				
			||||||
            app:layout_constraintTop_toTopOf="parent"
 | 
					            app:layout_constraintTop_toTopOf="parent"
 | 
				
			||||||
            app:layout_constraintBottom_toBottomOf="parent"
 | 
					            app:layout_constraintBottom_toBottomOf="parent"
 | 
				
			||||||
@@ -151,7 +151,7 @@
 | 
				
			|||||||
            android:layout_height="20dp"
 | 
					            android:layout_height="20dp"
 | 
				
			||||||
            android:src="@android:drawable/arrow_up_float"
 | 
					            android:src="@android:drawable/arrow_up_float"
 | 
				
			||||||
            app:tint="#FFFFFFFF"
 | 
					            app:tint="#FFFFFFFF"
 | 
				
			||||||
            android:contentDescription="접기"
 | 
					            android:contentDescription="@string/a11y_collapse"
 | 
				
			||||||
            app:layout_constraintEnd_toEndOf="parent"
 | 
					            app:layout_constraintEnd_toEndOf="parent"
 | 
				
			||||||
            app:layout_constraintTop_toTopOf="parent"
 | 
					            app:layout_constraintTop_toTopOf="parent"
 | 
				
			||||||
            app:layout_constraintBottom_toBottomOf="parent" />
 | 
					            app:layout_constraintBottom_toBottomOf="parent" />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,7 @@
 | 
				
			|||||||
        android:layout_marginEnd="8dp"
 | 
					        android:layout_marginEnd="8dp"
 | 
				
			||||||
        android:scaleType="centerCrop"
 | 
					        android:scaleType="centerCrop"
 | 
				
			||||||
        android:src="@drawable/ic_placeholder_profile"
 | 
					        android:src="@drawable/ic_placeholder_profile"
 | 
				
			||||||
        android:contentDescription="AI 프로필 이미지"
 | 
					        android:contentDescription="@string/a11y_ai_profile_image"
 | 
				
			||||||
        app:layout_constraintStart_toStartOf="parent"
 | 
					        app:layout_constraintStart_toStartOf="parent"
 | 
				
			||||||
        app:layout_constraintTop_toTopOf="parent"
 | 
					        app:layout_constraintTop_toTopOf="parent"
 | 
				
			||||||
        app:layout_constraintBottom_toBottomOf="parent" />
 | 
					        app:layout_constraintBottom_toBottomOf="parent" />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,8 @@
 | 
				
			|||||||
    android:paddingStart="12dp"
 | 
					    android:paddingStart="12dp"
 | 
				
			||||||
    android:paddingEnd="12dp"
 | 
					    android:paddingEnd="12dp"
 | 
				
			||||||
    android:paddingTop="6dp"
 | 
					    android:paddingTop="6dp"
 | 
				
			||||||
    android:paddingBottom="6dp">
 | 
					    android:paddingBottom="6dp"
 | 
				
			||||||
 | 
					    android:contentDescription="@string/a11y_typing">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <!-- 프로필 이미지 (AI) -->
 | 
					    <!-- 프로필 이미지 (AI) -->
 | 
				
			||||||
    <ImageView
 | 
					    <ImageView
 | 
				
			||||||
@@ -22,7 +23,7 @@
 | 
				
			|||||||
        android:layout_marginEnd="8dp"
 | 
					        android:layout_marginEnd="8dp"
 | 
				
			||||||
        android:scaleType="centerCrop"
 | 
					        android:scaleType="centerCrop"
 | 
				
			||||||
        android:src="@drawable/ic_placeholder_profile"
 | 
					        android:src="@drawable/ic_placeholder_profile"
 | 
				
			||||||
        android:contentDescription="AI 프로필 이미지"
 | 
					        android:contentDescription="@string/a11y_ai_profile_image"
 | 
				
			||||||
        app:layout_constraintStart_toStartOf="parent"
 | 
					        app:layout_constraintStart_toStartOf="parent"
 | 
				
			||||||
        app:layout_constraintTop_toTopOf="parent"
 | 
					        app:layout_constraintTop_toTopOf="parent"
 | 
				
			||||||
        app:layout_constraintBottom_toBottomOf="parent" />
 | 
					        app:layout_constraintBottom_toBottomOf="parent" />
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								app/src/main/res/values-en/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								app/src/main/res/values-en/strings.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					<resources>
 | 
				
			||||||
 | 
					    <!-- Chat Room UI strings (English) -->
 | 
				
			||||||
 | 
					    <string name="chat_notice_clone">AI Clone converses based on the creator\'s information, but it may not perfectly reflect all details or match real conversations.</string>
 | 
				
			||||||
 | 
					    <string name="chat_notice_character">VoiceOn AI Character Talk allows a high degree of freedom. You can be anyone in the conversation. Talk as a character in a universe or create your own story with a new persona together with the character.\nNote: AI Character Talk is in open beta; conversations may be awkward or incomplete.</string>
 | 
				
			||||||
 | 
					    <string name="chat_input_placeholder">Type a message</string>
 | 
				
			||||||
 | 
					    <string name="action_send">Send</string>
 | 
				
			||||||
 | 
					    <string name="action_retry">Retry</string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- Accessibility labels -->
 | 
				
			||||||
 | 
					    <string name="a11y_profile_background">Profile background image</string>
 | 
				
			||||||
 | 
					    <string name="a11y_back">Back</string>
 | 
				
			||||||
 | 
					    <string name="a11y_profile_image">Profile image</string>
 | 
				
			||||||
 | 
					    <string name="a11y_notice">Notice</string>
 | 
				
			||||||
 | 
					    <string name="a11y_collapse">Collapse</string>
 | 
				
			||||||
 | 
					    <string name="a11y_ai_profile_image">AI profile image</string>
 | 
				
			||||||
 | 
					    <string name="a11y_typing">Typing…</string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- Accessibility phrases for adapter -->
 | 
				
			||||||
 | 
					    <string name="a11y_my_message_prefix">My message</string>
 | 
				
			||||||
 | 
					    <string name="a11y_message_word">Message</string>
 | 
				
			||||||
 | 
					    <string name="status_sending">Sending</string>
 | 
				
			||||||
 | 
					    <string name="status_failed">Failed to send</string>
 | 
				
			||||||
 | 
					    <string name="status_sent">Sent</string>
 | 
				
			||||||
 | 
					</resources>
 | 
				
			||||||
@@ -19,4 +19,19 @@
 | 
				
			|||||||
    <string name="chat_input_placeholder">메세지를 입력하세요.</string>
 | 
					    <string name="chat_input_placeholder">메세지를 입력하세요.</string>
 | 
				
			||||||
    <string name="action_send">전송</string>
 | 
					    <string name="action_send">전송</string>
 | 
				
			||||||
    <string name="action_retry">다시 전송</string>
 | 
					    <string name="action_retry">다시 전송</string>
 | 
				
			||||||
 | 
					    <!-- Accessibility labels -->
 | 
				
			||||||
 | 
					    <string name="a11y_profile_background">프로필 배경 이미지</string>
 | 
				
			||||||
 | 
					    <string name="a11y_back">뒤로가기</string>
 | 
				
			||||||
 | 
					    <string name="a11y_profile_image">프로필 이미지</string>
 | 
				
			||||||
 | 
					    <string name="a11y_notice">안내</string>
 | 
				
			||||||
 | 
					    <string name="a11y_collapse">접기</string>
 | 
				
			||||||
 | 
					    <string name="a11y_ai_profile_image">AI 프로필 이미지</string>
 | 
				
			||||||
 | 
					    <string name="a11y_typing">상대방이 입력 중</string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- Accessibility phrases for adapter -->
 | 
				
			||||||
 | 
					    <string name="a11y_my_message_prefix">내 메시지</string>
 | 
				
			||||||
 | 
					    <string name="a11y_message_word">메시지</string>
 | 
				
			||||||
 | 
					    <string name="status_sending">전송 중</string>
 | 
				
			||||||
 | 
					    <string name="status_failed">전송 실패</string>
 | 
				
			||||||
 | 
					    <string name="status_sent">전송 완료</string>
 | 
				
			||||||
</resources>
 | 
					</resources>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user