Skip to content

Over the air translation update#27

Open
ImaginativeShohag wants to merge 51 commits into
devfrom
over-the-air-translation-update
Open

Over the air translation update#27
ImaginativeShohag wants to merge 51 commits into
devfrom
over-the-air-translation-update

Conversation

@ImaginativeShohag
Copy link
Copy Markdown
Owner

No description provided.

Add comprehensive runtime localization implementation plan:
- Create LocalizeKit module structure with blank files
- Design String extension API with .localize(default:comment:)
- Implement dictionary-based plurals with 6 CLDR categories
- Add Vue-i18n style custom plural rules support
- Design single interactive CLI tool for translation management
- Add module-based JSON organization from Targets/ folder
- Include complete workflows for extract, merge, and validate

Changes:
- Add Docs/RuntimeLocalizationPlan.md with complete specification
- Create LocalizeKit module in Project.swift
- Add blank files for LocalizeKit module structure
- Rename SuperProgress and SuperToast screen folders
- Add Store module localization resources
- Update AGENTS.md with localization architecture notes
- Remove MainScreen.swift from Store module
Implement Phase 1 & 3 of runtime localization system:

Core Components:
- Add PluralCategory enum with CLDR-compliant plural rules for 30+ languages
- Add custom plural rules support (Vue-i18n style)
- Implement LocalizationManager with observable language changes
- Create TranslationStorage for FileManager-based caching
- Define TranslationModels for JSON structure with module organization

String Extension API:
- Add .localize(default:comment:) for simple translations
- Add .localize(default:comment:with:) for string interpolation
- Add .localize(defaultPlural:comment:count:) for plural forms
- Support all 6 CLDR plural categories (zero, one, two, few, many, other)
- All methods use @mainactor for Swift 6 concurrency compliance

View Modifier:
- Add .onLanguageChange() view modifier for automatic UI refresh

App Configuration:
- Configure custom plural rules at app startup for en, bn, ar, ru
- Initialize LocalizationManager in WhyNotSwiftUIApp

Features:
- Fallback chain: Server translations → Cached translations → Default English text
- Observable pattern for language change notifications
- Type-safe dictionary-based plural API
- Comprehensive documentation with usage examples

Build Status: ✅ Verified successful build
Add LocalizationAPI and integrate with LocalizationManager:

LocalizationAPI:
- Add LocalizationAPI enum with two endpoints:
  - availableLanguages: Fetch list of available languages
  - translationFile(languageCode): Fetch translations for specific language
- Implement comprehensive stub data for en, bn, ar languages
- Include proper stub configuration with StubResponseType.success
- Add realistic 1-second delay for development testing

DataSource Integration:
- Add Localization backend to DataSource enum
- Configure with NetworkSession for proper session management
- Enable stubbing for development (can be disabled for production)

LocalizationManager Updates:
- Implement loadAvailableLanguages() - Fetches and populates availableLanguages array
- Implement fetchTranslations(for:) - Fetches, caches, and activates translations
- Update changeLanguage(to:) - Now fetches from server if not cached
- Add NetworkKit dependency import

Features:
- Full stub data with module-based organization (Store module samples)
- Support for simple, plural, and interpolation translation types
- Automatic caching after successful fetch
- Version tracking in Preferences
- Proper error handling with SuperLog

Stub Data Includes:
- English: store_welcome, store_items_count, store_greeting
- Bengali: Full Bengali translations with proper Unicode
- Arabic: Full Arabic translations with all 6 plural forms

Build Status: ✅ Verified successful build
Create comprehensive language settings interface for Store module:

LanguageSettingsScreen:
- Full-screen language selection interface with NavigationStack
- List view showing available languages from LocalizationManager
- Display native name (e.g., "বাংলা") and English name
- Visual checkmark indicator for currently selected language
- Loading state with ProgressView
- Error state with retry button
- Overlay loading indicator when changing language
- Footer text explaining language selection
- Done button to dismiss

LanguageSettingsViewModel:
- Observable @mainactor view model with three states: loading, data, error
- Integration with LocalizationManager for language operations
- loadLanguages() - Fetches available languages from server
- changeLanguage(to:) - Switches app language with loading state
- isSelected() - Helper to determine current language
- Preview initializer for SwiftUI previews
- Proper error handling and logging

ProfileSheet Integration:
- Add "Language Settings" button in Profile sheet
- Sheet presentation for LanguageSettingsScreen
- Placed between Orders and Sign Out sections
- State management for sheet presentation

Project Configuration:
- Add LocalizeKit dependency to Store module in Project.swift
- Enables access to LocalizationManager and Language models

Features:
- Real-time language switching
- Asynchronous operations with proper loading states
- Clean, native iOS design following HIG
- Comprehensive SwiftUI previews for all states
- Type-safe observable pattern
- Proper dismiss handling

Build Status: ✅ Verified successful build
Demonstrate runtime localization system in action:

HomeScreen Localization:
- Add LocalizeKit import
- Localize welcome message with proper format specifier:
  - "Welcome, **%@**\!" using %@ placeholder for user's full name
  - Correct usage: .localize(default: "Welcome, **%@**\!", with: userName)
- Add .onLanguageChange() modifier for automatic UI refresh

ProfileSheet Localization:
- Add LocalizeKit import
- Localize all user-facing strings:
  - "Retry" button
  - "Profile" navigation title
  - "Done" button
  - Section headers: "Details"
  - Labels: "Name", "Username", "Email", "Phone", "Address"
  - Buttons: "Orders", "Language Settings", "Sign Out"
  - Alert: "Sign out from Store?" with "Sign Out" confirmation
- Add .onLanguageChange() modifier for automatic UI refresh

Localized String Keys (13 total):
- store_welcome - Welcome message with %@ interpolation
- store_retry - Retry button
- store_profile - Profile title
- store_done - Done button
- store_details - Section header
- store_name, store_username, store_email, store_phone, store_address - Labels
- store_orders - Orders button
- store_language_settings - Language settings button
- store_sign_out - Sign out button
- store_sign_out_alert_title - Alert title

Features:
- Proper format specifier usage (%@ for string interpolation)
- Full .localize() API demonstration
- Simple string localization
- Automatic UI refresh with .onLanguageChange()
- All strings have English defaults and translator comments
- Type-safe localization with compiler checks
- Translators can reorder words in different languages

Build Status: ✅ Verified successful build
Complete implementation of the LocalizeKit CLI tool for managing translations
in the runtime localization system.

## CLI Tool Features

### Commands Implemented
- **extract**: Extract localization strings from Swift files using SwiftSyntax
- **merge**: Merge new extracted strings with existing translations
- **validate**: Validate translation files for completeness and correctness
- **diff**: Generate diff between translation versions (JSON/Markdown)
- **menu**: Interactive menu system for easy access

### Core Functionality
- SwiftSyntax-based AST parsing for string extraction
- Module-based organization matching Targets/ structure
- Smart merge with status tracking (new, modified, unchanged, removed)
- Comprehensive validation:
  - Missing translations
  - Format specifier matching
  - CLDR plural forms validation
  - Completeness checking
- Diff generation for translator workflow

### Translation Files
- Created English (en.json) - 14 strings
- Created Bengali (bn.json) - 14 strings
- Created Arabic (ar.json) - 14 strings
- All with proper metadata and validation status

### Documentation
- Comprehensive CLI tool README
- Quick start guide for developers
- Implementation summary document
- Updated AGENTS.md with localization workflow

### NetworkKit Updates
- Updated stub data with actual Store module translations
- All 14 strings from HomeScreen and ProfileSheet
- Proper format specifiers and translator comments

## Technical Details

**Dependencies:**
- SwiftSyntax 509.0.0 for AST parsing
- ArgumentParser 1.2.0 for CLI

**Statistics:**
- 17 Swift files (~1,500 lines)
- 3 translation JSON files
- 3 documentation files
- 4 commands + interactive menu

**Build Status:** ✅ All builds passing

The complete runtime localization system is now production-ready with
comprehensive tooling for translation management.
Fixed two critical issues with the runtime localization system:

## Issue 1: Language Changes Not Reflecting in UI

**Problem:** When users changed language in settings, translations were
loaded but UI didn't update to show the new text.

**Root Cause:** LocalizationManager wasn't using Swift's @observable macro,
preventing SwiftUI from automatically tracking state changes.

**Fix:**
- Migrated LocalizationManager from ObservableObject to @observable
- Updated LocalizationObserver to use @State instead of @ObservedObject
- Removed Combine dependency (not needed with @observable)

**Result:** Language changes now instantly update the entire UI without
requiring app restart.

## Issue 2: Markdown Not Rendering in Localized Text

**Problem:** Markdown formatting (e.g., **bold**) in localized strings
wasn't rendering - literal asterisks were shown instead.

**Root Cause:** .localize() returns plain String, which Text treats as
literal text without markdown parsing.

**Fix:** Created Text+Localization extension with static methods that
return Text views with markdown support using AttributedString.

**Usage:**
- Before: Text("key".localize(default: "**Bold**", ...))
- After: Text.localized("key", default: "**Bold**", ...)

**Result:** Markdown now renders correctly - bold, italic, strikethrough,
links, and other SwiftUI-supported markdown work as expected.

## Changes

### LocalizationManager.swift
- Migrated from ObservableObject to @observable macro
- Removed @published wrappers (automatic with @observable)
- Removed Combine import (not needed)
- All properties automatically observable by SwiftUI

### LocalizationObserver.swift
- Changed from @ObservedObject to @State
- Works seamlessly with @observable types

### Text+Localization.swift (NEW)
- Added Text extension with 3 localized() static methods
- Supports simple, single interpolation, and multiple interpolation
- Parses markdown using AttributedString with fallback to plain text
- Safe error handling - invalid markdown falls back gracefully

### HomeScreen.swift
- Updated welcome message to use Text.localized()
- User name now displays in bold as intended

## Technical Details

- @observable macro provides automatic property observation
- .onLanguageChange() modifier observes LocalizationManager.shared
- AttributedString(markdown:) parses markdown safely with try/catch
- Minimal performance impact - parsing cached by SwiftUI
- Build Status: ✅ All tests passing

The runtime localization system now uses modern Swift observation and
provides seamless language switching with proper markdown formatting.
Applied LocalizeKit runtime localization system to all screens in the Store module:
- SplashScreen: Welcome text and app name
- LoginScreen: Form labels, placeholders, and button text
- MainScreen: Tab bar labels (Home, Categories, Bag)
- HomeScreen: Welcome message with user name
- CartScreen: Empty state, total label, checkout button, navigation
- ProductDetailsScreen: Navigation title
- ProductsScreen: Category title, error retry button
- CategoriesScreen: Navigation title, error retry button
- PlaceOrderScreen: Form labels, placeholders, buttons, success alert
- OrdersScreen: Navigation title
- LanguageSettingsScreen: All UI elements including loading, title, buttons
- ErrorView: Retry button text

All screens now include:
- Proper default English fallback text
- Helpful translator comments for context
- .onLanguageChange() modifier for reactive UI updates
- Consistent store_ prefix for translation keys

Fixed type-checking timeout in PlaceOrderScreen by extracting content into separate computed property.
Updated stub data in LocalizationAPI.swift to include all 37 translation keys for the Store module in English, Bengali, and Arabic:

New keys added:
- Splash screen: welcome_to, app_name
- Login screen: login, username, password
- Main screen: tab_home, tab_categories, tab_bag
- Cart screen: cart_empty_title, cart_empty_description, cart_total, cart_checkout, cart_title, cart_menu_orders
- Product screens: product_details_title, products_category_title, categories_title
- Checkout: checkout_completed_title, checkout_completed_description, checkout_title, checkout_shipping_address, checkout_name_placeholder, checkout_phone_placeholder, checkout_address_placeholder, checkout_total, checkout_placing_order, checkout_place_order, checkout_success_title
- Orders: orders_title
- Language settings: language_loading, language_title, language_changing, language_select_header, language_select_footer
- Common: ok, retry

All translations now include:
- English values matching default fallback text
- Bengali (বাংলা) translations
- Arabic (العربية) translations with RTL-appropriate text
- Proper interpolation support for dynamic content (%@)
LocalizeKit CLI Improvements:
- Add support for Text.localized() static method pattern detection
- Fix string extraction to handle both localization patterns
- Update StringExtractor to detect Text.localized("key", ...) calls
- Fix MenuCommand initialization issues with ArgumentParser
- Add DiffSummary mutability for proper diff generation
- Configure Package.swift with parse-as-library flag

Documentation:
- Update README with comprehensive installation instructions
- Document both String.localize() and Text.localized() patterns
- Add detailed troubleshooting section with common issues
- Include build instructions with --disable-sandbox flag

Translation Updates:
- Complete Arabic translation with all 48 Store module strings
- Add 34 missing Arabic translations for UI elements
- Update Bengali and English translation files with proper metadata
- Ensure all format specifiers preserved in translations

Testing:
- Verified CLI extracts all 48 Store module strings correctly
- Confirmed both localization patterns detected successfully
- Validated Arabic translations for RTL compatibility
Major upgrade to LocalizeKit translation management tool:

- Auto-managed integer versioning (no manual version specification)
- Per-key version tracking for granular change detection
- Simplified workflow with base.json + target language files
- New migrate command to convert v1 files to v2 format
- Enhanced diff command with terminal preview
- Improved merge logic with version-based synchronization
- Multi-language batch operations with --all flag
- Comprehensive test suite with 16 automated tests

This significantly streamlines the translation workflow and provides
better tracking of translation changes across app updates.
Changes made:
- Changed CLI version from 2.0.0 to 1.0.0
- Removed MigrateCommand.swift and migration functionality
- Updated README.md to remove all migration references
- Updated AGENTS.md to reflect version 1.0.0 without migration
- Removed migration workflow examples and troubleshooting sections

LocalizeKit retains all core features: extract, merge, validate, and diff
commands with auto-versioning and per-key change tracking.
Major refactoring to support unit testing:

- Restructured LocalizeKit into library and executable targets
- Created LocalizeKitCore library with all core logic
- Made all types, classes, and methods public for testability
- Added LocalizeKitTests target with XCTest framework
- Moved Core and Models from LocalizeKit to LocalizeKitCore
- Removed duplicate code directories

Implemented 12 comprehensive unit tests covering:
- Translation model encoding/decoding
- Base and target file structures
- JSON serialization/deserialization
- Format specifier preservation
- Plural forms (all CLDR categories)
- Performance benchmarks

Updated documentation:
- README.md with Swift test instructions
- TESTING.md rewritten for XCTest approach

All tests passing: 12/12 ✅

Benefits over bash script:
- Type safety and compile-time checking
- IDE integration with Xcode/VS Code
- Better debugging capabilities
- CI/CD friendly with standard reporting
- Easier to maintain and extend
…d CLI test script

This commit refactors the LocalizeKit test suite by:
- Removing TESTING.md documentation in favor of inline Swift tests
- Replacing test_localizekit.sh with test_cli.sh for better CLI testing
- Adding LocalizeKitIntegrationTests.swift with comprehensive integration tests covering the full workflow: extract → merge → validate → diff
Update TranslationFile model to use Int for version field instead of String,
matching the JSON structure in Translations/en.json. Also update stub data
in LocalizationAPI and Preferences property to maintain consistency.
Translators now receive context comments in target language files
(ar.json, bn.json) directly from base.json, eliminating the need
to reference base.json separately during translation work.
Target translation files now include comments for translator
context while keeping simplified structure without version metadata.
- Create TranslationRepository in Store module to handle all network calls
- Remove NetworkKit dependency from LocalizeKit module
- Add setter methods to LocalizationManager (setAvailableLanguages, setTranslations)
- Refactor changeLanguage() to cache-only operation
- Update LanguageSettingsViewModel to use repository pattern
- LocalizeKit is now a pure localization engine with no network coupling
…odules

LocalizeKit now has zero external dependencies, making it a truly portable and reusable module.

Changes:
- Created LocalizeKitStorage: minimal UserDefaults accessor for language preferences (backward compatible)
- Created LocalizeKitLogger: DEBUG-only logging utility using OSLog (zero overhead in Release builds)
- Updated LocalizationManager to use new internal utilities instead of Core.Preferences and SuperLog
- Removed Core and SuperLog dependencies from Project.swift module configuration
- Added comprehensive unit tests for LocalizeKitStorage (9 tests, all passing)
- Updated AGENTS.md to reflect module independence and portability
- Fixed Swift 6 concurrency warning with @unchecked Sendable conformance

Benefits:
- Zero dependencies on other project modules
- Backward compatible with existing user data (same UserDefaults keys)
- No breaking changes to public API
- Can be copied to any Swift/iOS project or extracted as standalone Swift Package
- Production builds have zero logging overhead
Users must now click the Apply/Done button to apply language selection instead of auto-applying on tap.

Changes:
- Added pendingLanguage state to track selected but not yet applied language
- Language row buttons now call selectLanguage() instead of directly changing language
- Done button becomes "Apply" button when there's a pending change
- Apply button triggers language change before dismissing the sheet
- Checkmark shows for pending selection, giving immediate visual feedback
- Apply button has semibold font weight to draw attention
- Apply/Done button disabled during language change to prevent multiple taps
- Separated ternary operators into if/else for proper LocalizeKit extraction

User Experience:
- Tap a language → Shows checkmark immediately (pending state)
- Tap Apply → Applies the change and dismisses sheet
- Tap Done (when no changes) → Dismisses sheet without changes
- No accidental language changes from exploratory taps
- Rename LanguageSettingsScreen to LanguageSettingsSheet for consistency
- Move Apply button to toolbar with confirmationAction placement
- Convert Done button to cancellationAction with .close role
- Remove unused status and fallback fields from Language model
- Simplify language row UI by removing status/fallback badges
- Remove generatedAt and language fields from target translation files
- Update LocalizeKit CLI merge command to generate cleaner JSON output
- Add toolbar button conventions to AGENTS.md documentation

The changes improve UI consistency with iOS HIG and reduce unnecessary
data in translation files, making the system simpler and more maintainable.
… selection sheets

Implement intelligent caching system that:
- Stores translations permanently in Application Support directory
- Tracks versions per language (bn_BD: v12, ar_AE: v2, etc.)
- Uses cache-first strategy with version comparison
- Only fetches from API when cache is missing, stale, or corrupted
- Provides instant language switching for cached translations
- Skips API calls for en_US (uses code defaults)

Caching changes:
- Move cache from Library/Caches to Library/Application Support/LocalizeKit/Translations
- Add CacheState enum (valid, stale, missing, corrupted)
- Add checkCacheState() method in TranslationStorage
- Update LocalizationManager with getCacheState() and activateLanguage()
- Update LanguageSettingsViewModel with version-checking flow + en_US optimization
- Remove obsolete global translationVersion from LocalizeKitStorage
- Remove obsolete tests for translationVersion

UI separation:
- Extract LanguageListSheet from LanguageSettingsSheet
- LanguageSettingsSheet now only handles country selection
- LanguageListSheet handles language selection for a country
- Both sheets share the same ViewModel for single source of truth
- Improved code organization and maintainability

Benefits:
- Performance: Instant language switching for cached languages
- Reliability: Permanent storage survives iOS cleanup
- Accuracy: Per-language version tracking prevents stale data
- Network optimization: Only fetch when needed (version mismatch)
- Better separation of concerns in UI layer

Architecture:
1. User selects language (e.g., bn_BD with server version 12)
2. Special case: en_US uses empty file (defaults from code)
3. Check if cache exists and load its embedded version field
4. Compare cached version with server version
5. If match → use cache instantly (no API call)
6. If mismatch/missing/corrupted → fetch from API, cache, activate
…a fields

Target language files (bn.json, ar.json, en.json) now use a cleaner structure
with only version and modules fields. The generatedAt and language fields were
removed as they are only needed in base.json for source tracking.

This simplification makes target files easier to work with and reduces file size
while maintaining all necessary translation data. The LocalizeKit CLI merge
command automatically generates files in the correct format.

Updated documentation to clarify the distinction between base file format
(with full metadata) and target file format (simplified structure).
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @ImaginativeShohag, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a robust and flexible runtime localization system, LocalizeKit, designed to manage translations dynamically and efficiently. It provides a complete solution for over-the-air updates, a powerful CLI tool for developers and translators, and seamless integration into the application's UI. The initial rollout focuses on the Store module, establishing a scalable pattern for future internationalization efforts across the project.

Highlights

  • Comprehensive Runtime Localization System: Introduced a new LocalizeKit module enabling over-the-air translation updates, local caching, and dynamic language switching without app restarts. This system supports CLDR-compliant pluralization rules and string interpolation.
  • Dedicated Translation Management CLI Tool: A powerful command-line interface (Tools/LocalizeKit) has been added to streamline the translation workflow. It provides commands to extract strings from code, merge translations, validate files for correctness, and preview differences between versions.
  • Store Module Localization: The Store module has been fully integrated with the new LocalizeKit system. All user-facing strings now utilize the .localize() string extension and Text.localized() static methods, ensuring dynamic content updates upon language changes.
  • Language Selection User Interface: A new language settings UI has been implemented within the Store module, allowing users to easily select their preferred language. The UI provides a smooth experience for changing languages and persists selections across app launches.
  • Extensive Documentation: Detailed documentation has been added, including an implementation plan, quick start guides, usage instructions, and a comprehensive summary of the runtime localization system, ensuring clarity for developers and translators.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This is an impressive and comprehensive pull request that introduces a full-featured runtime localization system, LocalizeKit, along with a powerful CLI tool for managing translations. The documentation is exceptionally thorough, which is a huge asset for the project. The architecture is well-thought-out, with a clear separation of concerns between the localization engine, the UI, and the data layer.

My review focuses on a few key areas to enhance correctness and maintainability. I've identified a critical build configuration issue, some opportunities to improve code clarity and maintainability in the new LocalizeKit module, and a couple of places where documentation and implementation could be better aligned. Overall, this is a fantastic addition to the project.

Comment thread Project.swift
}

let moduleName = String(components[0]).capitalized
let translationKey = String(components[1])
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The translationKey variable is declared but never used, which can be confusing. The lookup on line 181 correctly uses the original key. This line can be removed to improve code clarity.

}

let moduleName = String(components[0]).capitalized
let translationKey = String(components[1])
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Similar to the string(for:) function, the translationKey variable here is declared but never used. The lookup on line 217 correctly uses the original key. This line can be removed to improve code clarity.

Comment on lines +49 to +54
switch languageCode {
case "en", "de", "nl", "sv", "da", "no", "nn", "nb", "fo", "is", "it", "pt", "es", "ca", "et", "fi", "gl", "hu", "lb", "ml", "sw", "ta", "te", "ur", "zu":
// English-like: zero, one, other
if count == 0 { return .zero }
if count == 1 { return .one }
return .other
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The builtInCategory function uses a large switch statement with long case lists of language codes, which can be hard to read and maintain. Consider refactoring this by grouping language codes into Sets for cleaner and more efficient lookups.

For example:

private static let englishLikeLanguages: Set<String> = ["en", "de", "nl", /* ... */]

private static func builtInCategory(for count: Int, languageCode: String) -> PluralCategory {
    if englishLikeLanguages.contains(languageCode) {
        if count == 0 { return .zero }
        if count == 1 { return .one }
        return .other
    }
    // ... other checks
}

Comment on lines +96 to +156
private var availableLanguagesStubData: Data {
let json = """
{
"success": true,
"message": "Request processed successfully",
"data": {
"Bangladesh": [
{
"code": "bn_BD",
"name_en": "Bengali",
"name_locale": "বাংলা",
"version": 1
},
{
"code": "en_US",
"name_en": "English",
"name_locale": "English",
"version": 4
}
],
"United Arab Emirates": [
{
"code": "ar_AE",
"name_en": "Arabic (U.A.E.)",
"name_locale": "العربية",
"version": 2
},
{
"code": "en_US",
"name_en": "English",
"name_locale": "English",
"version": 4
}
],
"United States": [
{
"code": "en_US",
"name_en": "English",
"name_locale": "English",
"version": 4
}
],
"China": [
{
"code": "zh_CN",
"name_en": "Chinese (China)",
"name_locale": "中文",
"version": 1
},
{
"code": "en_US",
"name_en": "English",
"name_locale": "English",
"version": 4
}
]
}
}
"""
return json.data(using: .utf8)!
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The stub data for available languages and translations is hardcoded as very large multi-line strings. This makes the file difficult to read and maintain. Consider moving this JSON data into separate .json files within a Resources directory and loading them using Data(contentsOf:). This will keep the Swift code cleaner and make the stub data easier to manage.

Comment thread Docs/LocalizationFixes.md Outdated
Comment on lines +13 to +32
The `currentTranslations` property in `LocalizationManager` was a regular `private` property, not a `@Published` property. This meant that when translations were updated, SwiftUI's observation system wasn't triggered.

**Fix:**
Changed `currentTranslations` from a regular property to a `@Published` property:

```swift
// Before
private var currentTranslations: TranslationFile?

// After
/// Current translations - published to trigger UI updates
@Published private var currentTranslations: TranslationFile?
```

**How It Works:**
- When `currentTranslations` changes, `LocalizationManager` (which is `@ObservableObject`) publishes the change
- Views using `.onLanguageChange()` modifier observe `LocalizationManager.shared`
- The `.id(localizationManager.currentLanguage)` in the modifier forces view recreation
- All localized strings are re-evaluated with new translations
- UI updates instantly
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The explanation for 'Issue 1: Language Not Reflecting on Change' appears to be out of sync with the implementation. The documentation mentions changing currentTranslations to a @Published property and refers to @ObservableObject, which is part of the Combine framework. However, the LocalizationManager is implemented using the modern Swift Concurrency @Observable macro. The actual fix seems to be the .id(localizationManager.currentLanguage) modifier in LocalizationObserver.swift. Please update this documentation to accurately reflect the @Observable implementation to avoid confusing future developers.

…improvements

Added complete UI test coverage for the Store module with 37 tests across 4 test suites:
- StoreHomeUITests (9 tests): home screen, products, categories, profile navigation
- StoreCartUITests (9 tests): cart operations, quantity management, checkout flow
- StoreProductsUITests (10 tests): product listing, details, and error handling
- StoreLanguageUITests (9 tests): language settings and country selection

UI Test Infrastructure Enhancements:
- Added uiTestEnvKeyUserData constant for passing mock user data to tests
- Enhanced Preferences to support mock user injection in UI test environment
- Updated StoreAPI and LocalizationAPI to respect error status codes in test mode
- Integrated MockResponse system with TestUtils for reliable API mocking

Accessibility Improvements:
- Added identifiers to all interactive elements across Store module screens
- Added identifiers to tab bar items (home_tab, categories_tab, bag_tab)
- Added identifiers to buttons, menus, and navigation elements
- Added identifiers to profile details and language selection UI
- Added identifiers to cart elements and checkout button
- Added identifiers to error views and retry buttons

Project Configuration:
- Enabled UI tests for Store module in Project.swift
- Added TestUtils as UI test dependency for shared testing utilities

Documentation:
- Created comprehensive test report (StoreUITestsReport.md) with 21/37 tests passing
- Documented failing test patterns and recommended fixes
- Identified priority issues including cart calculation bug and loading indicator detection

This establishes a solid foundation for UI test coverage on the Store module, ensuring translation features, cart operations, and user flows work correctly across releases.
Added comprehensive documentation about the new UI testing infrastructure:
- Documented 37 UI tests across 4 test suites for Store module
- Added UI testing commands and examples
- Documented TestUtils module for shared UI testing utilities
- Added information about MockResponse system and API stubbing
- Documented accessibility identifiers convention
- Referenced StoreUITestsReport.md for detailed test results
- Modernize MainScreen TabView from Tab() to .tabItem {} modifier
- Change tab view style from .sidebarAdaptable to .automatic for better behavior
- Add tabBarButton(withLabel:) helper for more reliable tab selection in tests
- Update all UI tests to use label-based tab finding instead of accessibility IDs
- Skip splash screen delay in UI test mode for faster test execution
- Add accessibility identifier to retry button in ProductsScreen
  - Separate TranslationFile (from server) and CachedTranslationFile (with version)
  - Language version now comes from Language.version in available languages API
  - Add country, language name, and version tracking to LocalizeKitStorage
  - Update LocalizationManager to store and restore language metadata
  - Add robust Language.version decoding (handles Int and String)
  - Update method signatures to accept version as separate parameter
  - Expand test coverage for new storage properties
- Load and apply user's selected language during splash screen
- English uses built-in text without API call for optimal performance
- Non-English languages check cache state and fetch if needed
- Handle cache states: valid (instant), stale (re-fetch), missing (fetch), corrupted (delete + re-fetch)
- Graceful error handling - app continues with default/cached language if network fails
- Remove 'store_' prefix from localization keys for cleaner API
- Convert product count in PlaceOrderScreen to use localize plural forms
- Update LocalizationAPI stub data with simplified keys
- Remove xcstrings entry in favor of runtime localization
- Update String+Localization documentation examples
- Fix MenuCommand border formatting alignment
- Reorganize documentation from Docs/ to docs/ directory structure
- Create comprehensive LocalizeKit Runtime Usage Guide (1,336 lines)
- Create comprehensive LocalizeKit CLI Usage Guide (749 lines)
- Remove outdated LocalizeKitQuickStart.md and LocalizeKitUsage.md
- Update AGENTS.md references to new documentation structure
… plural migrations

Add dedicated Migration Guides section with comprehensive migration documentation:
- From NSLocalizedString to LocalizeKit
- From SwiftUI Native Plurals (^[text](count)) to LocalizeKit

Includes side-by-side comparisons, migration steps, and benefits of LocalizeKit.
…n API

Add 74 unit tests covering all edge cases and corner cases for the string
localization API to ensure robust handling of various scenarios including:

- Simple localization with translation presence/absence
- Single and multiple argument interpolation with format strings
- All CLDR plural categories (.zero, .one, .two, .few, .many, .other)
- Edge cases for counts (negative, very large, zero-only forms)
- Key format validation (empty keys, Unicode, multiple underscores)
- Value edge cases (empty defaults, Unicode/emoji, special characters)
- Format string mismatches (placeholder/argument count mismatches)
- Translation type mismatches (simple vs plural API usage)
- LocalizationManager state handling (cache clearing, concurrent access)
- Module boundary validation (case sensitivity, cross-module access)
- Comprehensive fallback chain testing for plural forms

All 88 tests pass (14 LocalizeKitStorageTests + 74 StringLocalizationTests)
with 100% success rate, validating the implementation's correctness and
ensuring locale-aware plural rules work as expected.
…support

Add plural localization methods to Text extension for SwiftUI:
- localized(_:defaultPlural:comment:count:) - without interpolation
- localized(_:defaultPlural:comment:count:with:) - single argument
- localized(_:defaultPlural:comment:count:with:) - multiple arguments

All methods support markdown rendering for formatted text in plurals.

Also migrate Store module from SwiftUI native ^[...] plural syntax:
- PlaceOrderScreen: Product count in checkout
- OrdersScreen: Total product count in order summary

Update documentation with pre-migration audit checklist and best practices
for choosing between Text.localized() and Text("key".localize()).
…ection

- Remove 'store_' prefix from all localization keys across UI screens
- Update translation files with new key format (base, bn, ar, en)
- Leverage LocalizeKit's automatic module detection via #fileID
- Update LocalizationAPI stub data to match new key format
- Add extractModuleName() to extract module from compile-time file path
- Update all localize() methods to accept file parameter with #fileID default
- Modify LocalizationManager to require explicit moduleName parameter
- Clean API: keys no longer need module prefix (e.g., "cart_title" vs "store_cart_title")
- Update all tests to verify module auto-detection functionality
- Improve documentation with full stops and backticks for code keywords
- Update AGENTS.md to document new module detection feature
- Add comprehensive examples in LocalizeKit runtime and CLI guides

Benefits:
- Zero runtime overhead (compile-time literal)
- Privacy-safe (no full paths exposed)
- Cleaner translation keys
- Automatic module scoping without manual prefixes
Enable automatic right-to-left layout for Arabic, Hebrew, Urdu, and Persian to ensure proper text direction and UI mirroring across SwiftUI and UIKit components. Simplify translation models by removing unnecessary metadata fields for cleaner runtime structure.
Update AGENTS.md with comprehensive RTL support documentation including automatic detection, configuration options, SwiftUI/UIKit integration, and usage examples.
Add concise RTL documentation including automatic detection, configuration example, SwiftUI/UIKit integration notes, and API reference updates.
- Add snake_case key naming convention (screen_element_description)
- Include component breakdown table with examples
- Add last updated date (January 14, 2026) to both docs
- Organize best practices with clear examples and anti-patterns
- Show errors via alert dialog instead of changing view state for better UX
- Remove unused English stub data from LocalizationAPI (code defaults are sufficient)
- Fix country selection timing in language change flow
- Convert hasPendingChanges() method to computed property for Swift idiomaticity
- Simplify country lookup in SplashViewModel using saved preferences
- Update ValidateCommand flags with clearer defaults and inversion support
- Enhance LocalizeKit documentation with snake_case naming enforcement and format specifier guidelines
- Upgrade Tuist from 4.115.1 to 4.131.0
Add comprehensive LocalizeKit migration skill with step-by-step guidance for converting NSLocalizedString, SwiftUI native plurals, and hardcoded strings. Update .gitignore to include skills directory while excluding other AI tool files. Fix missing .onLanguageChange() modifier in LanguageListSheet.
…ture

- Add Constants.swift with centralized default values for locale settings and RTL languages
- Update LocalizationManager to use Constants instead of hardcoded values
- Reorder LocalizationManager properties for better organization
- Move CacheState enum to bottom of LocalizationManager file
- Update PluralCategory to use Constants.fallbackLanguageCode
- Add Constants to internal utilities list
- Document centralized configuration approach
…ance plural support

Restructure LocalizeKit into Core/, Extensions/, Models/, Storage/, and Utils/ subdirectories for better maintainability. Add comprehensive PluralCategory with full test coverage, refactor existing tests, and tighten API surface with private(set) properties.
Copilot AI review requested due to automatic review settings March 28, 2026 02:07
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces an over-the-air (server-driven) runtime localization system for the Store module (including caching, pluralization, and UI for language selection), along with a CLI toolchain for extracting/merging/validating translation files and expanded UI-test infrastructure.

Changes:

  • Add LocalizeKit runtime localization (storage, plural rules, markdown-capable Text.localized, and view refresh via .onLanguageChange()), and integrate it into Store screens + app startup.
  • Add Tools/LocalizeKit CLI (extract/merge/validate/diff) + translation JSON files for English/Bengali/Arabic.
  • Improve UI test utilities and add Store UI tests; update project/dependency configuration (Tuist, SPM, gitignore, docs).

Reviewed changes

Copilot reviewed 78 out of 82 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
mise.toml Bump Tuist version.
Translations/en.json Add English translation JSON (Store module).
Translations/bn.json Add Bengali translation JSON (Store module).
Translations/ar.json Add Arabic translation JSON (Store module).
Tools/LocalizeKit/Tests/LocalizeKitTests/LocalizeKitCoreTests.swift Add LocalizeKitCore model encoding/decoding tests.
Tools/LocalizeKit/Sources/LocalizeKitCore/Models/TranslationModels.swift Add CLI/core translation model definitions + loader.
Tools/LocalizeKit/Sources/LocalizeKitCore/Core/TranslationValidator.swift Add CLI translation validation (missing keys, plurals, format checks).
Tools/LocalizeKit/Sources/LocalizeKitCore/Core/TranslationMerger.swift Add legacy translation merge logic.
Tools/LocalizeKit/Sources/LocalizeKitCore/Core/TranslationFileGenerator.swift Generate legacy translation JSON from extracted strings.
Tools/LocalizeKit/Sources/LocalizeKitCore/Core/StringExtractor.swift Extract localization calls from Swift sources via SwiftSyntax.
Tools/LocalizeKit/Sources/LocalizeKitCore/Core/LanguageMerger.swift Sync base.json into target language JSONs.
Tools/LocalizeKit/Sources/LocalizeKitCore/Core/DiffGenerator.swift Generate translation diffs (JSON/Markdown).
Tools/LocalizeKit/Sources/LocalizeKitCore/Core/BaseTranslationFileGenerator.swift Generate base.json with per-key metadata/versioning.
Tools/LocalizeKit/Sources/LocalizeKitCore/Core/BaseFileMerger.swift Incremental merge of extracted strings into base.json.
Tools/LocalizeKit/Sources/LocalizeKit/main.swift Add localizekit CLI entrypoint and subcommands.
Tools/LocalizeKit/Sources/LocalizeKit/Commands/MergeCommand.swift CLI command to merge/sync target language files.
Tools/LocalizeKit/Sources/LocalizeKit/Commands/MenuCommand.swift Interactive CLI menu/wizards.
Tools/LocalizeKit/Sources/LocalizeKit/Commands/ExtractCommand.swift CLI extraction flow for generating/updating base.json.
Tools/LocalizeKit/Sources/LocalizeKit/Commands/DiffCommand.swift CLI diff viewer against base.json.
Tools/LocalizeKit/Package.swift Add SwiftPM package for CLI + LocalizeKitCore.
Tools/LocalizeKit/Package.resolved Pin CLI dependencies (swift-syntax, argument-parser).
Targets/WhyNotSwiftUI/Sources/Why_Not_SwiftUIApp.swift Configure plural rules + enable runtime language updates.
Targets/WhyNotSwiftUI/Resources/Localizable.xcstrings Update a string comment.
Targets/TestUtils/Sources/Extensions/XCUIElement+.swift Add tab bar button lookup helper.
Targets/TestUtils/Sources/Extensions/XCUIApplication+.swift Add userData injection into UI test launch env.
Targets/Store/UITests/StoreHomeUITests.swift Add Store home UI test suite.
Targets/Store/Sources/UI/Splash/SplashViewModel.swift Auto-load/apply selected language at startup + skip delay in UI tests.
Targets/Store/Sources/UI/Splash/SplashScreen.swift Localize splash screen strings + observe language changes.
Targets/Store/Sources/UI/Settings/LanguageSettingsViewModel.swift Add language selection logic + cache-first fetching.
Targets/Store/Sources/UI/Settings/LanguageSettingsSheet.swift Add country selection UI for languages.
Targets/Store/Sources/UI/Settings/LanguageListSheet.swift Add language list UI + apply action + loading overlay.
Targets/Store/Sources/UI/Profile/ProfileSheet.swift Add localized labels + language settings entry + sheet.
Targets/Store/Sources/UI/Products/ProductsScreen.swift Localize retry + localized category title + observe language changes.
Targets/Store/Sources/UI/ProductDetails/ProductDetailsScreen.swift Localize navigation title + observe language changes.
Targets/Store/Sources/UI/PlaceOrder/PlaceOrderScreen.swift Localize checkout flow (placeholders, plurals, empty state, alerts).
Targets/Store/Sources/UI/Orders/OrdersScreen.swift Localize titles + pluralized product count + observe language changes.
Targets/Store/Sources/UI/Main/MainScreen.swift Localize tab labels + adjust tab view structure/style + observe language changes.
Targets/Store/Sources/UI/Login/LoginScreen.swift Localize login UI strings + observe language changes.
Targets/Store/Sources/UI/Home/HomeScreen.swift Localize welcome text + add accessibility identifiers + observe language changes.
Targets/Store/Sources/UI/Components/ErrorView.swift Localize retry text + add accessibility identifiers.
Targets/Store/Sources/UI/Categories/CategoriesScreen.swift Localize title/retry + add accessibility identifiers + observe language changes.
Targets/Store/Sources/UI/Cart/CartScreen.swift Localize empty state/title/total/checkout + add accessibility identifiers + observe language changes.
Targets/Store/Sources/Repositories/TranslationRepository.swift Add repo for fetching available languages + translations.
Targets/Store/Sources/Preferences/Preferences.swift Allow injecting mock user via UI test environment.
Targets/Store/Sources/Network/StoreAPI.swift Make UI-test stub response type fail on injected error codes.
Targets/Store/Resources/BLANK_FILE.swift Placeholder resource file.
Targets/NetworkKit/Sources/Constants/UITestConstants.swift Add env key for user data injection in UI tests.
Targets/LocalizeKit/Tests/Resources/BLANK_FILE.swift Placeholder test resource file.
Targets/LocalizeKit/Tests/LocalizeKitStorageTests.swift Add unit tests for LocalizeKit user-defaults storage.
Targets/LocalizeKit/Sources/Utils/LocalizeKitLogger.swift Add DEBUG-only OSLog-based logger.
Targets/LocalizeKit/Sources/Utils/Constants.swift Add centralized LocalizeKit constants (defaults, RTL list, suite name).
Targets/LocalizeKit/Sources/Storage/TranslationStorage.swift Add file-based translation cache + version checking.
Targets/LocalizeKit/Sources/Storage/LocalizeKitStorage.swift Add LocalizeKit preferences storage (language/country/version/direction).
Targets/LocalizeKit/Sources/Models/TranslationModels.swift Add runtime translation + available-languages models.
Targets/LocalizeKit/Sources/Models/PluralCategory.swift Add CLDR plural categories + built-in rules + custom-rule support.
Targets/LocalizeKit/Sources/Extensions/Text+Localization.swift Add Text.localized(...) helpers with markdown + plural support.
Targets/LocalizeKit/Sources/Extensions/String+Localization.swift Add "key".localize(...) helpers with module detection + plural support.
Targets/LocalizeKit/Sources/Core/LocalizationObserver.swift Add .onLanguageChange() modifier for refresh + layout direction env.
Targets/Home/Sources/UI/Screens/SuperToast/SuperToastScreen.swift Add/restore Home demo screen file (localized via xcstrings).
Targets/Home/Sources/UI/Screens/SuperProgressView/SuperProgressScreen.swift Add/restore Home demo screen file (localized via xcstrings).
README.md Add a new TODO link entry.
Project.swift Change deployment target + add UI test deps + add LocalizeKit module.
Package.swift Bump Realm Swift dependency version.
Package.resolved Update pinned SPM dependency revisions/versions.
AGENTS.md Document UI testing + localization tooling/infrastructure.
.gitignore Rework ignore rules (Pods, Tuist outputs, AI folders).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +49 to +55
// Set user data if provided
if let userData = userData {
let encoder = JSONEncoder()
if let jsonData = try? encoder.encode(userData),
let jsonString = String(data: jsonData, encoding: .utf8) {
launchEnvironment[uiTestEnvKeyUserData] = jsonString
}
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

JSONEncoder.encode(_:) can't encode an existential any Encodable directly. As written, try? encoder.encode(userData) will not compile. Consider making launchApp generic (<T: Encodable>(..., userData: T? = nil)), or accept Data/String for userData, or wrap the value in a type-erased AnyEncodable that implements Encodable.

Copilot uses AI. Check for mistakes.
Comment on lines +41 to +75
// Process each module in extracted strings
for (moduleName, extractedStrings) in extractedMap {
let existingStrings = existing.modules[moduleName] ?? [:]
var updatedStrings: [String: BaseTranslationEntry] = [:]

for (key, extractedString) in extractedStrings {
if let existingEntry = existingStrings[key] {
// EXISTING KEY - compare for changes
let updatedEntry = try await processExistingKey(
key: key,
extracted: extractedString,
existing: existingEntry,
newVersion: newVersion
)
updatedStrings[key] = updatedEntry
} else {
// NEW KEY
let newEntry = processNewKey(
extracted: extractedString,
newVersion: newVersion
)
updatedStrings[key] = newEntry
changes.new.append("\(moduleName).\(key)")
}
}

// Check for REMOVED KEYS (in existing but not in extracted)
for (key, _) in existingStrings {
if extractedStrings[key] == nil {
changes.removed.append("\(moduleName).\(key)")
}
}

updatedModules[moduleName] = updatedStrings
}
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

merge(existing:extracted:newVersion:) only iterates over modules found in the newly extracted strings (extractedMap). Any modules present in existing.modules but missing from extractedMap will be dropped from the returned BaseTranslationFile, effectively deleting entire modules from base.json. Consider iterating over the union of module names (existing ∪ extracted) and carrying forward unchanged modules/keys when nothing was extracted for them.

Copilot uses AI. Check for mistakes.
Comment on lines +139 to +167
if valueChanged {
// Value changed - always increment version
shouldIncrementVersion = true
status = .modified
changes.modified.append(key)
} else if commentChanged {
// Comment changed - ask user or ignore
if ignoreCommentChanges {
// Update comment silently without incrementing version
shouldIncrementVersion = false
status = existing.metadata?.status ?? .unchanged
} else {
// Interactive prompt
let requiresRetranslation = await promptForCommentChange(
key: key,
oldComment: existing.comment ?? "",
newComment: extractedComment ?? ""
)

if requiresRetranslation {
shouldIncrementVersion = true
status = .modified
changes.modified.append(key)
} else {
shouldIncrementVersion = false
status = existing.metadata?.status ?? .unchanged
}
changes.commentChanged.append(key)
}
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

changes.modified.append(key) and changes.commentChanged.append(key) record only the raw key, while changes.new/changes.removed include the module prefix (e.g., "Module.key"). This makes the change summary inconsistent and can be ambiguous when different modules share the same key. Consider consistently storing fully-qualified keys ("(moduleName).(key)") for all change arrays.

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +61
if currentLang == "en" || currentLang == "en_US" {
SuperLog.d("MainViewModel: Current language is English, activating with built-in text (no API call)")

// Use saved country if available, otherwise default to "United States"
let country = localizationManager.currentCountry

// Create empty translation file - localize() will use default values from code
let emptyTranslation = TranslationFile(modules: [:])
localizationManager.activateLanguage(languageCode: currentLang, languageName: "English", country: country, version: 0, translationFile: emptyTranslation)
SuperLog.d("MainViewModel: English language activated (v0, built-in)")
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

Log messages in this file are prefixed with "MainViewModel:", but the type is SplashViewModel. This makes filtering/debugging logs harder. Please update the log prefix to match the actual type name (or use a shared constant).

Copilot uses AI. Check for mistakes.
Comment on lines +106 to +116
// Special case: Default English language doesn't need API call (uses code defaults)
if languageCode == "en" || languageCode == "en_US" {
SuperLog.d("LanguageChangeViewModel: Using default English (no API call needed)")
// Create empty translation file - localize() will use default values
let emptyTranslation = TranslationFile(modules: [:])
localizationManager.activateLanguage(languageCode: languageCode, languageName: "English", country: country, version: 0, translationFile: emptyTranslation)
selectedLanguage = languageCode
selectedCountry = "United States"
isChangingLanguage = false
return
}
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

When switching to English (en/en_US), the view model forces selectedCountry = "United States" even though the user may have selected a different country in the UI (and country is already available). This can desync the UI state from the user's selection. Consider setting selectedCountry = country (or leaving it unchanged) instead of hard-coding "United States".

Copilot uses AI. Check for mistakes.
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.

2 participants