Add german translations (#1383)

* Fix title localization of user list view

* fix typo

* add translations for waypoint form

* add localization for user list group caption

* add localization for upper part of direct messages help

* revert commit

* add localization for user list group caption

* improve localization of help text

* add config localization

* improve translation of waypoint expire switch

* add localization for route management

* add map overlay localization

* change translation of map overlay localization

* add localization for route finish annotations on the maps

* add app settings localization

* add/change localization for app settings

* add user config localization

* add localization for device onboarding screens

* change notification translations

* add settings bundle localizations

* add localization for settings

* correct casings

* change translation for presettings

* replace spaces with tabs
This commit is contained in:
Manuel Spengler 2025-09-12 03:49:47 +02:00 committed by GitHub
parent 7c4d55219c
commit e5bc161444
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 813 additions and 55 deletions

File diff suppressed because it is too large Load diff

View file

@ -450,7 +450,7 @@ enum MapDataError: Error, LocalizedError {
case .unsupportedFormat:
return "Unsupported file format. Supported formats: JSON, GeoJSON, KML, KMZ, GZ, ZLIB."
case .invalidContent:
return "Invalid file content. Please check the file format."
return String(localized: "Invalid file content. Please check the file format.")
case .directoryCreationFailed:
return "Failed to create storage directory."
case .invalidDestination:

View file

@ -173,7 +173,7 @@ struct UserList: View {
}
}
.listStyle(.plain)
.navigationTitle(String.localizedStringWithFormat("Contacts (%@)", String(users.count)))
.navigationTitle(String.localizedStringWithFormat("Contacts (%@)".localized, String(users.count)))
.sheet(isPresented: $editingFilters) {
NodeListFilter(filterTitle: "Contact Filters", filters: filters)

View file

@ -172,7 +172,7 @@ struct MeshMapContent: MapContent {
let routeCoords = locations.compactMap {(loc) -> CLLocationCoordinate2D in
return loc.locationCoordinate ?? LocationsHandler.DefaultLocation
}
Annotation("Start", coordinate: routeCoords.first ?? LocationsHandler.DefaultLocation) {
Annotation(String(localized: "Start"), coordinate: routeCoords.first ?? LocationsHandler.DefaultLocation) {
ZStack {
Circle()
.fill(Color(.green))
@ -181,7 +181,7 @@ struct MeshMapContent: MapContent {
}
}
.annotationTitles(.automatic)
Annotation("Finish", coordinate: routeCoords.last ?? LocationsHandler.DefaultLocation) {
Annotation(String(localized: "Finish ", comment: "Space at the end has been added to not interfere with translations for 'Finish' in RouteRecorder"), coordinate: routeCoords.last ?? LocationsHandler.DefaultLocation) {
ZStack {
Circle()
.fill(Color(.black))

View file

@ -120,8 +120,7 @@ struct MapDataFiles: View {
await MainActor.run {
isProcessing = false
processingProgress = 1.0
successMessage = "Successfully uploaded '\(metadata.originalName)' with \(metadata.overlayCount) overlays".localized
successMessage = String(localized: "Successfully uploaded '\(metadata.originalName)' with \(metadata.overlayCount) overlays")
showSuccess = true
}
} catch {
@ -198,8 +197,7 @@ struct MapDataFileRow: View {
.padding(.vertical, 2)
.background(Color.secondary.opacity(0.2))
.cornerRadius(4)
Text("\(file.overlayCount) \(file.overlayCount > 1 ? "features".localized : "feature".localized)")
Text("\(file.overlayCount) features")
.font(.caption2)
.foregroundColor(.secondary)
Spacer()

View file

@ -161,7 +161,7 @@ struct MapSettingsForm: View {
Text(file.originalName)
.font(.subheadline)
HStack {
Text("\(file.overlayCount) \(file.overlayCount > 1 ? "features".localized : "feature".localized)")
Text("\(file.overlayCount) features")
.font(.caption2)
.foregroundColor(.secondary)
Spacer()

View file

@ -43,18 +43,18 @@ struct DeviceOnboarding: View {
VStack(alignment: .leading, spacing: 16) {
makeRow(
icon: "antenna.radiowaves.left.and.right",
title: "Stay Connected Anywhere".localized,
subtitle: "Communicate off-the-grid with your friends and community without cell service.".localized
title: String(localized: "Stay Connected Anywhere"),
subtitle: String(localized: "Communicate off-the-grid with your friends and community without cell service.")
)
makeRow(
icon: "point.3.connected.trianglepath.dotted",
title: "Create Your Own Networks".localized,
subtitle: "Easily set up private mesh networks for secure and reliable communication in remote areas.".localized
title: String(localized: "Create Your Own Networks"),
subtitle: String(localized: "Easily set up private mesh networks for secure and reliable communication in remote areas.")
)
makeRow(
icon: "location",
title: "Track and Share Locations".localized,
subtitle: "Share your location in real-time and keep your group coordinated with integrated GPS features.".localized
title: String(localized: "Track and Share Locations"),
subtitle: String(localized: "Share your location in real-time and keep your group coordinated with integrated GPS features.")
)
}
.padding()
@ -94,18 +94,18 @@ struct DeviceOnboarding: View {
.fixedSize(horizontal: false, vertical: true)
makeRow(
icon: "message",
title: "Incoming Messages".localized,
subtitle: "Notifications for channel and direct messages.".localized
title: String(localized: "Incoming Messages"),
subtitle: String(localized: "Notifications for channel and direct messages.")
)
makeRow(
icon: "flipphone",
title: "New Nodes".localized,
subtitle: "Notifications for newly discovered nodes.".localized
title: String(localized: "New Nodes"),
subtitle: String(localized: "Notifications for newly discovered nodes.")
)
makeRow(
icon: "battery.25percent",
title: "Low Battery".localized,
subtitle: "Notifications for low battery alerts for the connected device.".localized
title: String(localized: "Low Battery"),
subtitle: String(localized: "Notifications for low battery alerts for the connected device.")
)
Text("Critical Alerts")
.font(.title2.bold())
@ -113,7 +113,7 @@ struct DeviceOnboarding: View {
.fixedSize(horizontal: false, vertical: true)
makeRow(
icon: "exclamationmark.triangle.fill",
subtitle: "Select packets sent as critical will ignore the mute switch and Do Not Disturb settings in the OS notification center.".localized
subtitle: String(localized: "Select packets sent as critical will ignore the mute switch and Do Not Disturb settings in the OS notification center.")
)
}
.padding()
@ -151,8 +151,8 @@ struct DeviceOnboarding: View {
.fixedSize(horizontal: false, vertical: true)
makeRow(
icon: "location",
title: "Share Location".localized,
subtitle: "Use your phone GPS to send locations to your node to instead of using a hardware GPS on your node.".localized
title: String(localized: "Share Location"),
subtitle: String(localized: "Use your phone GPS to send locations to your node to instead of using a hardware GPS on your node.")
)
Toggle(isOn: $provideLocation ) {
Label {
@ -171,18 +171,18 @@ struct DeviceOnboarding: View {
}
makeRow(
icon: "lines.measurement.horizontal",
title: "Distance Measurements".localized,
subtitle: "Display the distance between your phone and other Meshtastic nodes with positions.".localized
title: String(localized: "Distance Measurements"),
subtitle: String(localized: "Display the distance between your phone and other Meshtastic nodes with positions.")
)
makeRow(
icon: "line.3.horizontal.decrease.circle",
title: "Distance Filters".localized,
subtitle: "Filter the node list and mesh map based on proximity to your phone.".localized
title: String(localized: "Distance Filters"),
subtitle: String(localized: "Filter the node list and mesh map based on proximity to your phone.")
)
makeRow(
icon: "mappin",
title: "Mesh Map Location",
subtitle: "Enables the blue location dot for your phone in the mesh map.".localized
title: String(localized: "Mesh Map Location"),
subtitle: String(localized: "Enables the blue location dot for your phone in the mesh map.")
)
}
.padding()
@ -389,8 +389,8 @@ struct DeviceOnboarding: View {
// MARK: Formatting
func createLocationString() -> AttributedString {
var fullText = AttributedString("Meshtastic uses your phone's location to enable a number of features. You can update your location permissions at any time from settings.")
if let range = fullText.range(of: "settings") {
var fullText = AttributedString(localized: "Meshtastic uses your phone's location to enable a number of features. You can update your location permissions at any time from settings.")
if let range = fullText.range(of: String(localized: "settings")) {
fullText[range].link = URL(string: UIApplication.openSettingsURLString)!
fullText[range].foregroundColor = .blue
}

View file

@ -248,7 +248,7 @@ struct Routes: View {
hasChanges = true
}
Map {
Annotation("Start", coordinate: lineCoords.first ?? LocationsHandler.DefaultLocation) {
Annotation(String(localized: "Start"), coordinate: lineCoords.first ?? LocationsHandler.DefaultLocation) {
ZStack {
Circle()
.fill(Color(.green))
@ -257,7 +257,7 @@ struct Routes: View {
}
}
.annotationTitles(.automatic)
Annotation("Finish", coordinate: lineCoords.last ?? LocationsHandler.DefaultLocation) {
Annotation(String(localized: "Finish ", comment: "Space at the end has been added to not interfere with translations for 'Finish' in RouteRecorder"), coordinate: lineCoords.last ?? LocationsHandler.DefaultLocation) {
ZStack {
Circle()
.fill(Color(.black))
@ -306,7 +306,7 @@ struct Routes: View {
)
}
}
.navigationTitle(selectedRoute != nil ? name : "Route List")
.navigationTitle(selectedRoute != nil ? name : String(localized: "Route List"))
.navigationBarTitleDisplayMode(.inline)
}
}

View file

@ -0,0 +1,18 @@
// german localization
"Will share your phone GPS location with your node." = "Teile den GPS-Standort deines Handys mit deinem Funkgerät.";
"Share Location" = "Standort teilen";
"Interval" = "Intervall";
"Ten Seconds" = "10 s";
"Fifteen Seconds" = "15 s";
"Thirty Seconds" = "30 s";
"Forty Five Seconds" = "45 s";
"One Minute" = "1 min";
"Five Minutes" = "5 min";
"Ten Minutes" = "10 min";
"Fifteen Minutes" = "15 min";
"Accurate Locations Only" = "Nur genaue Standorte";
"Notifications" = "Mitteilungen";
"Channel Messages" = "Kanalnachrichten";
"New Nodes" = "Neu entdeckte Knoten";
"Low Battery" = "Niedriger Akkustand";