Add comprehensive i18n localization for KMM and iOS
KMM (Android/Shared): - Add strings.xml with 200+ localized strings - Add translation files for es, fr, de, pt languages - Update all screens to use stringResource() for i18n - Add Accept-Language header to API client for all platforms iOS: - Add L10n.swift helper with type-safe string accessors - Add Localizable.xcstrings with translations for all 5 languages - Update all SwiftUI views to use L10n.* for localized strings - Localize Auth, Residence, Task, Contractor, Document, and Profile views Supported languages: English, Spanish, French, German, Portuguese 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -57,11 +57,11 @@ struct AllTasksView: View {
|
||||
.sheet(isPresented: $showingUpgradePrompt) {
|
||||
UpgradePromptView(triggerKey: "add_11th_task", isPresented: $showingUpgradePrompt)
|
||||
}
|
||||
.alert("Archive Task", isPresented: $showArchiveConfirmation) {
|
||||
Button("Cancel", role: .cancel) {
|
||||
.alert(L10n.Tasks.archiveTask, isPresented: $showArchiveConfirmation) {
|
||||
Button(L10n.Common.cancel, role: .cancel) {
|
||||
selectedTaskForArchive = nil
|
||||
}
|
||||
Button("Archive", role: .destructive) {
|
||||
Button(L10n.Tasks.archive, role: .destructive) {
|
||||
if let task = selectedTaskForArchive {
|
||||
taskViewModel.archiveTask(id: task.id) { _ in
|
||||
loadAllTasks()
|
||||
@@ -71,14 +71,14 @@ struct AllTasksView: View {
|
||||
}
|
||||
} message: {
|
||||
if let task = selectedTaskForArchive {
|
||||
Text("Are you sure you want to archive \"\(task.title)\"? You can unarchive it later from archived tasks.")
|
||||
Text(L10n.Tasks.archiveConfirm.replacingOccurrences(of: "this task", with: "\"\(task.title)\""))
|
||||
}
|
||||
}
|
||||
.alert("Delete Task", isPresented: $showCancelConfirmation) {
|
||||
Button("Cancel", role: .cancel) {
|
||||
.alert(L10n.Tasks.deleteTask, isPresented: $showCancelConfirmation) {
|
||||
Button(L10n.Common.cancel, role: .cancel) {
|
||||
selectedTaskForCancel = nil
|
||||
}
|
||||
Button("Archive", role: .destructive) {
|
||||
Button(L10n.Tasks.archive, role: .destructive) {
|
||||
if let task = selectedTaskForCancel {
|
||||
taskViewModel.cancelTask(id: task.id) { _ in
|
||||
loadAllTasks()
|
||||
@@ -88,7 +88,7 @@ struct AllTasksView: View {
|
||||
}
|
||||
} message: {
|
||||
if let task = selectedTaskForCancel {
|
||||
Text("Are you sure you want to archive \"\(task.title)\"? You can unarchive it later from archived tasks.")
|
||||
Text(L10n.Tasks.archiveConfirm.replacingOccurrences(of: "this task", with: "\"\(task.title)\""))
|
||||
}
|
||||
}
|
||||
.onChange(of: showAddTask) { isShowing in
|
||||
@@ -129,16 +129,16 @@ struct AllTasksView: View {
|
||||
.font(.system(size: 64))
|
||||
.foregroundStyle(Color.appPrimary.opacity(0.6))
|
||||
|
||||
Text("No tasks yet")
|
||||
Text(L10n.Tasks.noTasksYet)
|
||||
.font(.title2)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundColor(Color.appTextPrimary)
|
||||
|
||||
Text("Create your first task to get started")
|
||||
Text(L10n.Tasks.createFirst)
|
||||
.font(.body)
|
||||
.foregroundColor(Color.appTextSecondary)
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
|
||||
Button(action: {
|
||||
// Check if we should show upgrade prompt before adding
|
||||
if subscriptionCache.shouldShowUpgradePrompt(currentCount: totalTaskCount, limitKey: "tasks") {
|
||||
@@ -149,7 +149,7 @@ struct AllTasksView: View {
|
||||
}) {
|
||||
HStack(spacing: 8) {
|
||||
Image(systemName: "plus")
|
||||
Text("Add Task")
|
||||
Text(L10n.Tasks.addButton)
|
||||
.fontWeight(.semibold)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
@@ -160,13 +160,13 @@ struct AllTasksView: View {
|
||||
.padding(.horizontal, 48)
|
||||
.disabled(residenceViewModel.myResidences?.residences.isEmpty ?? true)
|
||||
.accessibilityIdentifier(AccessibilityIdentifiers.Task.addButton)
|
||||
|
||||
|
||||
if residenceViewModel.myResidences?.residences.isEmpty ?? true {
|
||||
Text("Add a property first from the Residences tab")
|
||||
Text(L10n.Tasks.addPropertyFirst)
|
||||
.font(.caption)
|
||||
.foregroundColor(Color.appError)
|
||||
}
|
||||
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
@@ -235,7 +235,7 @@ struct AllTasksView: View {
|
||||
}
|
||||
.scrollContentBackground(.hidden)
|
||||
.background(Color.appBackgroundPrimary)
|
||||
.navigationTitle("All Tasks")
|
||||
.navigationTitle(L10n.Tasks.allTasks)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
|
||||
Reference in New Issue
Block a user