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:
@@ -51,7 +51,7 @@ struct CompleteTaskView: View {
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Task Details")
|
||||
Text(L10n.Tasks.taskDetails)
|
||||
}
|
||||
.listRowBackground(Color.appBackgroundSecondary)
|
||||
|
||||
@@ -61,7 +61,7 @@ struct CompleteTaskView: View {
|
||||
showContractorPicker = true
|
||||
}) {
|
||||
HStack {
|
||||
Label("Select Contractor", systemImage: "wrench.and.screwdriver")
|
||||
Label(L10n.Tasks.selectContractor, systemImage: "wrench.and.screwdriver")
|
||||
.foregroundStyle(.primary)
|
||||
|
||||
Spacer()
|
||||
@@ -77,7 +77,7 @@ struct CompleteTaskView: View {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Text("None")
|
||||
Text(L10n.Tasks.none)
|
||||
.foregroundStyle(.tertiary)
|
||||
}
|
||||
|
||||
@@ -87,20 +87,20 @@ struct CompleteTaskView: View {
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Contractor (Optional)")
|
||||
Text(L10n.Tasks.contractorOptional)
|
||||
} footer: {
|
||||
Text("Select a contractor if they completed this work, or leave blank for manual entry.")
|
||||
Text(L10n.Tasks.contractorHelper)
|
||||
}
|
||||
.listRowBackground(Color.appBackgroundSecondary)
|
||||
|
||||
// Completion Details Section
|
||||
Section {
|
||||
LabeledContent {
|
||||
TextField("Your name", text: $completedByName)
|
||||
TextField(L10n.Tasks.yourName, text: $completedByName)
|
||||
.multilineTextAlignment(.trailing)
|
||||
.disabled(selectedContractor != nil)
|
||||
} label: {
|
||||
Label("Completed By", systemImage: "person")
|
||||
Label(L10n.Tasks.completedBy, systemImage: "person")
|
||||
}
|
||||
|
||||
LabeledContent {
|
||||
@@ -113,19 +113,19 @@ struct CompleteTaskView: View {
|
||||
}
|
||||
.padding(.leading, 12)
|
||||
} label: {
|
||||
Label("Actual Cost", systemImage: "dollarsign.circle")
|
||||
Label(L10n.Tasks.actualCost, systemImage: "dollarsign.circle")
|
||||
}
|
||||
} header: {
|
||||
Text("Optional Information")
|
||||
Text(L10n.Tasks.optionalInfo)
|
||||
} footer: {
|
||||
Text("Add any additional details about completing this task.")
|
||||
Text(L10n.Tasks.optionalDetails)
|
||||
}
|
||||
.listRowBackground(Color.appBackgroundSecondary)
|
||||
|
||||
// Notes Section
|
||||
Section {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Label("Notes", systemImage: "note.text")
|
||||
Label(L10n.Tasks.notes, systemImage: "note.text")
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.secondary)
|
||||
|
||||
@@ -134,7 +134,7 @@ struct CompleteTaskView: View {
|
||||
.scrollContentBackground(.hidden)
|
||||
}
|
||||
} footer: {
|
||||
Text("Optional notes about the work completed.")
|
||||
Text(L10n.Tasks.optionalNotes)
|
||||
}
|
||||
.listRowBackground(Color.appBackgroundSecondary)
|
||||
|
||||
@@ -142,7 +142,7 @@ struct CompleteTaskView: View {
|
||||
Section {
|
||||
VStack(spacing: 12) {
|
||||
HStack {
|
||||
Label("Quality Rating", systemImage: "star")
|
||||
Label(L10n.Tasks.qualityRating, systemImage: "star")
|
||||
.font(.subheadline)
|
||||
|
||||
Spacer()
|
||||
@@ -168,7 +168,7 @@ struct CompleteTaskView: View {
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
} footer: {
|
||||
Text("Rate the quality of work from 1 to 5 stars.")
|
||||
Text(L10n.Tasks.rateQuality)
|
||||
}
|
||||
.listRowBackground(Color.appBackgroundSecondary)
|
||||
|
||||
@@ -179,7 +179,7 @@ struct CompleteTaskView: View {
|
||||
Button(action: {
|
||||
showCamera = true
|
||||
}) {
|
||||
Label("Take Photo", systemImage: "camera")
|
||||
Label(L10n.Tasks.takePhoto, systemImage: "camera")
|
||||
.frame(maxWidth: .infinity)
|
||||
.foregroundStyle(Color.appPrimary)
|
||||
}
|
||||
@@ -191,7 +191,7 @@ struct CompleteTaskView: View {
|
||||
matching: .images,
|
||||
photoLibrary: .shared()
|
||||
) {
|
||||
Label("Library", systemImage: "photo.on.rectangle.angled")
|
||||
Label(L10n.Tasks.library, systemImage: "photo.on.rectangle.angled")
|
||||
.frame(maxWidth: .infinity)
|
||||
.foregroundStyle(Color.appPrimary)
|
||||
}
|
||||
@@ -230,9 +230,9 @@ struct CompleteTaskView: View {
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Photos (\(selectedImages.count)/5)")
|
||||
Text("\(L10n.Tasks.photos) (\(selectedImages.count)/5)")
|
||||
} footer: {
|
||||
Text("Add up to 5 photos documenting the completed work.")
|
||||
Text(L10n.Tasks.addPhotos)
|
||||
}
|
||||
.listRowBackground(Color.appBackgroundSecondary)
|
||||
|
||||
@@ -244,7 +244,7 @@ struct CompleteTaskView: View {
|
||||
ProgressView()
|
||||
.tint(.white)
|
||||
} else {
|
||||
Label("Complete Task", systemImage: "checkmark.circle.fill")
|
||||
Label(L10n.Tasks.completeTask, systemImage: "checkmark.circle.fill")
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
@@ -258,17 +258,17 @@ struct CompleteTaskView: View {
|
||||
.listStyle(.plain)
|
||||
.scrollContentBackground(.hidden)
|
||||
.background(Color.appBackgroundPrimary)
|
||||
.navigationTitle("Complete Task")
|
||||
.navigationTitle(L10n.Tasks.completeTask)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button("Cancel") {
|
||||
Button(L10n.Common.cancel) {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
.alert("Error", isPresented: $showError) {
|
||||
Button("OK", role: .cancel) {}
|
||||
.alert(L10n.Tasks.error, isPresented: $showError) {
|
||||
Button(L10n.Common.ok, role: .cancel) {}
|
||||
} message: {
|
||||
Text(errorMessage)
|
||||
}
|
||||
@@ -386,9 +386,9 @@ struct ContractorPickerView: View {
|
||||
}) {
|
||||
HStack {
|
||||
VStack(alignment: .leading) {
|
||||
Text("None (Manual Entry)")
|
||||
Text(L10n.Tasks.noneManual)
|
||||
.foregroundStyle(.primary)
|
||||
Text("Enter name manually")
|
||||
Text(L10n.Tasks.enterManually)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
@@ -450,11 +450,11 @@ struct ContractorPickerView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("Select Contractor")
|
||||
.navigationTitle(L10n.Tasks.selectContractor)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button("Cancel") {
|
||||
Button(L10n.Common.cancel) {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user