i18n: complete app-wide localization (10 languages) + audit tooling
Android UI Tests / ui-tests (push) Has been cancelled
Android UI Tests / ui-tests (push) Has been cancelled
Localize all user-facing strings across iOS (SwiftUI), shared Kotlin, and Android Compose into en/es/fr/de/pt/it/ja/ko/nl/zh: - iOS String Catalogs: main + widget Localizable.xcstrings, InfoPlist.xcstrings (permissions), plural variations, ~200 new keys translated - Shared Kotlin ClientStrings table + Android composeResources/values-* (884 keys ×10), routed Api/ViewModel/util error & UI strings through localization - Backend-localized lookups/suggestions consumed via display names - Widget extension catalog; theme names, home-profile fallbacks, validation, network errors, accessibility labels all localized Add re-runnable verification gates: - scripts/i18n_audit.py — enumerate every literal, partition to GAP=0 - scripts/i18n_coverage.py — all 10 locales translated, format-specifier parity Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -248,6 +248,18 @@ object DataManager : IDataManager {
|
||||
private val _contractorSpecialtiesMap = MutableStateFlow<Map<Int, ContractorSpecialty>>(emptyMap())
|
||||
val contractorSpecialtiesMap: StateFlow<Map<Int, ContractorSpecialty>> = _contractorSpecialtiesMap.asStateFlow()
|
||||
|
||||
// Home-profile field options (heating_type -> [options], etc.), served
|
||||
// localized by the backend. Replaces the previously hardcoded client lists.
|
||||
private val _homeProfileOptions = MutableStateFlow<Map<String, List<HomeProfileOption>>>(emptyMap())
|
||||
val homeProfileOptions: StateFlow<Map<String, List<HomeProfileOption>>> = _homeProfileOptions.asStateFlow()
|
||||
|
||||
// Document type / category options ({value, display_name}), served localized.
|
||||
private val _documentTypes = MutableStateFlow<List<HomeProfileOption>>(emptyList())
|
||||
val documentTypes: StateFlow<List<HomeProfileOption>> = _documentTypes.asStateFlow()
|
||||
|
||||
private val _documentCategories = MutableStateFlow<List<HomeProfileOption>>(emptyList())
|
||||
val documentCategories: StateFlow<List<HomeProfileOption>> = _documentCategories.asStateFlow()
|
||||
|
||||
// ==================== STATE METADATA ====================
|
||||
|
||||
private val _isInitialized = MutableStateFlow(false)
|
||||
@@ -824,6 +836,15 @@ object DataManager : IDataManager {
|
||||
setTaskCategories(seededData.taskCategories)
|
||||
setContractorSpecialties(seededData.contractorSpecialties)
|
||||
setTaskTemplatesGrouped(seededData.taskTemplates)
|
||||
if (seededData.homeProfileOptions.isNotEmpty()) {
|
||||
_homeProfileOptions.value = seededData.homeProfileOptions
|
||||
}
|
||||
if (seededData.documentTypes.isNotEmpty()) {
|
||||
_documentTypes.value = seededData.documentTypes
|
||||
}
|
||||
if (seededData.documentCategories.isNotEmpty()) {
|
||||
_documentCategories.value = seededData.documentCategories
|
||||
}
|
||||
setSeededDataETag(etag)
|
||||
_lookupsInitialized.value = true
|
||||
// Persist lookups to disk for faster startup
|
||||
@@ -890,6 +911,9 @@ object DataManager : IDataManager {
|
||||
_taskCategoriesMap.value = emptyMap()
|
||||
_contractorSpecialties.value = emptyList()
|
||||
_contractorSpecialtiesMap.value = emptyMap()
|
||||
_homeProfileOptions.value = emptyMap()
|
||||
_documentTypes.value = emptyList()
|
||||
_documentCategories.value = emptyList()
|
||||
_taskTemplates.value = emptyList()
|
||||
_taskTemplatesGrouped.value = null
|
||||
_lookupsInitialized.value = false
|
||||
|
||||
Reference in New Issue
Block a user