Skip to content

[Feat/#305] 영어버전 국제화를 마무리합니다.#308

Merged
SYAAINN merged 11 commits intodevelopfrom
feat/#305-en-i18n
Jul 23, 2025
Merged

[Feat/#305] 영어버전 국제화를 마무리합니다.#308
SYAAINN merged 11 commits intodevelopfrom
feat/#305-en-i18n

Conversation

@SYAAINN
Copy link
Contributor

@SYAAINN SYAAINN commented Jul 21, 2025

📌 ISSUE

closed #305

📄 Work Description

홈 화면 변경사항

  • 탑바 연/월 포맷 변경
  • 달력 요일 포맷 변경
  • 연/월 피커 순서 설정

일기쓰기 화면 변경사항

  • 월,일, 요일 포맷 변경

답장확인 화면 변경사항

  • 월,일 포맷 변경
  • 타이틀(이름) 리소스 %d -> %s 오류 해결

알림설정 화면 변경사항

  • 시간 포맷 변경

일기 모아보기 화면 변경사항

  • 탑바 연/월 포맷 변경
  • 일일 일기 카드 요일 포맷 변경
  • 연/월 피커 순서 설정

✨ PR Point

UI 쪽에서 언어 분기 처리를 진행하려고 하다보니 최대한 strings.xml 리소스를 활용하여 진행하려 했지만, 어쩔 수 없이 locale을 가져오는 부분이 생겼습니다. LaungeProvider로 일원화 하고싶었지만 녹록치가 않네요 ㅜㅜ

📸 ScreenShot/Video

일기 모아보기(리스트) 연,월 타임피커
home diary_list year_month_picker
일기쓰기 답장확인 알림설정
write_diary reply notification_setting

Summary by CodeRabbit

  • New Features

    • Year and month labels throughout the app are now localized based on the user's language settings.
    • The year/month picker UI is enhanced with locale-aware ordering, improved scrolling, and visual effects.
  • Bug Fixes

    • Corrected input validation for nicknames and diary entries to properly enforce length limits.
  • Refactor

    • Simplified and improved date and day-of-week display by leveraging system locale and standard APIs.
    • Updated top app bar and diary screens to use localized date formats and improved label formatting.
    • Removed redundant or unused UI components and extension functions.
    • Replaced custom date label extensions with new locale-aware composable implementations.
  • Style

    • Adjusted text alignment and typography for improved visual consistency.
  • Documentation

    • Updated string resources for clearer and more flexible date/time formatting in multiple languages.

@SYAAINN SYAAINN requested a review from MoonsuKang July 21, 2025 06:58
@SYAAINN SYAAINN self-assigned this Jul 21, 2025
@SYAAINN SYAAINN added ✨ FEAT 기능 개발 🔥 민재 민재 labels Jul 21, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 21, 2025

Walkthrough

This update implements comprehensive internationalization for date and time formatting across the app. It introduces new localized extension functions for year and month labels, updates string resources to use string placeholders, replaces hardcoded date logic with locale-aware formatting, and removes or refactors components to support dynamic, language-appropriate display of dates and times in both Korean and English.

Changes

File(s) / Group Change Summary
.../SignUpViewModel.kt, .../WriteDiaryViewModel.kt Fixed regex quantifier syntax errors for nickname and diary entry validation.
.../ui/component/dialog/ClodyDialog.kt Centered dialog title text using TextAlign.Center.
.../ui/component/timepicker/YearMonthPicker.kt, .../YearMonthPickerItem.kt (deleted) Refactored year/month picker: locale-aware order, new scrollable picker with snapping and fading edges, removed old picker file.
.../ui/diarylist/component/DiaryListTopAppBar.kt, .../ui/home/component/HomeTopAppBar.kt Changed selectedYear/selectedMonth parameter types from Int to String.
.../ui/diarylist/screen/DiaryListScreen.kt, .../ui/home/screen/HomeScreen.kt, .../ui/replydiary/ReplyDiaryScreen.kt Applied new localized year/month label extensions to display formatted strings.
.../ui/diarylist/screen/DiaryListViewModel.kt Replaced custom day-of-week logic with Java LocalDate.
.../ui/home/calendar/component/DailyDiaryListItem.kt, .../ui/home/calendar/component/WeekHeader.kt Switched day-of-week display to locale-aware Java API, removed custom enums and preview composables.
.../ui/home/component/YearAndMonthTitle.kt (deleted) Removed now-obsolete year/month title composable.
.../ui/writediary/component/text/DiaryTitleText.kt (deleted), .../ui/writediary/screen/WriteDiaryScreen.kt Replaced custom diary title composable with localized Text using string resources.
.../utils/extension/GetDayOfWeek.kt, .../utils/extension/StringExt.kt Made day-of-week and 12-hour time formatting composable and locale-aware.
.../utils/extension/YearMonthLabelUtil.kt Removed old localized year/month label extensions.
.../utils/extension/DateLabelExtension.kt (new) Added new composable extensions for localized year/month label formatting.
.../res/values-ko/strings.xml, .../res/values/strings.xml Updated and reorganized string resources for modular, locale-aware date/time formatting.

Sequence Diagram(s)

sequenceDiagram
    participant UI as User Interface
    participant Ext as DateLabelExtension
    participant Strings as String Resources
    participant Locale as Locale API

    UI->>Ext: selectedYear.toLocalizedYearLabel()
    Ext->>Strings: get year_format string for locale
    Ext->>Locale: get current locale
    Ext-->>UI: localized year string

    UI->>Ext: selectedMonth.toLocalizedMonthLabel()
    Ext->>Locale: get current locale
    alt Korean
        Ext->>Strings: get month_format string
        Ext-->>UI: localized month string
    else Other
        Ext->>Locale: get English month name
        Ext-->>UI: formatted English month string
    end

    UI->>Strings: Use home_year_month_format with localized year/month
Loading

Estimated code review effort

4 (~80–100 minutes)

Possibly related PRs

Suggested labels

🌊 문수

Poem

A bunny with code in its paws,
Hops through locales, fixing flaws.
Dates and months now dance and sing,
In English or Korean—what joy they bring!
With strings aligned and formats bright,
The world reads dates just right.
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 81e225d and a80bed0.

📒 Files selected for processing (5)
  • app/src/main/java/com/sopt/clody/presentation/ui/component/timepicker/YearMonthPicker.kt (5 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/diarylist/screen/DiaryListViewModel.kt (2 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/home/calendar/component/DailyDiaryListItem.kt (3 hunks)
  • app/src/main/java/com/sopt/clody/presentation/utils/extension/DateLabelExtension.kt (1 hunks)
  • app/src/main/java/com/sopt/clody/presentation/utils/extension/GetDayOfWeek.kt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • app/src/main/java/com/sopt/clody/presentation/ui/diarylist/screen/DiaryListViewModel.kt
  • app/src/main/java/com/sopt/clody/presentation/ui/home/calendar/component/DailyDiaryListItem.kt
  • app/src/main/java/com/sopt/clody/presentation/utils/extension/DateLabelExtension.kt
  • app/src/main/java/com/sopt/clody/presentation/utils/extension/GetDayOfWeek.kt
  • app/src/main/java/com/sopt/clody/presentation/ui/component/timepicker/YearMonthPicker.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🔭 Outside diff range comments (3)
app/src/main/java/com/sopt/clody/presentation/ui/home/calendar/component/WeekHeader.kt (1)

25-33: Excellent architectural improvement!

Removing the custom WeekLang enum and extension functions in favor of standard Java time APIs is a significant improvement. This approach is more maintainable, leverages well-tested standard libraries, and automatically supports all locales without manual mapping.

Apply the same safe locale access pattern:

-text = week.getDisplayName(TextStyle.NARROW, LocalConfiguration.current.locales[0]),
+text = week.getDisplayName(TextStyle.NARROW, LocalConfiguration.current.locales.let { if (it.isEmpty()) java.util.Locale.getDefault() else it[0] }),

Also applies to: 39-52

app/src/main/java/com/sopt/clody/presentation/utils/extension/StringExt.kt (1)

24-32: Hardcoded Korean strings contradict internationalization goals.

The to24HourFormat function contains hardcoded Korean strings "오후" and "오전" which defeats the purpose of internationalization. This function should accept localized strings or be made @composable to use string resources.

Consider one of these approaches:

  1. Make it @composable and use string resources:
+@Composable
 fun Triple<String, String, String>.to24HourFormat(): String {
     val (amPm, hour, minute) = this
+    val pmString = stringResource(R.string.time_pm)
+    val amString = stringResource(R.string.time_am)
     val hourInt = when {
-        amPm == "오후" && hour.toInt() != 12 -> hour.toInt() + 12
-        amPm == "오전" && hour.toInt() == 12 -> 0
+        amPm == pmString && hour.toInt() != 12 -> hour.toInt() + 12
+        amPm == amString && hour.toInt() == 12 -> 0
         else -> hour.toInt()
     }
     return String.format("%02d:%02d", hourInt, minute.toInt())
 }
  1. Pass the localized strings as parameters:
-fun Triple<String, String, String>.to24HourFormat(): String {
+fun Triple<String, String, String>.to24HourFormat(amString: String, pmString: String): String {
     val (amPm, hour, minute) = this
     val hourInt = when {
-        amPm == "오후" && hour.toInt() != 12 -> hour.toInt() + 12
-        amPm == "오전" && hour.toInt() == 12 -> 0
+        amPm == pmString && hour.toInt() != 12 -> hour.toInt() + 12
+        amPm == amString && hour.toInt() == 12 -> 0
         else -> hour.toInt()
     }
     return String.format("%02d:%02d", hourInt, minute.toInt())
 }
app/src/main/java/com/sopt/clody/presentation/ui/component/timepicker/YearMonthPicker.kt (1)

170-175: Potential IndexOutOfBounds risk when converting labels back to values.

The indexOf calls on lines 172-173 could return -1 if the localized strings don't match exactly, which would cause an IndexOutOfBoundsException when accessing the lists.

 val year = yearItems[yearLabelItems.indexOf(yearPickerState.selectedItem)]
 val month = monthItems[monthLabelItems.indexOf(monthPickerState.selectedItem)]
+// Add validation
+val yearIndex = yearLabelItems.indexOf(yearPickerState.selectedItem)
+val monthIndex = monthLabelItems.indexOf(monthPickerState.selectedItem)
+if (yearIndex == -1 || monthIndex == -1) {
+    // Handle error case
+    return
+}
+val year = yearItems[yearIndex]
+val month = monthItems[monthIndex]
🧹 Nitpick comments (8)
app/src/main/java/com/sopt/clody/presentation/ui/component/dialog/ClodyDialog.kt (1)

38-40: Typo in parameter names: MassageMessage
The current spelling may confuse contributors and hurts autocomplete/searchability.

-fun ClodyDialog(
-    titleMassage: String,
-    descriptionMassage: String,
+fun ClodyDialog(
+    titleMessage: String,
+    descriptionMessage: String,

Don’t forget to rename the corresponding usages inside the body.

app/src/main/java/com/sopt/clody/presentation/ui/auth/signup/SignUpViewModel.kt (1)

178-178: LGTM! Regex syntax is now correct.

The quantifier closure fix resolves the syntax error and the regex will now properly validate nicknames between 2 and the maximum allowed length.

Minor optimization opportunity - the character class contains 가-힣 twice, which is redundant:

-val regex = "^[a-zA-Z가-힣0-9ㄱ-ㅎㅏ-ㅣ가-힣]{2,${state.nicknameMaxLength}}$".toRegex()
+val regex = "^[a-zA-Z가-힣0-9ㄱ-ㅎㅏ-ㅣ]{2,${state.nicknameMaxLength}}$".toRegex()
app/src/main/java/com/sopt/clody/presentation/utils/extension/StringExt.kt (1)

7-22: Consider simplifying the minute formatting logic.

The minute formatting on line 19 can be simplified by using String.format directly with the integer value.

-    val minuteAfter = if (minuteBefore == 0) "00" else minuteBefore.toString()
-
-    return String.format(stringResource(R.string.notification_setting_selected_time, amPm, hourAfter, minuteAfter))
+    return String.format(stringResource(R.string.notification_setting_selected_time, amPm, hourAfter, minuteBefore))
app/src/main/java/com/sopt/clody/presentation/utils/extension/IntExtension.kt (1)

1-23: Consider API consistency and simplification.

  1. You're importing kotlinx.datetime.Month but using java.time.format.TextStyle. Consider using consistent APIs.
  2. The locale check only considers the first locale, which might miss user preferences.
  3. The string manipulation for capitalizing month names can be simplified.
-import kotlinx.datetime.Month
-import java.time.format.TextStyle
+import java.time.Month
+import java.time.format.TextStyle
 import java.util.Locale
 
 @Composable
 fun Int.toLocalizedYearLabel(): String = stringResource(R.string.year_format, this)
 
 @Composable
 fun Int.toLocalizedMonthLabel(): String {
-    val locale = LocalContext.current.resources.configuration.locales[0]
+    val locale = LocalContext.current.resources.configuration.locales.get(0)
     return if (locale.language == "ko") {
         stringResource(R.string.month_format, this)
     } else {
         Month.of(this).getDisplayName(TextStyle.FULL, Locale.ENGLISH)
-            .lowercase().replaceFirstChar { it.titlecase() }
+            .lowercase(Locale.ENGLISH)
+            .replaceFirstChar { it.uppercase(Locale.ENGLISH) }
     }
 }
app/src/main/res/values-ko/strings.xml (1)

107-107: Consider zero-padding minutes for consistency
Current pattern %1$s %2$d시 %3$s분 will show 3분 instead of 03분.

-<string name="notification_setting_selected_time">%1$s %2$d시 %3$s분</string>
+<string name="notification_setting_selected_time">%1$s %2$d시 %3$02d분</string>
app/src/main/res/values/strings.xml (3)

45-47: Placeholder type is numeric but consumed as string downstream
year_format and month_format use %d, yet the resulting strings are later passed as %s. This is fine at runtime, but for stronger type-safety you could make them %s in both locales to keep the contract uniform.


73-74: Minor style inconsistency
reply_title capitalises only the first word after the article (“lucky reply”). Consider title case (“Lucky Reply”) to match other headings.


107-107: 12-hour time string: pad minutes for single digits
Same suggestion as for the Korean resource—use %02d to avoid “3:5 PM”.

-<string name="notification_setting_selected_time">%2$d:%3$s %1$s</string>
+<string name="notification_setting_selected_time">%2$d:%3$02d %1$s</string>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6178853 and dd449f1.

📒 Files selected for processing (22)
  • app/src/main/java/com/sopt/clody/presentation/ui/auth/signup/SignUpViewModel.kt (1 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/component/dialog/ClodyDialog.kt (1 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/component/timepicker/YearMonthPicker.kt (5 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/component/timepicker/YearMonthPickerItem.kt (0 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/diarylist/component/DiaryListTopAppBar.kt (1 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/diarylist/screen/DiaryListScreen.kt (2 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/diarylist/screen/DiaryListViewModel.kt (2 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/home/calendar/component/DailyDiaryListItem.kt (3 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/home/calendar/component/WeekHeader.kt (2 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/home/component/HomeTopAppBar.kt (2 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/home/component/YearAndMonthTitle.kt (0 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/home/screen/HomeScreen.kt (3 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/replydiary/ReplyDiaryScreen.kt (3 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/writediary/component/text/DiaryTitleText.kt (0 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/writediary/screen/WriteDiaryScreen.kt (3 hunks)
  • app/src/main/java/com/sopt/clody/presentation/ui/writediary/screen/WriteDiaryViewModel.kt (1 hunks)
  • app/src/main/java/com/sopt/clody/presentation/utils/extension/GetDayOfWeek.kt (1 hunks)
  • app/src/main/java/com/sopt/clody/presentation/utils/extension/IntExtension.kt (1 hunks)
  • app/src/main/java/com/sopt/clody/presentation/utils/extension/StringExt.kt (1 hunks)
  • app/src/main/java/com/sopt/clody/presentation/utils/extension/YearMonthLabelUtil.kt (0 hunks)
  • app/src/main/res/values-ko/strings.xml (3 hunks)
  • app/src/main/res/values/strings.xml (4 hunks)
💤 Files with no reviewable changes (4)
  • app/src/main/java/com/sopt/clody/presentation/utils/extension/YearMonthLabelUtil.kt
  • app/src/main/java/com/sopt/clody/presentation/ui/home/component/YearAndMonthTitle.kt
  • app/src/main/java/com/sopt/clody/presentation/ui/writediary/component/text/DiaryTitleText.kt
  • app/src/main/java/com/sopt/clody/presentation/ui/component/timepicker/YearMonthPickerItem.kt
🧰 Additional context used
🧬 Code Graph Analysis (2)
app/src/main/java/com/sopt/clody/presentation/ui/writediary/screen/WriteDiaryScreen.kt (1)
app/src/main/java/com/sopt/clody/presentation/utils/extension/GetDayOfWeek.kt (1)
  • getDayOfWeek (8-12)
app/src/main/java/com/sopt/clody/presentation/ui/component/timepicker/YearMonthPicker.kt (1)
app/src/main/java/com/sopt/clody/presentation/ui/component/timepicker/PickerState.kt (1)
  • rememberPickerState (15-16)
🔇 Additional comments (22)
app/src/main/java/com/sopt/clody/presentation/ui/component/dialog/ClodyDialog.kt (2)

78-82: Title centering improves readability – looks good
The newly-added textAlign = TextAlign.Center makes the dialog title consistent with the rest of the centered content.


124-129: Confirm button never dismisses the dialog
confirmAction() is invoked, but onDismiss() isn’t, so the dialog stays visible unless the caller manually closes it. Is that intentional?

-    confirmAction()
+    confirmAction()
+    onDismiss()   // ensure the dialog closes after the action succeeds

If confirmAction sometimes needs the dialog to stay open, consider adding a boolean return or pass a lambda to it so the caller can decide when to dismiss.

app/src/main/java/com/sopt/clody/presentation/ui/home/calendar/component/DailyDiaryListItem.kt (1)

53-53: Text style changes improve visual hierarchy.

The typography updates from body3Medium to body2Medium for the date and body2Medium to body2SemiBold for the day of week create better visual distinction and hierarchy.

Also applies to: 59-59

app/src/main/java/com/sopt/clody/presentation/ui/diarylist/component/DiaryListTopAppBar.kt (1)

32-33: Good architectural change for internationalization.

Changing parameter types from Int to String is the right approach for pre-localized year and month labels. This improves separation of concerns by moving formatting logic upstream and allows the component to focus solely on presentation.

app/src/main/java/com/sopt/clody/presentation/ui/writediary/screen/WriteDiaryViewModel.kt (1)

162-162: LGTM! Critical regex syntax fix.

The missing closing curly brace in the quantifier has been properly fixed, ensuring correct validation of diary entry length. The regex pattern appropriately supports both Korean and English characters for internationalization.

app/src/main/java/com/sopt/clody/presentation/ui/diarylist/screen/DiaryListScreen.kt (2)

28-29: LGTM! Proper localization imports added.

The new extension functions for localized year and month labels support the internationalization effort effectively.


135-136: LGTM! Consistent localization implementation.

Converting integer values to localized strings before passing to the UI component ensures proper internationalization. This approach aligns well with the broader localization strategy across the app.

app/src/main/java/com/sopt/clody/presentation/ui/replydiary/ReplyDiaryScreen.kt (3)

44-44: LGTM! Localization import added.

Adding the toLocalizedMonthLabel extension supports proper internationalization for month display.


122-122: LGTM! Consistent month localization.

Converting the month integer to a localized string ensures proper internationalization and aligns with the app's localization strategy.


146-146: Verify layout impact of modifier change.

The Column modifier changed from fillMaxWidth() to fillMaxSize(), which will make the column expand to fill the entire available space rather than just the width. Ensure this change produces the desired UI layout.

app/src/main/java/com/sopt/clody/presentation/ui/writediary/screen/WriteDiaryScreen.kt (3)

22-22: LGTM! Standard component import.

Using the standard Material3 Text component instead of a custom component promotes consistency and maintainability.


53-53: LGTM! Localization extension imported.

Adding the toLocalizedMonthLabel extension supports proper internationalization.


246-255: Excellent localization refactor!

This change significantly improves internationalization by:

  • Replacing the custom DiaryTitleText component with a standard Text composable
  • Using the getDayOfWeek composable which properly handles locale-aware day names
  • Using toLocalizedMonthLabel() for proper month localization
  • Leveraging string resources for flexible formatting

This approach aligns perfectly with the PR's objective of completing English version internationalization and provides a solid foundation for supporting multiple locales.

app/src/main/java/com/sopt/clody/presentation/ui/home/screen/HomeScreen.kt (1)

379-381: No null pointer risk with calendarState.message

The CalendarState.Error is instantiated in HomeViewModel.kt (line 133) as:

CalendarState.Error(exception.message ?: ErrorMessages.UNKNOWN_ERROR)

which guarantees calendarState.message is never null at runtime. No fallback change is needed.

app/src/main/java/com/sopt/clody/presentation/ui/home/component/HomeTopAppBar.kt (1)

24-89: LGTM! Clean implementation of localized date display.

The changes properly implement the localization approach by:

  • Accepting pre-localized strings instead of raw integers
  • Using a clean inline implementation with proper click handling
  • Maintaining consistent styling and behavior
app/src/main/java/com/sopt/clody/presentation/ui/component/timepicker/YearMonthPicker.kt (1)

246-250: Verify the intentional consumption of vertical drag gestures.

The pointerInput modifier consumes all vertical drag gestures, which prevents parent components from receiving these events. This might interfere with bottom sheet dismissal gestures.

Is this intentional to prevent accidental dismissal while scrolling? If not, consider removing this modifier as the LazyColumn already handles its own scrolling.

app/src/main/res/values-ko/strings.xml (4)

45-47: Year / month formats look correct and locale-specific
Placeholders and ordering (, ) follow Korean conventions and align with the new home_year_month_format.


59-59: Verify argument order for write_diary_month_date_day_of_week
%2$s %3$s일 %1$s expects (monthLabel, day, dayOfWeek) while the English string expects (dayOfWeek, monthLabel, day).
If the code always calls getString(id, dayOfWeek, monthLabel, day) the Korean version will render incorrectly.


73-73: LGTM – placeholder swap removes type-mismatch risk
Using two %s tokens is safe now that both inputs are already formatted strings.


77-77: Consistent with top-app-bar format
Same argument order as home_year_month_format; no issues spotted.

app/src/main/res/values/strings.xml (2)

59-59: Date string looks good; no ordinal suffix
English usually writes “July 3” or “3 July”; if you plan to add ordinal suffixes (“3rd”), this is the place. Current form is acceptable.


170-170: Escaped newline renders correctly
"\n" is used here, whereas line 68 uses \\n. Ensure both follow the same convention; double-escaped sequence will print “\n” literally.

Comment on lines +58 to +59
text = dayOfWeek.getDisplayName(TextStyle.FULL, LocalConfiguration.current.locales[0]),
style = ClodyTheme.typography.body2SemiBold,
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Good localization update with locale-aware day names.

The shift from string resources to Java time API with current locale properly supports internationalization requirements.

Same issue as in GetDayOfWeek.kt - add safe locale access:

-text = dayOfWeek.getDisplayName(TextStyle.FULL, LocalConfiguration.current.locales[0]),
+text = dayOfWeek.getDisplayName(TextStyle.FULL, LocalConfiguration.current.locales.let { if (it.isEmpty()) java.util.Locale.getDefault() else it[0] }),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
text = dayOfWeek.getDisplayName(TextStyle.FULL, LocalConfiguration.current.locales[0]),
style = ClodyTheme.typography.body2SemiBold,
text = dayOfWeek.getDisplayName(
TextStyle.FULL,
LocalConfiguration.current.locales.let {
if (it.isEmpty()) java.util.Locale.getDefault()
else it[0]
}
),
style = ClodyTheme.typography.body2SemiBold,
🤖 Prompt for AI Agents
In
app/src/main/java/com/sopt/clody/presentation/ui/home/calendar/component/DailyDiaryListItem.kt
around lines 58 to 59, the code accesses the locale directly from
LocalConfiguration.current.locales[0], which may cause issues if the locales
list is empty. To fix this, add safe access to the locale by checking if the
locales list is not empty before accessing the first element, and provide a
fallback locale if necessary to ensure robust locale handling.

Comment on lines +8 to 12
@Composable
fun getDayOfWeek(year: Int, month: Int, day: Int): String {
val date = LocalDate.of(year, month, day)
return date.dayOfWeek.getDisplayName(TextStyle.FULL, Locale.KOREAN)
return date.dayOfWeek.getDisplayName(TextStyle.FULL, LocalConfiguration.current.locales[0])
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Excellent internationalization improvement!

Converting to locale-aware day of week display aligns perfectly with the PR's internationalization goals. The use of standard Java time APIs and dynamic locale detection is the right approach.

Add safe access to the locale to prevent potential IndexOutOfBoundsException:

@Composable
fun getDayOfWeek(year: Int, month: Int, day: Int): String {
    val date = LocalDate.of(year, month, day)
-   return date.dayOfWeek.getDisplayName(TextStyle.FULL, LocalConfiguration.current.locales[0])
+   val locale = LocalConfiguration.current.locales.let { if (it.isEmpty()) java.util.Locale.getDefault() else it[0] }
+   return date.dayOfWeek.getDisplayName(TextStyle.FULL, locale)
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Composable
fun getDayOfWeek(year: Int, month: Int, day: Int): String {
val date = LocalDate.of(year, month, day)
return date.dayOfWeek.getDisplayName(TextStyle.FULL, Locale.KOREAN)
return date.dayOfWeek.getDisplayName(TextStyle.FULL, LocalConfiguration.current.locales[0])
}
@Composable
fun getDayOfWeek(year: Int, month: Int, day: Int): String {
val date = LocalDate.of(year, month, day)
val locale = LocalConfiguration.current.locales.let {
if (it.isEmpty()) java.util.Locale.getDefault() else it[0]
}
return date.dayOfWeek.getDisplayName(TextStyle.FULL, locale)
}
🤖 Prompt for AI Agents
In app/src/main/java/com/sopt/clody/presentation/utils/extension/GetDayOfWeek.kt
between lines 8 and 12, the code accesses the first locale from
LocalConfiguration.current.locales without checking if the locales list is
empty, which can cause an IndexOutOfBoundsException. Fix this by safely
accessing the locale list, for example by checking if the list is not empty
before accessing the first element or providing a default locale fallback to
ensure safe and robust locale retrieval.

Copy link
Contributor

@MoonsuKang MoonsuKang left a comment

Choose a reason for hiding this comment

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

수고하셨습니다! 든든하네요ㅠ 파일명 하나만 체크해주세요~
image

Copy link
Contributor

Choose a reason for hiding this comment

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

P3
파일명을 좀더 명확하게 했으면 좋겠어요!
ex) DateLabelExtensions?

Copy link
Contributor

Choose a reason for hiding this comment

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

타임피커는 대대적으로 개편이 필요할거 같아유.
언젠가.. 날잡고 수리한번 가겠습니다

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
app/src/main/java/com/sopt/clody/presentation/utils/extension/DateLabelExtension.kt (1)

7-9: Consider using consistent date/time libraries.

The code mixes kotlinx.datetime.Month with java.time.format.TextStyle and java.util.Locale. While this works, consider using a consistent approach - either stick with kotlinx-datetime or java.time throughout for better maintainability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dd449f1 and 81e225d.

📒 Files selected for processing (1)
  • app/src/main/java/com/sopt/clody/presentation/utils/extension/DateLabelExtension.kt (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (3)
app/src/main/java/com/sopt/clody/presentation/utils/extension/DateLabelExtension.kt (3)

11-12: LGTM!

Clean and straightforward implementation using string resources for proper localization.


20-20: toLocalizedMonthLabel inputs are always in the valid 1–12 range – exception handling is not needed

I checked every call site of Int.toLocalizedMonthLabel() across the codebase:

  • In YearMonthPicker.kt, monthItems is defined as (1..12)
  • In HomeScreen.kt, DiaryListScreen.kt, WriteDiaryScreen.kt, and ReplyDiaryScreen.kt, the month values all come from this picker or from view‐model state initialized by it

Since Month.of(this) only ever receives values 1 through 12, it cannot throw a DateTimeException. You can safely ignore adding extra exception handling here.

Likely an incorrect or invalid review comment.


17-17: Improve locale language detection.

The current check locale.language == "ko" is too restrictive and won't handle locale variants like "ko-KR" or "ko-KP".

Apply this diff to handle Korean locale variants:

-    return if (locale.language == "ko") {
+    return if (locale.language.startsWith("ko")) {

Likely an incorrect or invalid review comment.

Comment on lines +15 to +16
fun Int.toLocalizedMonthLabel(): String {
val locale = LocalContext.current.resources.configuration.locales[0]
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add input validation and improve locale detection.

The function lacks input validation for the month parameter and has potential issues with locale detection.

Apply this diff to improve robustness:

@Composable
fun Int.toLocalizedMonthLabel(): String {
+    require(this in 1..12) { "Month must be between 1 and 12, got: $this" }
-    val locale = LocalContext.current.resources.configuration.locales[0]
+    val locales = LocalContext.current.resources.configuration.locales
+    val locale = if (locales.isEmpty) Locale.getDefault() else locales[0]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fun Int.toLocalizedMonthLabel(): String {
val locale = LocalContext.current.resources.configuration.locales[0]
@Composable
fun Int.toLocalizedMonthLabel(): String {
require(this in 1..12) { "Month must be between 1 and 12, got: $this" }
val locales = LocalContext.current.resources.configuration.locales
val locale = if (locales.isEmpty) Locale.getDefault() else locales[0]
// …rest of the logic…
}
🤖 Prompt for AI Agents
In
app/src/main/java/com/sopt/clody/presentation/utils/extension/DateLabelExtension.kt
at lines 15-16, the function toLocalizedMonthLabel lacks validation for the
integer input representing the month and may incorrectly detect the locale. Add
input validation to ensure the integer is within the valid month range (1 to
12). Also, improve locale detection by safely accessing the current locale,
considering backward compatibility and potential null values, to avoid runtime
exceptions.

- 로케일을 불러오는 과정에서 안정성을 위한 디폴트값을 설정합니다.
- YearMonthPicker 레이아웃을 조정합니다.
@SYAAINN SYAAINN merged commit a78740f into develop Jul 23, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ FEAT 기능 개발 🔥 민재 민재

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 영어버전 국제화를 마무리합니다.

2 participants