From 81e746fcba5ffed82fdc4728c3b403abf2bb957c Mon Sep 17 00:00:00 2001 From: Ahmed Harmouche Date: Wed, 16 Sep 2026 11:57:03 +0200 Subject: [PATCH 1/4] Localization HU WIP --- .vscode/settings.json | 3 + .../app/src/main/AndroidManifest.xml | 1 + .../softwiredtech/dashpilot/MainActivity.kt | 6 +- .../dashpilot/ble/DashKitOtaUpdate.kt | 15 +- .../dashpilot/ble/FirmwareUpdateManager.kt | 7 +- .../dashpilot/datasource/DashKitBleManager.kt | 25 +- .../dashpilot/ui/AutomationsScreen.kt | 52 +- .../dashpilot/ui/BatteryScreen.kt | 36 +- .../dashpilot/ui/ClimateScreen.kt | 58 +- .../dashpilot/ui/ControlScreen.kt | 8 +- .../dashpilot/ui/DebugDataSourceMenu.kt | 18 +- .../softwiredtech/dashpilot/ui/HomeScreen.kt | 26 +- .../dashpilot/ui/ScreenHeader.kt | 4 +- .../softwiredtech/dashpilot/ui/SetupScreen.kt | 6 +- .../dashpilot/ui/controls/VehicleControls.kt | 26 +- .../viewmodel/ConnectionViewModel.kt | 7 +- .../app/src/main/res/values-hu/strings.xml | 313 +++ .../app/src/main/res/values/strings.xml | 132 ++ .../app/src/main/res/xml/locales_config.xml | 5 + .../dashpilot.xcodeproj/project.pbxproj | 1 + .../dashpilot/BLE/DashKitOtaUpdate.swift | 14 +- .../dashpilot/BLE/FirmwareUpdateManager.swift | 6 +- .../DataSource/DashKitBleManager.swift | 18 +- dashpilot-ios/dashpilot/InfoPlist.xcstrings | 16 + dashpilot-ios/dashpilot/Localizable.xcstrings | 1866 +++++++++++++++++ .../dashpilot/Models/DashboardConfig.swift | 10 +- .../dashpilot/Models/VehicleControls.swift | 16 +- .../dashpilot/UI/AutomationsView.swift | 18 +- dashpilot-ios/dashpilot/UI/BatteryView.swift | 2 +- dashpilot-ios/dashpilot/UI/ClimateView.swift | 24 +- dashpilot-ios/dashpilot/UI/Components.swift | 2 +- .../dashpilot/UI/DashKitSettingsView.swift | 22 +- dashpilot-ios/dashpilot/UI/HomeView.swift | 8 +- .../Onboarding/OnboardingPageScaffold.swift | 6 +- .../UI/Onboarding/OnboardingPairingPage.swift | 9 +- .../UI/Onboarding/OnboardingTipsPage.swift | 2 +- dashpilot-ios/dashpilot/UI/SettingsView.swift | 10 +- dashpilot-ios/dashpilot/UI/SetupView.swift | 7 +- .../ViewModel/ConnectionViewModel.swift | 2 +- 39 files changed, 2590 insertions(+), 217 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 dashpilot-android/app/src/main/res/values-hu/strings.xml create mode 100644 dashpilot-android/app/src/main/res/xml/locales_config.xml create mode 100644 dashpilot-ios/dashpilot/InfoPlist.xcstrings create mode 100644 dashpilot-ios/dashpilot/Localizable.xcstrings diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..604fadc0 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cmake.sourceDirectory": "/Users/ahmedharmouche/Documents/dashpilot/dashpilot-android/bridge" +} \ No newline at end of file diff --git a/dashpilot-android/app/src/main/AndroidManifest.xml b/dashpilot-android/app/src/main/AndroidManifest.xml index 93b9bbca..6a34521d 100644 --- a/dashpilot-android/app/src/main/AndroidManifest.xml +++ b/dashpilot-android/app/src/main/AndroidManifest.xml @@ -24,6 +24,7 @@ android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" + android:localeConfig="@xml/locales_config" android:usesCleartextTraffic="true" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/MainActivity.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/MainActivity.kt index 6dec6618..3573102e 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/MainActivity.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/MainActivity.kt @@ -240,7 +240,7 @@ class MainActivity : ComponentActivity() { } }, onSkip = { - connectionVM.disconnect() + connectionVM.disconnect(context) setOnboardingCompleted(context, true) navController.navigate(SetupRoute) { popUpTo(OnboardingRoute) { inclusive = true } @@ -273,7 +273,7 @@ class MainActivity : ComponentActivity() { ) }, onDisconnect = { - connectionVM.disconnect() + connectionVM.disconnect(context) }, onNext = toDashboard, onBattery = { @@ -374,7 +374,7 @@ class MainActivity : ComponentActivity() { onRemoveTesla = { teslaSource?.requestReset() == true }, onEnrollTesla = { navController.navigate(TeslaEnrollRoute) }, onReplayOnboarding = { - connectionVM.disconnect() + connectionVM.disconnect(context) setOnboardingCompleted(context, false) navController.navigate(OnboardingRoute) { popUpTo(SetupRoute) { inclusive = false } diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ble/DashKitOtaUpdate.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ble/DashKitOtaUpdate.kt index 709055b1..75d23a42 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ble/DashKitOtaUpdate.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ble/DashKitOtaUpdate.kt @@ -12,6 +12,7 @@ import com.softwiredtech.dashpilot.datasource.GattListener import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import java.util.UUID +import com.softwiredtech.dashpilot.R sealed class OtaState { object Idle : OtaState() @@ -52,7 +53,7 @@ class DashKitOtaUpdate( fun start(fw: ByteArray) { if (fw.isEmpty()) { - _state.value = OtaState.Error("Firmware file is empty") + _state.value = OtaState.Error(manager.context.getString(R.string.ota_error_empty)) return } firmware = fw @@ -98,7 +99,7 @@ class DashKitOtaUpdate( private fun setupOtaService(g: BluetoothGatt) { val service = g.getService(OTA_SERVICE_UUID) if (service == null) { - _state.value = OtaState.Error("OTA service not found on device") + _state.value = OtaState.Error(manager.context.getString(R.string.ota_error_service_not_found)) return } @@ -107,7 +108,7 @@ class DashKitOtaUpdate( statusChar = service.getCharacteristic(OTA_STATUS_UUID) if (ctrlChar == null || dataChar == null || statusChar == null) { - _state.value = OtaState.Error("OTA characteristics not found") + _state.value = OtaState.Error(manager.context.getString(R.string.ota_error_chars_not_found)) return } controlChar = g.getService(VehicleControl.SERVICE_UUID) @@ -132,7 +133,7 @@ class DashKitOtaUpdate( // Only handle OTA status descriptor if (descriptor.characteristic?.uuid != OTA_STATUS_UUID) return if (status != BluetoothGatt.GATT_SUCCESS) { - _state.value = OtaState.Error("Failed to enable OTA notifications") + _state.value = OtaState.Error(manager.context.getString(R.string.ota_error_notify)) return } sendBeginCommand(gatt) @@ -159,7 +160,7 @@ class DashKitOtaUpdate( return } if (status != BluetoothGatt.GATT_SUCCESS) { - _state.value = OtaState.Error("Write failed (status $status)") + _state.value = OtaState.Error(manager.context.getString(R.string.ota_error_write, status)) return } val fw = firmware @@ -177,7 +178,7 @@ class DashKitOtaUpdate( Log.d(TAG, "Link dropped after the last chunk; treating as reboot") _state.value = OtaState.Rebooting } else if (currentState !is OtaState.Rebooting && currentState !is OtaState.Idle) { - _state.value = OtaState.Error("Disconnected unexpectedly") + _state.value = OtaState.Error(manager.context.getString(R.string.ota_error_disconnected)) } manager.suppressPings = false firmware = null @@ -265,7 +266,7 @@ class DashKitOtaUpdate( 0xFF -> { val errCode = if (value.size > 1) value[1].toInt() and 0xFF else 0 Log.e(TAG, "OTA error from device: 0x${errCode.toString(16)}") - _state.value = OtaState.Error("Device reported error (0x${errCode.toString(16)})") + _state.value = OtaState.Error(manager.context.getString(R.string.ota_error_device, errCode.toString(16))) manager.removeGattListener(this) manager.suppressPings = false uploadFinished = false diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ble/FirmwareUpdateManager.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ble/FirmwareUpdateManager.kt index 0f4aed45..e4f0a0bd 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ble/FirmwareUpdateManager.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ble/FirmwareUpdateManager.kt @@ -8,6 +8,7 @@ import com.softwiredtech.dashpilot.util.SemVer import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import java.security.MessageDigest +import com.softwiredtech.dashpilot.R /** * Orchestrates the end-to-end firmware update flow: @@ -60,7 +61,7 @@ class FirmwareUpdateManager( _check.value = Check.Checking val manifest = FirmwareUpdateRepository.fetchManifest() if (manifest == null) { - _check.value = Check.Error("Could not reach update server") + _check.value = Check.Error(manager.context.getString(R.string.fw_error_unreachable)) return } val current = installedVersion.value ?: versionReader.await() @@ -93,14 +94,14 @@ class FirmwareUpdateManager( if (!expected.isNullOrEmpty()) { val actual = sha256Hex(bytes) if (actual != expected) { - _check.value = Check.Error("Downloaded firmware failed integrity check") + _check.value = Check.Error(manager.context.getString(R.string.fw_error_integrity)) return } } ota.start(bytes) } catch (e: Exception) { _downloadProgress.value = null - _check.value = Check.Error("Download failed: ${e.message}") + _check.value = Check.Error(manager.context.getString(R.string.fw_error_download, e.message)) } } diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/datasource/DashKitBleManager.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/datasource/DashKitBleManager.kt index 201236a0..a512da67 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/datasource/DashKitBleManager.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/datasource/DashKitBleManager.kt @@ -24,6 +24,7 @@ import java.util.UUID import com.softwiredtech.dashpilot.ble.VehicleControl import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import com.softwiredtech.dashpilot.R interface GattListener { fun onServicesReady(gatt: BluetoothGatt) {} @@ -39,7 +40,7 @@ interface GattListener { class BleConnectionException(message: String) : Exception(message) @SuppressLint("MissingPermission") -class DashKitBleManager(private val context: Context) { +class DashKitBleManager(internal val context: Context) { companion object { private const val TAG = "DashKitBleManager" @@ -186,7 +187,7 @@ class DashKitBleManager(private val context: Context) { Log.w(TAG, "Scan timed out without finding DashKit (attempt $attemptCount/$MAX_ATTEMPTS)") crashlytics.log("BLE: scan timed out (attempt $attemptCount/$MAX_ATTEMPTS)") stopScan() - retryOrFail("DashKit not found") + retryOrFail(context.getString(R.string.ble_dashkit_not_found)) } private val connectTimeoutRunnable = Runnable { @@ -195,7 +196,7 @@ class DashKitBleManager(private val context: Context) { Log.w(TAG, "Connect attempt timed out (attempt $attemptCount/$MAX_ATTEMPTS)") crashlytics.log("BLE: connect attempt timed out (attempt $attemptCount/$MAX_ATTEMPTS)") try { pending.close() } catch (_: Exception) {} - retryOrFail("Could not connect to DashKit") + retryOrFail(context.getString(R.string.ble_could_not_connect)) } // Retry after a short pause while attempts remain, otherwise publish an @@ -281,7 +282,7 @@ class DashKitBleManager(private val context: Context) { override fun onScanFailed(errorCode: Int) { Log.e(TAG, "BLE scan failed: $errorCode") crashlytics.recordException(BleConnectionException("BLE scan failed (error $errorCode)")) - _connectionState.value = ConnectionStatus.Error("BLE scan failed (error $errorCode)") + _connectionState.value = ConnectionStatus.Error(context.getString(R.string.ble_scan_failed_code, errorCode)) } } @@ -327,7 +328,7 @@ class DashKitBleManager(private val context: Context) { Log.e(TAG, "createBond() failed to start") crashlytics.recordException(BleConnectionException("Could not start pairing (createBond failed)")) _connectionState.value = - ConnectionStatus.Error("Could not start pairing") + ConnectionStatus.Error(context.getString(R.string.ble_could_not_start_pairing)) } } } @@ -360,9 +361,9 @@ class DashKitBleManager(private val context: Context) { // pairing window is open. val message = if (g.device.bondState == BluetoothDevice.BOND_BONDED) { - "Could not connect to DashKit" + context.getString(R.string.ble_could_not_connect) } else { - "DashKit did not accept pairing. Open \"Pair a new device\" in DashPilot settings on an already-paired phone, then try again." + context.getString(R.string.ble_pairing_rejected) } retryOrFail(message) return @@ -448,7 +449,7 @@ class DashKitBleManager(private val context: Context) { if (status != BluetoothGatt.GATT_SUCCESS) { Log.e(TAG, "Service discovery failed: $status") crashlytics.recordException(BleConnectionException("Service discovery failed (status=$status)")) - _connectionState.value = ConnectionStatus.Error("Service discovery failed") + _connectionState.value = ConnectionStatus.Error(context.getString(R.string.ble_service_discovery_failed)) return } Log.d(TAG, "Discovered ${g.services.size} services:") @@ -602,13 +603,13 @@ class DashKitBleManager(private val context: Context) { .adapter ?: run { Log.e(TAG, "Bluetooth not available") crashlytics.recordException(BleConnectionException("Bluetooth not available")) - _connectionState.value = ConnectionStatus.Error("Bluetooth not available") + _connectionState.value = ConnectionStatus.Error(context.getString(R.string.ble_bluetooth_unavailable)) return } val scanner = adapter.bluetoothLeScanner ?: run { Log.e(TAG, "BLE scanner not available") crashlytics.recordException(BleConnectionException("BLE scanner not available (Bluetooth off?)")) - _connectionState.value = ConnectionStatus.Error("BLE scanner not available") + _connectionState.value = ConnectionStatus.Error(context.getString(R.string.ble_scanner_unavailable)) return } val settings = ScanSettings.Builder() @@ -631,11 +632,11 @@ class DashKitBleManager(private val context: Context) { } catch (e: SecurityException) { Log.e(TAG, "BLE scan failed — missing permission: ${e.message}") crashlytics.recordException(BleConnectionException("BLE scan failed — missing permission: ${e.message}")) - _connectionState.value = ConnectionStatus.Error("Missing BLE permission") + _connectionState.value = ConnectionStatus.Error(context.getString(R.string.ble_missing_permission)) } catch (e: Exception) { Log.e(TAG, "BLE scan failed: ${e.message}") crashlytics.recordException(BleConnectionException("BLE scan failed: ${e.message}")) - _connectionState.value = ConnectionStatus.Error("Scan failed: ${e.message}") + _connectionState.value = ConnectionStatus.Error(context.getString(R.string.ble_scan_failed, e.message)) } } diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/AutomationsScreen.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/AutomationsScreen.kt index b1af5ade..ef629218 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/AutomationsScreen.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/AutomationsScreen.kt @@ -52,6 +52,8 @@ import com.softwiredtech.dashpilot.ui.controls.controlById import com.softwiredtech.dashpilot.ui.controls.vehicleControls import com.softwiredtech.dashpilot.ui.theme.AccentColor import com.softwiredtech.dashpilot.ui.theme.DarkColors +import androidx.compose.ui.res.stringResource +import com.softwiredtech.dashpilot.R // Finger counts that can be bound to an infotainment gesture (matches the // firmware's MULTI_FINGER_MIN/MAX_FINGERS). @@ -101,36 +103,36 @@ fun AutomationsScreen( .verticalScroll(rememberScrollState()) .padding(horizontal = 24.dp, vertical = 24.dp) ) { - ScreenHeader(title = "Automations", onBack = onBack) + ScreenHeader(title = stringResource(R.string.automations_title), onBack = onBack) Spacer(modifier = Modifier.height(24.dp)) - SectionLabel("Wipers") + SectionLabel(stringResource(R.string.automations_section_wipers)) Spacer(modifier = Modifier.height(8.dp)) AutomationRow( icon = Icons.Rounded.WaterDrop, - title = "Wiper Off", - subtitle = "Keep wipers disabled automatically", + title = stringResource(R.string.automations_wiper_off_title), + subtitle = stringResource(R.string.automations_wiper_off_subtitle), checked = wiperOffEnabled, onToggle = { onWiperOffChange(!wiperOffEnabled) } ) Spacer(modifier = Modifier.height(28.dp)) - SectionLabel("Climate") + SectionLabel(stringResource(R.string.automations_section_climate)) Spacer(modifier = Modifier.height(8.dp)) AutomationRow( icon = Icons.Rounded.AcUnit, - title = "Keep climate on", - subtitle = "Keep the climate on when you leave the car. The automation stops after the set time, or when you return to the car.", + title = stringResource(R.string.automations_keep_climate_title), + subtitle = stringResource(R.string.automations_keep_climate_subtitle), checked = climateKeepEnabled, onToggle = { onClimateKeepChange(!climateKeepEnabled) }, extraContent = if (climateKeepEnabled) { { NumberPickerFooter( - label = "Stop after", + label = stringResource(R.string.automations_stop_after), value = climateKeepMinutes, - unit = "min", + unit = stringResource(R.string.unit_min), range = CLIMATE_KEEP_MINUTE_RANGE, onValueChange = onClimateKeepMinutesChange ) @@ -140,18 +142,18 @@ fun AutomationsScreen( Spacer(modifier = Modifier.height(28.dp)) - SectionLabel("Driving") + SectionLabel(stringResource(R.string.automations_section_driving)) Spacer(modifier = Modifier.height(8.dp)) AutomationRow( icon = Icons.Rounded.Speed, - title = "Kick-down", - subtitle = "Switch from Chill to Standard while the accelerator is pressed past the threshold. Reverts when you ease off.", + title = stringResource(R.string.automations_kickdown_title), + subtitle = stringResource(R.string.automations_kickdown_subtitle), checked = sportKickdownEnabled, onToggle = { onSportKickdownChange(!sportKickdownEnabled) }, extraContent = if (sportKickdownEnabled) { { NumberPickerFooter( - label = "Pedal threshold", + label = stringResource(R.string.automations_pedal_threshold), value = sportKickdownPercent, unit = "%", range = SPORT_KICKDOWN_PERCENT_RANGE, @@ -164,10 +166,10 @@ fun AutomationsScreen( Spacer(modifier = Modifier.height(28.dp)) - SectionLabel("Multi-touch infotainment trigger") + SectionLabel(stringResource(R.string.automations_multitouch_title)) Spacer(modifier = Modifier.height(4.dp)) Text( - text = "Bind 3-, 4-, or 5-finger infotainment taps to a control", + text = stringResource(R.string.automations_multitouch_subtitle), color = DarkColors.TextMuted, fontSize = 13.sp, modifier = Modifier.padding(start = 4.dp) @@ -275,10 +277,10 @@ internal fun NumberPickerFooter( TextButton(onClick = { showPicker = false onValueChange(pending) - }) { Text("OK") } + }) { Text(stringResource(R.string.common_ok)) } }, dismissButton = { - TextButton(onClick = { showPicker = false }) { Text("Cancel") } + TextButton(onClick = { showPicker = false }) { Text(stringResource(R.string.common_cancel)) } } ) } @@ -307,21 +309,21 @@ private fun FingerActionRow( onSelect = onFingerCountChange ) Spacer(modifier = Modifier.size(6.dp)) - Text(text = "fingers", color = DarkColors.TextMuted, fontSize = 14.sp) + Text(text = stringResource(R.string.automations_fingers), color = DarkColors.TextMuted, fontSize = 14.sp) Spacer(modifier = Modifier.size(10.dp)) - Text(text = "action:", color = DarkColors.TextMuted, fontSize = 14.sp) + Text(text = stringResource(R.string.automations_action), color = DarkColors.TextMuted, fontSize = 14.sp) Spacer(modifier = Modifier.size(6.dp)) DropdownPicker( - selectedLabel = controlById(controlId)?.label?.invoke() ?: controlId, + selectedLabel = controlById(controlId)?.let { stringResource(it.labelRes()) } ?: controlId, options = vehicleControls, - optionLabel = { it.label() }, + optionLabel = { stringResource(it.labelRes()) }, onSelect = { onActionChange(it.id) }, modifier = Modifier.weight(1f) ) IconButton(onClick = onRemove) { Icon( imageVector = Icons.Rounded.Close, - contentDescription = "Remove", + contentDescription = stringResource(R.string.automations_remove), tint = DarkColors.TextMuted, modifier = Modifier.size(20.dp) ) @@ -334,7 +336,7 @@ private fun FingerActionRow( private fun DropdownPicker( selectedLabel: String, options: List, - optionLabel: (T) -> String, + optionLabel: @Composable (T) -> String, onSelect: (T) -> Unit, modifier: Modifier = Modifier ) { @@ -388,13 +390,13 @@ private fun AddTriggerButton(onClick: () -> Unit) { ) { Icon( imageVector = Icons.Rounded.Add, - contentDescription = "Add trigger", + contentDescription = stringResource(R.string.automations_add_trigger), tint = AccentColor, modifier = Modifier.size(22.dp) ) Spacer(modifier = Modifier.size(8.dp)) Text( - text = "Add trigger", + text = stringResource(R.string.automations_add_trigger), color = AccentColor, fontSize = 15.sp, fontWeight = FontWeight.SemiBold diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/BatteryScreen.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/BatteryScreen.kt index 2f4ee059..b9309f0f 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/BatteryScreen.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/BatteryScreen.kt @@ -39,6 +39,8 @@ import com.softwiredtech.dashpilot.ui.theme.DarkColors import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf import kotlin.math.roundToInt +import androidx.compose.ui.res.stringResource +import com.softwiredtech.dashpilot.R @Composable fun BatteryScreen( @@ -62,7 +64,7 @@ fun BatteryScreen( .verticalScroll(rememberScrollState()) .padding(horizontal = 24.dp, vertical = 24.dp) ) { - ScreenHeader(title = "Battery", onBack = onBack) + ScreenHeader(title = stringResource(R.string.battery_title), onBack = onBack) Spacer(modifier = Modifier.height(24.dp)) @@ -70,7 +72,7 @@ fun BatteryScreen( controlById("battery_preheat")?.let { action -> Spacer(modifier = Modifier.height(28.dp)) Text( - text = "Preheat", + text = stringResource(R.string.battery_preheat), color = DarkColors.TextMuted, fontSize = 13.sp, fontWeight = FontWeight.SemiBold @@ -87,35 +89,35 @@ fun BatteryScreen( Spacer(modifier = Modifier.height(28.dp)) InfoSection( - "Energy", + stringResource(R.string.battery_section_energy), listOf( - "Remaining" to energyText(car.nominalEnergyRemaining), - "Usable" to usableEnergyText(car), - "Full Pack" to energyText(car.fullPackEnergy), - "Buffer" to bufferText(car) + stringResource(R.string.battery_remaining) to energyText(car.nominalEnergyRemaining), + stringResource(R.string.battery_usable) to usableEnergyText(car), + stringResource(R.string.battery_full_pack) to energyText(car.fullPackEnergy), + stringResource(R.string.battery_buffer) to bufferText(car) ) ) Spacer(modifier = Modifier.height(28.dp)) InfoSection( - "Power", + stringResource(R.string.battery_section_power), listOf( - "Power" to powerText(car), - "Max Discharge" to kilowattText(car.maxDischargePower), - "Max Regen" to kilowattText(car.maxRegenPower) + stringResource(R.string.battery_power) to powerText(car), + stringResource(R.string.battery_max_discharge) to kilowattText(car.maxDischargePower), + stringResource(R.string.battery_max_regen) to kilowattText(car.maxRegenPower) ) ) Spacer(modifier = Modifier.height(28.dp)) InfoSection( - "Pack", + stringResource(R.string.battery_section_pack), listOf( - "Voltage" to voltageText(car), - "Current" to currentText(car), - "Temp Min" to tempText(car.packTMin), - "Temp Max" to tempText(car.packTMax) + stringResource(R.string.battery_voltage) to voltageText(car), + stringResource(R.string.battery_current) to currentText(car), + stringResource(R.string.battery_temp_min) to tempText(car.packTMin), + stringResource(R.string.battery_temp_max) to tempText(car.packTMax) ) ) @@ -166,7 +168,7 @@ private fun SocCard(car: CarState) { ) } Text( - text = "State of charge", + text = stringResource(R.string.battery_state_of_charge), color = DarkColors.TextMuted, fontSize = 13.sp ) diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/ClimateScreen.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/ClimateScreen.kt index fb89174e..ed76f3ec 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/ClimateScreen.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/ClimateScreen.kt @@ -34,6 +34,8 @@ import com.softwiredtech.dashpilot.ui.theme.DarkColors import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf import kotlin.math.roundToInt +import androidx.compose.ui.res.stringResource +import com.softwiredtech.dashpilot.R @Composable fun ClimateScreen( @@ -63,7 +65,7 @@ fun ClimateScreen( .verticalScroll(rememberScrollState()) .padding(horizontal = 24.dp, vertical = 24.dp) ) { - ScreenHeader(title = "Climate", onBack = onBack) + ScreenHeader(title = stringResource(R.string.climate_title), onBack = onBack) Spacer(modifier = Modifier.height(24.dp)) @@ -71,20 +73,20 @@ fun ClimateScreen( Spacer(modifier = Modifier.height(28.dp)) - SectionTitle("Automation") + SectionTitle(stringResource(R.string.climate_section_automation)) Spacer(modifier = Modifier.height(8.dp)) AutomationRow( icon = Icons.Rounded.AcUnit, - title = "Keep climate on", - subtitle = "Keep the climate on when you leave the car. The automation stops after the set time, or when you return to the car.", + title = stringResource(R.string.automations_keep_climate_title), + subtitle = stringResource(R.string.automations_keep_climate_subtitle), checked = climateKeepEnabled, onToggle = { onClimateKeepChange(!climateKeepEnabled) }, extraContent = if (climateKeepEnabled) { { NumberPickerFooter( - label = "Stop after", + label = stringResource(R.string.automations_stop_after), value = climateKeepMinutes, - unit = "min", + unit = stringResource(R.string.unit_min), range = CLIMATE_KEEP_MINUTE_RANGE, onValueChange = onClimateKeepMinutesChange ) @@ -95,23 +97,23 @@ fun ClimateScreen( Spacer(modifier = Modifier.height(28.dp)) InfoSection( - "Setpoints", + stringResource(R.string.climate_section_setpoints), listOf( - "Driver" to setpointText(car.acTemp, imperial), - "Passenger" to setpointText(car.acTempRight, imperial) + stringResource(R.string.climate_driver) to setpointText(car.acTemp, imperial), + stringResource(R.string.climate_passenger) to setpointText(car.acTempRight, imperial) ) ) Spacer(modifier = Modifier.height(28.dp)) InfoSection( - "Settings", + stringResource(R.string.climate_section_settings), listOf( - "Power" to enumText(live, car.hvacPowerState, POWER_LABELS), - "Fan" to fanText(live, car.hvacFanLevel), - "A/C" to enumText(live, car.hvacAcMode, AC_LABELS), - "Recirculation" to enumText(live, car.hvacRecirc, RECIRC_LABELS), - "Keep climate" to enumText(live, car.hvacKeepClimateOn, KEEP_LABELS) + stringResource(R.string.climate_power) to enumText(live, car.hvacPowerState, POWER_LABELS), + stringResource(R.string.climate_fan) to fanText(live, car.hvacFanLevel), + stringResource(R.string.climate_ac) to enumText(live, car.hvacAcMode, AC_LABELS), + stringResource(R.string.climate_recirculation) to enumText(live, car.hvacRecirc, RECIRC_LABELS), + stringResource(R.string.climate_keep_climate) to enumText(live, car.hvacKeepClimateOn, KEEP_LABELS) ) ) @@ -148,7 +150,7 @@ private fun SetpointCard(car: CarState, imperial: Boolean) { ) } Text( - text = "Driver setpoint", + text = stringResource(R.string.climate_driver_setpoint), color = DarkColors.TextMuted, fontSize = 13.sp ) @@ -201,10 +203,16 @@ private fun InfoSection(title: String, rows: List>) { } } -private val POWER_LABELS = listOf("Off", "On", "Preconditioning", "Overheat protection (fan)", "Overheat protection") -private val AC_LABELS = listOf("Auto", "Off", "On") -private val RECIRC_LABELS = listOf("Auto", "Recirculate", "Fresh air") -private val KEEP_LABELS = listOf("Off", "Keep", "Dog mode", "Camp mode") +private val POWER_LABELS = listOf( + R.string.climate_value_off, + R.string.climate_value_on, + R.string.climate_value_preconditioning, + R.string.climate_value_overheat_fan, + R.string.climate_value_overheat +) +private val AC_LABELS = listOf(R.string.climate_value_auto, R.string.climate_value_off, R.string.climate_value_on) +private val RECIRC_LABELS = listOf(R.string.climate_value_auto, R.string.climate_value_recirculate, R.string.climate_value_fresh_air) +private val KEEP_LABELS = listOf(R.string.climate_value_off, R.string.climate_value_keep, R.string.climate_value_dog_mode, R.string.climate_value_camp_mode) private fun setpointText(value: Float, imperial: Boolean): String { if (value == 0f) return "—" @@ -217,14 +225,16 @@ private fun setpointText(value: Float, imperial: Boolean): String { } } -private fun enumText(live: Boolean, value: Float, labels: List): String = - if (live) labels.getOrNull(value.roundToInt()) ?: "—" else "—" +@Composable +private fun enumText(live: Boolean, value: Float, labels: List): String = + if (live) labels.getOrNull(value.roundToInt())?.let { stringResource(it) } ?: "—" else "—" +@Composable private fun fanText(live: Boolean, value: Float): String { if (!live) return "—" return when (val level = value.roundToInt()) { - 0 -> "Off" - 11 -> "Auto" + 0 -> stringResource(R.string.climate_value_off) + 11 -> stringResource(R.string.climate_value_auto) in 1..10 -> "$level" else -> "—" } diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/ControlScreen.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/ControlScreen.kt index b784a01d..7af86cdf 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/ControlScreen.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/ControlScreen.kt @@ -22,6 +22,8 @@ import com.softwiredtech.dashpilot.datasource.DashKitBleManager import com.softwiredtech.dashpilot.ui.controls.ControlActionButton import com.softwiredtech.dashpilot.ui.controls.vehicleControls import com.softwiredtech.dashpilot.ui.theme.DarkColors +import androidx.compose.ui.res.stringResource +import com.softwiredtech.dashpilot.R /** * Vehicle control screen. Exposes the available DashKit commands as single @@ -51,12 +53,12 @@ fun ControlScreen( .verticalScroll(rememberScrollState()) .padding(horizontal = 24.dp, vertical = 24.dp) ) { - ScreenHeader(title = "Controls", onBack = onBack) + ScreenHeader(title = stringResource(R.string.controls_title), onBack = onBack) if (!enabled) { Spacer(modifier = Modifier.height(4.dp)) Text( - text = "Connect to DashKit to send commands", + text = stringResource(R.string.controls_connect_hint), color = DarkColors.TextMuted, fontSize = 13.sp, textAlign = TextAlign.Center, @@ -81,7 +83,7 @@ fun ControlScreen( Spacer(modifier = Modifier.height(20.dp)) Text( - text = "Tip: long-press a control to pin it to the home screen", + text = stringResource(R.string.controls_pin_tip), color = DarkColors.TextSubtle, fontSize = 12.sp, textAlign = TextAlign.Center, diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/DebugDataSourceMenu.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/DebugDataSourceMenu.kt index ee5ff4b3..5963bfc0 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/DebugDataSourceMenu.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/DebugDataSourceMenu.kt @@ -28,6 +28,8 @@ import com.softwiredtech.dashpilot.datamodel.dash.DASH_PREFS_NAME import com.softwiredtech.dashpilot.datasource.ConnectionStatus import com.softwiredtech.dashpilot.datasource.DataSourceType import com.softwiredtech.dashpilot.ui.theme.DarkColors +import androidx.compose.ui.res.stringResource +import com.softwiredtech.dashpilot.R private const val PREF_LAST_WEBSOCKET_ADDRESS = "last_websocket_address" @@ -56,9 +58,9 @@ fun DebugDataSourceMenu( TextButton(onClick = { expanded = true }) { Text( text = when (connectionStatus) { - is ConnectionStatus.Connected -> "Data source: connected" - is ConnectionStatus.Connecting -> "Data source: connecting…" - else -> "Data source" + is ConnectionStatus.Connected -> stringResource(R.string.data_source_connected) + is ConnectionStatus.Connecting -> stringResource(R.string.data_source_connecting) + else -> stringResource(R.string.data_source) }, color = DarkColors.TextMuted, fontSize = 13.sp @@ -88,7 +90,7 @@ fun DebugDataSourceMenu( } } else { DropdownMenuItem( - text = { Text("Disconnect") }, + text = { Text(stringResource(R.string.setup_disconnect)) }, onClick = { expanded = false onDisconnect() @@ -109,12 +111,12 @@ fun DebugDataSourceMenu( var address by remember { mutableStateOf(getLastWebsocketAddress(context)) } AlertDialog( onDismissRequest = { showIpDialog = false }, - title = { Text("WebSocket server") }, + title = { Text(stringResource(R.string.data_source_websocket_server)) }, text = { OutlinedTextField( value = address, onValueChange = { address = it }, - label = { Text("IP address") }, + label = { Text(stringResource(R.string.data_source_ip_address)) }, singleLine = true ) }, @@ -127,10 +129,10 @@ fun DebugDataSourceMenu( onSelectDataSource(DataSourceType.WEBSOCKET) onConnect(address.trim(), DataSourceType.WEBSOCKET) } - ) { Text("Connect") } + ) { Text(stringResource(R.string.setup_connect)) } }, dismissButton = { - TextButton(onClick = { showIpDialog = false }) { Text("Cancel") } + TextButton(onClick = { showIpDialog = false }) { Text(stringResource(R.string.common_cancel)) } } ) } diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/HomeScreen.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/HomeScreen.kt index 8b6e4f33..d53d9f2a 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/HomeScreen.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/HomeScreen.kt @@ -69,6 +69,8 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOf import kotlin.math.roundToInt +import androidx.compose.ui.res.stringResource +import com.softwiredtech.dashpilot.R /** * Landing screen. DashKit is the default source and shows the connected home @@ -252,13 +254,13 @@ private fun Header( ) { Icon( imageVector = Icons.Rounded.Settings, - contentDescription = "Settings", + contentDescription = stringResource(R.string.settings_title), tint = DarkColors.TextMuted, modifier = Modifier.size(24.dp) ) } Text( - text = "DashPilot", + text = stringResource(R.string.app_name), color = Color.White, fontSize = 20.sp, fontWeight = FontWeight.Bold, @@ -306,7 +308,7 @@ private fun PortraitContent( pinned?.let { action -> Text( - text = "Pinned", + text = stringResource(R.string.home_pinned), color = DarkColors.TextMuted, fontSize = 13.sp, fontWeight = FontWeight.SemiBold @@ -317,14 +319,14 @@ private fun PortraitContent( } ActionButton( - label = "Automations", + label = stringResource(R.string.home_automations), icon = Icons.Rounded.AutoAwesome, accent = false, onClick = onAutomations ) Spacer(modifier = Modifier.height(12.dp)) ActionButton( - label = "Controls", + label = stringResource(R.string.home_controls), icon = Icons.Rounded.Tune, accent = false, onClick = onControls @@ -387,7 +389,7 @@ private fun LandscapeContent( horizontalArrangement = Arrangement.spacedBy(GridGap) ) { ActionTile( - label = "Automations", + label = stringResource(R.string.home_automations), icon = Icons.Rounded.AutoAwesome, onClick = onAutomations, modifier = Modifier @@ -395,7 +397,7 @@ private fun LandscapeContent( .fillMaxHeight() ) ActionTile( - label = "Controls", + label = stringResource(R.string.home_controls), icon = Icons.Rounded.Tune, onClick = onControls, modifier = Modifier @@ -442,7 +444,7 @@ private fun WidgetGrid( ) { InfoWidget( icon = Icons.Rounded.BatteryChargingFull, - label = "Battery", + label = stringResource(R.string.home_widget_battery), value = socText(car), fillHeight = fillHeight, modifier = Modifier.weight(1f), @@ -450,7 +452,7 @@ private fun WidgetGrid( ) InfoWidget( icon = Icons.Rounded.DeviceThermostat, - label = "Battery Temp", + label = stringResource(R.string.home_widget_battery_temp), value = batteryTempText(car), fillHeight = fillHeight, modifier = Modifier.weight(1f), @@ -463,7 +465,7 @@ private fun WidgetGrid( ) { InfoWidget( icon = Icons.Rounded.AcUnit, - label = "AC Temp", + label = stringResource(R.string.home_widget_ac_temp), value = tempText(car.acTemp), fillHeight = fillHeight, modifier = Modifier.weight(1f), @@ -471,7 +473,7 @@ private fun WidgetGrid( ) InfoWidget( icon = Icons.Rounded.Speed, - label = "Odometer", + label = stringResource(R.string.home_widget_odometer), value = odometerText(car.odometer, useImperial), fillHeight = fillHeight, modifier = Modifier.weight(1f) @@ -494,7 +496,7 @@ private fun PinnedButton(action: ControlAction, bleManager: DashKitBleManager?) @Composable private fun DriveButton(onDrive: () -> Unit) { ActionButton( - label = "Drive", + label = stringResource(R.string.home_drive), icon = Icons.Rounded.DirectionsCar, accent = true, onClick = onDrive diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/ScreenHeader.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/ScreenHeader.kt index d0317df2..05eaac02 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/ScreenHeader.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/ScreenHeader.kt @@ -16,6 +16,8 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.compose.ui.res.stringResource +import com.softwiredtech.dashpilot.R /** * Shared header for back-navigable screens: back button on the left, title @@ -35,7 +37,7 @@ fun ScreenHeader(title: String, onBack: () -> Unit) { ) { Icon( imageVector = Icons.AutoMirrored.Rounded.ArrowBack, - contentDescription = "Back", + contentDescription = stringResource(R.string.common_back), tint = Color.White, modifier = Modifier.size(24.dp) ) diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/SetupScreen.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/SetupScreen.kt index 2b0dbb6c..270c7466 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/SetupScreen.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/SetupScreen.kt @@ -267,7 +267,7 @@ fun SetupScreen( ) { Icon( imageVector = Icons.Rounded.Settings, - contentDescription = "Settings", + contentDescription = stringResource(R.string.settings_title), tint = DarkColors.TextMuted, modifier = Modifier.size(24.dp) ) @@ -318,7 +318,7 @@ private fun ConnectionVisualization( ) { Icon( imageVector = Icons.Rounded.DirectionsCar, - contentDescription = "Vehicle", + contentDescription = stringResource(R.string.setup_vehicle_cd), tint = Color.White, modifier = Modifier.size(36.dp) ) @@ -388,7 +388,7 @@ private fun ConnectionVisualization( ) { Icon( imageVector = Icons.Rounded.PhoneAndroid, - contentDescription = "Phone", + contentDescription = stringResource(R.string.setup_phone_cd), tint = Color.White, modifier = Modifier.size(36.dp) ) diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/controls/VehicleControls.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/controls/VehicleControls.kt index c9d5b127..ddaf2e45 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/controls/VehicleControls.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/controls/VehicleControls.kt @@ -38,6 +38,8 @@ import com.softwiredtech.dashpilot.ble.VehicleControl import com.softwiredtech.dashpilot.datasource.DashKitBleManager import com.softwiredtech.dashpilot.ui.theme.AccentColor import com.softwiredtech.dashpilot.ui.theme.DarkColors +import androidx.compose.ui.res.stringResource +import com.softwiredtech.dashpilot.R /** * Session-scoped toggle state for controls the firmware exposes as separate @@ -55,13 +57,13 @@ object ControlsState { } /** - * A single vehicle control definition. [label] and [active] are read lazily so + * A single vehicle control definition. [labelRes] and [active] are read lazily so * they reflect the latest [ControlsState] each recomposition. */ data class ControlAction( val id: String, val icon: ImageVector, - val label: () -> String, + val labelRes: () -> Int, val active: () -> Boolean, // Action code sent to the firmware when this control is bound to a // multi-finger infotainment gesture (must match multi_finger_action_t in the @@ -78,7 +80,7 @@ val vehicleControls: List = listOf( ControlAction( id = "battery_preheat", icon = Icons.Rounded.Thermostat, - label = { if (ControlsState.preheatOn) "Battery Preheat: On" else "Battery Preheat: Off" }, + labelRes = { if (ControlsState.preheatOn) R.string.control_battery_preheat_on else R.string.control_battery_preheat_off }, active = { ControlsState.preheatOn }, gestureValue = 2, perform = { manager -> @@ -93,7 +95,7 @@ val vehicleControls: List = listOf( ControlAction( id = "frunk", icon = VehicleIcons.Frunk, - label = { "Frunk" }, + labelRes = { R.string.control_frunk }, active = { false }, gestureValue = 4, perform = { manager -> @@ -103,7 +105,7 @@ val vehicleControls: List = listOf( ControlAction( id = "trunk", icon = VehicleIcons.Trunk, - label = { "Trunk" }, + labelRes = { R.string.control_trunk }, active = { false }, gestureValue = 5, perform = { manager -> @@ -113,7 +115,7 @@ val vehicleControls: List = listOf( ControlAction( id = "charge_port", icon = Icons.Rounded.EvStation, - label = { if (ControlsState.chargePortOpen) "Charge Port: Open" else "Charge Port: Closed" }, + labelRes = { if (ControlsState.chargePortOpen) R.string.control_charge_port_open else R.string.control_charge_port_closed }, active = { ControlsState.chargePortOpen }, gestureValue = 6, perform = { manager -> @@ -127,7 +129,7 @@ val vehicleControls: List = listOf( ControlAction( id = "mirror_fold", icon = Icons.Rounded.Flip, - label = { if (ControlsState.mirrorsFolded) "Mirrors: Folded" else "Mirrors: Unfolded" }, + labelRes = { if (ControlsState.mirrorsFolded) R.string.control_mirrors_folded else R.string.control_mirrors_unfolded }, active = { ControlsState.mirrorsFolded }, gestureValue = 3, perform = { manager -> @@ -141,7 +143,7 @@ val vehicleControls: List = listOf( ControlAction( id = "rear_fan", icon = Icons.Rounded.Air, - label = { if (ControlsState.rearFanOn) "Rear Fan: On" else "Rear Fan: Off" }, + labelRes = { if (ControlsState.rearFanOn) R.string.control_rear_fan_on else R.string.control_rear_fan_off }, active = { ControlsState.rearFanOn }, gestureValue = 7, perform = { manager -> @@ -155,7 +157,7 @@ val vehicleControls: List = listOf( ControlAction( id = "mirror_dip", icon = Icons.Rounded.SouthEast, - label = { "Toggle Mirror Dip" }, + labelRes = { R.string.control_mirror_dip }, active = { false }, gestureValue = 8, perform = { manager -> @@ -166,7 +168,7 @@ val vehicleControls: List = listOf( ControlAction( id = "glovebox", icon = Icons.Rounded.Inbox, - label = { "Open Glovebox" }, + labelRes = { R.string.control_glovebox }, active = { false }, gestureValue = 1, perform = { manager -> @@ -235,7 +237,7 @@ fun ControlActionButton( } Spacer(modifier = Modifier.size(12.dp)) Text( - text = action.label(), + text = stringResource(action.labelRes()), color = Color.White, fontSize = 16.sp, fontWeight = FontWeight.SemiBold, @@ -245,7 +247,7 @@ fun ControlActionButton( if (pinned) { Icon( imageVector = Icons.Rounded.PushPin, - contentDescription = "Pinned", + contentDescription = stringResource(R.string.control_pinned_cd), tint = Color.White, modifier = Modifier .align(Alignment.TopEnd) diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/viewmodel/ConnectionViewModel.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/viewmodel/ConnectionViewModel.kt index 233d7339..56572775 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/viewmodel/ConnectionViewModel.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/viewmodel/ConnectionViewModel.kt @@ -82,6 +82,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withTimeoutOrNull import kotlin.coroutines.resume +import com.softwiredtech.dashpilot.R class ConnectionViewModel(private var networkUtil: NetworkUtil) : ViewModel() { private val _dataSource = MutableStateFlow(null) @@ -344,7 +345,7 @@ class ConnectionViewModel(private var networkUtil: NetworkUtil) : ViewModel() { if (gate != null) { gate { connect(context, manualServerAddress, dataSourceType, userInitiated) } } else { - _connectionStatus.value = ConnectionStatus.Error("Missing BLE permission") + _connectionStatus.value = ConnectionStatus.Error(context.getString(R.string.ble_missing_permission)) } return } @@ -499,11 +500,11 @@ class ConnectionViewModel(private var networkUtil: NetworkUtil) : ViewModel() { _hasAutoNavigatedToDashboard.value = false } - fun disconnect() { + fun disconnect(context: Context) { val wasConnecting = _connectionStatus.value is ConnectionStatus.Connecting teardownConnection() _connectionStatus.value = if (wasConnecting) { - ConnectionStatus.Error("Discovery cancelled") + ConnectionStatus.Error(context.getString(R.string.connection_discovery_cancelled)) } else { ConnectionStatus.Disconnected } diff --git a/dashpilot-android/app/src/main/res/values-hu/strings.xml b/dashpilot-android/app/src/main/res/values-hu/strings.xml new file mode 100644 index 00000000..20b0db72 --- /dev/null +++ b/dashpilot-android/app/src/main/res/values-hu/strings.xml @@ -0,0 +1,313 @@ + + DashPilot + Eszköz IP-címe + Válassz adatforrást + Csatlakozás a comma eszközhöz + Csatlakozás + Csatlakozás… + Mégse + Kapcsolat bontása + Tovább + Beállítások + Vissza + Verzió + Műszerfal + Válaszd ki, mi nyíljon meg csatlakozás után + Vanilla + Ambient + Retro + Expo + Analog + Rive + Rive fájl betöltése + Megjelenítés + Konfiguráció + Egyes beállítások a kiválasztott témától függenek + Műszerfal témája + 3D megjelenítő + Telefon akkumulátorának mutatása + Autó akkumulátorának mutatása + Kilométer-számláló mutatása + Mértékegységek + Angolszász mértékegységek + km + mi + Renderelési minőség + Alacsony + Közepes + Magas + Extra járműbusz + A szerkesztéshez kapcsold be az Extra járműbuszt. + Mindig bekapcsolt holttérfigyelő + Sötét mód + Háttér fényereje + Fordítsd a telefont fekvő helyzetbe + Firmware + DashKit firmware frissítése + DashKit keresése… + Csatlakozás… + Firmware feltöltése… %1$d%% + Frissítés kész! A DashKit újraindul… + A frissítés sikertelen: %1$s + A firmware frissítéséhez előbb csatlakozz a DashKithez + Frissítések keresése… + A DashKit firmware naprakész + Elérhető a(z) %1$s verzió + Frissítés telepítése + Firmware letöltése… %1$d%% + + + Általános + DashKit + + + Firmware adatai + Állapot + Csatlakozva + Nincs kapcsolat + Firmware verzió + Ismeretlen + + + Karbantartás + Passthrough + DashKit újraindítása + Újraindítod a DashKitet? + A DashKit újraindul, és rövid időre megszakad a kapcsolat. Amint újra elindult, automatikusan újracsatlakozik. + Újraindítás + Mégse + Újraindítási parancs elküldve. A DashKit újraindul. + Nem sikerült elküldeni az újraindítási parancsot. + A kezeléshez csatlakozz egy DashKit eszközhöz. + + + Párosítás + Új eszköz párosítása + Új eszköz párosításához előbb csatlakozz a DashKithez + Párosítasz egy új eszközt? + A DashKit a következő 2 percben egy új eszköz párosítását engedélyezi. Nyisd meg a DashPilotot a másik telefonon, és párosítsd most. + Párosítás megnyitása + Mégse + A DashKit párosításra kész. Párosítsd az új telefont 2 percen belül. + + + Beállítás + Kihagyás + %1$d / %2$d + + Eszköz párosítása + Párosítás… + Párosítsd a DashKitet + Csatlakoztasd a DashKitet az autó diagnosztikai portjához, majd koppints alul a Bluetooth-párosításhoz. + DashKit keresése… + Tartsd az eszközt a telefon közelében. Ez általában néhány másodpercet vesz igénybe. + Minden készen áll! + A DashKit csatlakozva van, és készen áll az adatok küldésére a műszerfalra. + Folytatás + + Még valami + További eszközöket párosíthatsz és firmware-frissítéseket telepíthetsz bármikor a Beállításokból. + Kezdjük + További DashKit eszközök párosítása + Firmware-frissítések keresése + + Bevezető újranézése + + + Tesla + Tesla csatlakoztatása + Nincs csatlakoztatva + Autó megtalálva — Csatlakozás + Az autó nincs csatlakoztatva + A csatlakozás sikertelen — koppints az újrapróbáláshoz + Csatlakoztatva + Jelen + Nincs jelen + Zárva + Nyitva + Alszik + Ébren + Kártya érintésére kész + A csatlakozás sikertelen + + + Tesla csatlakoztatása + A DashKit töltéskezelőként (Charging Manager) adja hozzá magát a Teslához — le tudja olvasni az állapotot és vezérli a töltést, de nem tudja kinyitni vagy vezetni az autót. + Töltéskezelő · Olvasás + töltés + Csatlakozás + Készítsd elő a kulcskártyát. + Kapcsolatfelvétel az autóval… A DashKit párosítást kezdeményez. + Tartsd a telefont és a DashKitet a közelben. + DashKit ellenőrzése… + Járműazonosító olvasása… + Tesla keresése… + Tesla · Alvázszám %1$s + Autó megtalálva — csatlakozás a DashKithez… + A DashKit nem erősítette meg az autót. Ellenőrizd a kapcsolatot, és próbáld újra. + A Tesla csatlakoztatásához frissítsd a DashKit firmware-ét. + Nem sikerült beolvasni az alvázszámot. Ébreszd fel a járművet, és próbáld újra. Ha a hiba továbbra is fennáll, frissítsd a DashKit firmware-ét. + Ellenőrizd, hogy a Bluetooth be van kapcsolva, és maradj a jármű közelében. + Érintsd oda a kulcskártyát + Helyezd a kulcskártyát a középkonzolra, majd hagyd jóvá az autó érintőképernyőjén. + %1$d mp van hátra + Az autó kész — érintsd oda most a kulcskártyát (%1$d mp) + Csatlakoztatva + A DashKit mostantól töltéskezelő a Tesládon. + Olvasás + töltés engedélyezve + Kész + A csatlakozás sikertelen + Újra + Mégse + Nem érintetted oda időben a kártyát. Próbáld újra. + Az autó elutasította a csatlakozást. Ellenőrizd, hogy a megfelelő autó közelében vagy, és annak kulcskártyáját használod. + A DashKit nem tudott kommunikálni az autóval. Próbáld újra. + A DashKit nem tudta elmenteni a kapcsolatot. Próbáld újra. + Hiba történt. Próbáld újra. + + + Tesla-kapcsolat + Állapot olvasása és töltésvezérlés BLE-n keresztül. + Állapot + Tesla csatlakoztatása + Tesla-kapcsolat eltávolítása + Eltávolítod a Tesla-kapcsolatot? + Távolítsd el a DashKitet az autó Zárak képernyőjéről, majd távolítsd el itt a kapcsolatot. Az újracsatlakozáshoz szükséged lesz a kulcskártyára. + Eltávolítás + Mégse + Tesla-kapcsolat eltávolítása… + Nem sikerült eltávolítani a kapcsolatot. Próbáld újra. + Kapcsolat eltávolítása… + Egy másik telefont párosít — a Tesla-kapcsolattól függetlenül. + + + Vissza + Mégse + OK + perc + + + Rögzítve + Automatizálások + Vezérlők + Vezetés + Akkumulátor + Akku hőmérséklet + Klíma hőfok + Kilométer-számláló + Jármű + Telefon + + + Adatforrás + Adatforrás: csatlakozva + Adatforrás: csatlakozás… + WebSocket-szerver + IP-cím + + + Vezérlők + A parancsok küldéséhez csatlakozz a DashKithez + Tipp: nyomj hosszan egy vezérlőt, hogy a kezdőképernyőre rögzítsd + Rögzítve + Akku előfűtés: Be + Akku előfűtés: Ki + Első csomagtartó + Csomagtartó + Töltőcsatlakozó: Nyitva + Töltőcsatlakozó: Zárva + Tükrök: Behajtva + Tükrök: Kihajtva + Hátsó ventilátor: Be + Hátsó ventilátor: Ki + Tükördöntés váltása + Kesztyűtartó nyitása + + + Automatizálások + Ablaktörlők + Ablaktörlő ki + Az ablaktörlők automatikus kikapcsolva tartása + Klíma + Klíma bekapcsolva tartása + A klíma bekapcsolva marad, amikor kiszállsz az autóból. Az automatizálás a beállított idő letelte után, vagy amikor visszatérsz az autóhoz, leáll. + Leállítás ennyi idő után + Vezetés + Kick-down + Chill módról Standardra vált, amíg a gázpedál a küszöbérték fölött van lenyomva. Visszaáll, amikor felengeded. + Pedálküszöb + Többujjas infotainment-indító + Rendelj 3, 4 vagy 5 ujjas koppintást az infotainment képernyőn egy vezérlőhöz + ujj + művelet: + Eltávolítás + Indító hozzáadása + + + Klíma + Automatizálás + Vezető oldali beállított hőfok + Beállított hőfokok + Vezető + Utas + Beállítások + Bekapcsolás + Ventilátor + Légkondi + Belső keringetés + Klíma megtartása + Ki + Be + Előkondicionálás + Túlmelegedés-védelem (ventilátor) + Túlmelegedés-védelem + Auto + Keringetés + Friss levegő + Megtartás + Kutya mód + Kemping mód + + + Akkumulátor + Előfűtés + Töltöttségi szint + Energia + Hátralévő + Felhasználható + Teljes csomag + Tartalék + Teljesítmény + Teljesítmény + Max. kisütés + Max. rekuperáció + Akkucsomag + Feszültség + Áramerősség + Min. hőmérséklet + Max. hőmérséklet + + + A DashKit nem található + Nem sikerült csatlakozni a DashKithez + A DashKit nem fogadta el a párosítást. Nyisd meg az „Új eszköz párosítása” lehetőséget a DashPilot beállításaiban egy már párosított telefonon, majd próbáld újra. + A BLE-keresés sikertelen (hibakód: %1$d) + Nem sikerült elindítani a párosítást + A szolgáltatások felderítése sikertelen + A Bluetooth nem érhető el + A BLE-kereső nem érhető el + Hiányzó BLE-engedély + A keresés sikertelen: %1$s + Keresés megszakítva + + + A frissítési szerver nem érhető el + A letöltött firmware integritás-ellenőrzése sikertelen + A letöltés sikertelen: %1$s + A firmware-fájl üres + Az OTA-szolgáltatás nem található az eszközön + Az OTA-jellemzők nem találhatók + Nem sikerült bekapcsolni az OTA-értesítéseket + Az írás sikertelen (állapot: %1$d) + Váratlanul megszakadt a kapcsolat + Az eszköz hibát jelzett (0x%1$s) + diff --git a/dashpilot-android/app/src/main/res/values/strings.xml b/dashpilot-android/app/src/main/res/values/strings.xml index e86e7759..e78295b0 100644 --- a/dashpilot-android/app/src/main/res/values/strings.xml +++ b/dashpilot-android/app/src/main/res/values/strings.xml @@ -179,4 +179,136 @@ Couldn\'t remove the connection. Try again. Removing connection… Pairs another phone — separate from your Tesla connection. + + + Back + Cancel + OK + min + + + Pinned + Automations + Controls + Drive + Battery + Battery Temp + AC Temp + Odometer + Vehicle + Phone + + + Data source + Data source: connected + Data source: connecting… + WebSocket server + IP address + + + Controls + Connect to DashKit to send commands + Tip: long-press a control to pin it to the home screen + Pinned + Battery Preheat: On + Battery Preheat: Off + Frunk + Trunk + Charge Port: Open + Charge Port: Closed + Mirrors: Folded + Mirrors: Unfolded + Rear Fan: On + Rear Fan: Off + Toggle Mirror Dip + Open Glovebox + + + Automations + Wipers + Wiper Off + Keep wipers disabled automatically + Climate + Keep climate on + Keep the climate on when you leave the car. The automation stops after the set time, or when you return to the car. + Stop after + Driving + Kick-down + Switch from Chill to Standard while the accelerator is pressed past the threshold. Reverts when you ease off. + Pedal threshold + Multi-touch infotainment trigger + Bind 3-, 4-, or 5-finger infotainment taps to a control + fingers + action: + Remove + Add trigger + + + Climate + Automation + Driver setpoint + Setpoints + Driver + Passenger + Settings + Power + Fan + A/C + Recirculation + Keep climate + Off + On + Preconditioning + Overheat protection (fan) + Overheat protection + Auto + Recirculate + Fresh air + Keep + Dog mode + Camp mode + + + Battery + Preheat + State of charge + Energy + Remaining + Usable + Full Pack + Buffer + Power + Power + Max Discharge + Max Regen + Pack + Voltage + Current + Temp Min + Temp Max + + + DashKit not found + Could not connect to DashKit + DashKit did not accept pairing. Open \"Pair a new device\" in DashPilot settings on an already-paired phone, then try again. + BLE scan failed (error %1$d) + Could not start pairing + Service discovery failed + Bluetooth not available + BLE scanner not available + Missing BLE permission + Scan failed: %1$s + Discovery cancelled + + + Could not reach update server + Downloaded firmware failed integrity check + Download failed: %1$s + Firmware file is empty + OTA service not found on device + OTA characteristics not found + Failed to enable OTA notifications + Write failed (status %1$d) + Disconnected unexpectedly + Device reported error (0x%1$s) diff --git a/dashpilot-android/app/src/main/res/xml/locales_config.xml b/dashpilot-android/app/src/main/res/xml/locales_config.xml new file mode 100644 index 00000000..a9fde47d --- /dev/null +++ b/dashpilot-android/app/src/main/res/xml/locales_config.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/dashpilot-ios/dashpilot.xcodeproj/project.pbxproj b/dashpilot-ios/dashpilot.xcodeproj/project.pbxproj index 6419c9d7..8110f4e8 100644 --- a/dashpilot-ios/dashpilot.xcodeproj/project.pbxproj +++ b/dashpilot-ios/dashpilot.xcodeproj/project.pbxproj @@ -302,6 +302,7 @@ knownRegions = ( en, Base, + hu, ); mainGroup = 29FF82352F72C9C400D48E9A; minimizedProjectReferenceProxies = 1; diff --git a/dashpilot-ios/dashpilot/BLE/DashKitOtaUpdate.swift b/dashpilot-ios/dashpilot/BLE/DashKitOtaUpdate.swift index 7384c41b..2b0dd38e 100644 --- a/dashpilot-ios/dashpilot/BLE/DashKitOtaUpdate.swift +++ b/dashpilot-ios/dashpilot/BLE/DashKitOtaUpdate.swift @@ -60,7 +60,7 @@ final class DashKitOtaUpdate: DashKitGattListener { func start(firmware fw: Data) { guard !fw.isEmpty else { - setState(.error("Firmware file is empty")) + setState(.error(String(localized: "Firmware file is empty"))) return } firmware = fw @@ -115,7 +115,7 @@ final class DashKitOtaUpdate: DashKitGattListener { return } guard let service = peripheral.services?.first(where: { $0.uuid == DashKitGatt.otaService }) else { - setState(.error("OTA service not found on device")) + setState(.error(String(localized: "OTA service not found on device"))) return } self.peripheral = peripheral @@ -123,7 +123,7 @@ final class DashKitOtaUpdate: DashKitGattListener { dataChar = service.characteristics?.first { $0.uuid == DashKitGatt.otaDataCharacteristic } statusChar = service.characteristics?.first { $0.uuid == DashKitGatt.otaStatusCharacteristic } guard let statusChar, ctrlChar != nil, dataChar != nil else { - setState(.error("OTA characteristics not found")) + setState(.error(String(localized: "OTA characteristics not found"))) return } let canService = peripheral.services?.first { $0.uuid == DashKitGatt.canService } @@ -141,7 +141,7 @@ final class DashKitOtaUpdate: DashKitGattListener { func onNotificationStateUpdated(_ characteristic: CBCharacteristic, error: Error?) { guard characteristic.uuid == DashKitGatt.otaStatusCharacteristic else { return } if error != nil { - setState(.error("Failed to enable OTA notifications")) + setState(.error(String(localized: "Failed to enable OTA notifications"))) resumeCanNotifications() return } @@ -162,7 +162,7 @@ final class DashKitOtaUpdate: DashKitGattListener { return } if let error { - setState(.error("Write failed (\(error.localizedDescription))")) + setState(.error(String(localized: "Write failed (\(error.localizedDescription))"))) resumeCanNotifications() return } @@ -181,7 +181,7 @@ final class DashKitOtaUpdate: DashKitGattListener { rebooting = true setState(.rebooting) } else if !rebooting, state != .idle { - setState(.error("Disconnected unexpectedly")) + setState(.error(String(localized: "Disconnected unexpectedly"))) } manager.suppressPings = false firmware = nil @@ -258,7 +258,7 @@ final class DashKitOtaUpdate: DashKitGattListener { case 0xFF: let errCode = value.count > 1 ? value[1] : 0 print("[DashKitOta] OTA error from device: 0x\(String(errCode, radix: 16))") - setState(.error("Device reported error (0x\(String(errCode, radix: 16)))")) + setState(.error(String(localized: "Device reported error (0x\(String(errCode, radix: 16)))"))) manager.removeGattListener(self) manager.suppressPings = false uploadFinished = false diff --git a/dashpilot-ios/dashpilot/BLE/FirmwareUpdateManager.swift b/dashpilot-ios/dashpilot/BLE/FirmwareUpdateManager.swift index 286da0f1..f7aaade9 100644 --- a/dashpilot-ios/dashpilot/BLE/FirmwareUpdateManager.swift +++ b/dashpilot-ios/dashpilot/BLE/FirmwareUpdateManager.swift @@ -113,7 +113,7 @@ final class FirmwareUpdateManager { private func runCheck() async { check = .checking guard let manifest = await FirmwareUpdateRepository.fetchManifest() else { - check = .error("Could not reach update server") + check = .error(String(localized: "Could not reach update server")) return } var current = installedVersion @@ -140,13 +140,13 @@ final class FirmwareUpdateManager { !expected.isEmpty { let actual = SHA256.hash(data: bytes).map { String(format: "%02x", $0) }.joined() guard actual == expected else { - check = .error("Downloaded firmware failed integrity check") + check = .error(String(localized: "Downloaded firmware failed integrity check")) return } } ota.start(firmware: bytes) } catch { - check = .error("Download failed: \(error.localizedDescription)") + check = .error(String(localized: "Download failed: \(error.localizedDescription)")) } } diff --git a/dashpilot-ios/dashpilot/DataSource/DashKitBleManager.swift b/dashpilot-ios/dashpilot/DataSource/DashKitBleManager.swift index cafc38b9..2bab03bb 100644 --- a/dashpilot-ios/dashpilot/DataSource/DashKitBleManager.swift +++ b/dashpilot-ios/dashpilot/DataSource/DashKitBleManager.swift @@ -309,7 +309,7 @@ final class DashKitBleManager: NSObject { guard let self, let central = self.central, central.isScanning else { return } print("[DashKitBleManager] scan timed out without finding DashKit") self.stopScan() - self.retryOrFail("DashKit not found") + self.retryOrFail(String(localized: "DashKit not found")) } } @@ -334,10 +334,10 @@ extension DashKitBleManager: CBCentralManagerDelegate { startScan() } case .unauthorized: - setState(.error("Bluetooth permission denied")) + setState(.error(String(localized: "Bluetooth permission denied"))) case .poweredOff: if state == .connecting { - setState(.error("Bluetooth is off")) + setState(.error(String(localized: "Bluetooth is off"))) } default: break @@ -365,7 +365,7 @@ extension DashKitBleManager: CBCentralManagerDelegate { print("[DashKitBleManager] connect attempt timed out") self.central?.cancelPeripheralConnection(pending) self.peripheral = nil - self.retryOrFail("Could not connect to DashKit") + self.retryOrFail(String(localized: "Could not connect to DashKit")) } } @@ -385,7 +385,7 @@ extension DashKitBleManager: CBCentralManagerDelegate { connectTimeoutTask = nil peripheral = nil print("[DashKitBleManager] connect failed: \(error?.localizedDescription ?? "unknown")") - retryOrFail("Could not connect to DashKit") + retryOrFail(String(localized: "Could not connect to DashKit")) } func centralManager(_ central: CBCentralManager, @@ -407,7 +407,7 @@ extension DashKitBleManager: CBCentralManagerDelegate { // attempt itself failed. Retry a few times before surfacing an // error. print("[DashKitBleManager] link dropped before setup completed") - retryOrFail("Could not connect to DashKit") + retryOrFail(String(localized: "Could not connect to DashKit")) return } if ProcessInfo.processInfo.systemUptime < pairingWindowUntil { @@ -437,7 +437,7 @@ extension DashKitBleManager: CBCentralManagerDelegate { // rejecting this phone's pairing. iOS cannot delete a bond // programmatically, so stop flapping and tell the user what to do. print("[DashKitBleManager] repeated drops right after connect; giving up") - setState(.error("DashKit rejected this phone's pairing. If DashKit is paired with another phone, open \"Pair a new device\" in its DashPilot settings and try again. If this phone was paired before, forget \"DashKit\" in Settings > Bluetooth first.")) + setState(.error(String(localized: "DashKit rejected this phone's pairing. If DashKit is paired with another phone, open \"Pair a new device\" in its DashPilot settings and try again. If this phone was paired before, forget \"DashKit\" in Settings > Bluetooth first."))) forEachListener { $0.onDisconnected() } return } @@ -460,12 +460,12 @@ extension DashKitBleManager: CBPeripheralDelegate { func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { if let error { print("[DashKitBleManager] service discovery failed: \(error.localizedDescription)") - setState(.error("Service discovery failed")) + setState(.error(String(localized: "Service discovery failed"))) return } let services = peripheral.services ?? [] guard !services.isEmpty else { - setState(.error("Service discovery failed")) + setState(.error(String(localized: "Service discovery failed"))) return } for service in services { diff --git a/dashpilot-ios/dashpilot/InfoPlist.xcstrings b/dashpilot-ios/dashpilot/InfoPlist.xcstrings new file mode 100644 index 00000000..ef06fd44 --- /dev/null +++ b/dashpilot-ios/dashpilot/InfoPlist.xcstrings @@ -0,0 +1,16 @@ +{ + "sourceLanguage": "en", + "strings": { + "NSBluetoothAlwaysUsageDescription": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A DashPilot Bluetoothon keresztül csatlakozik a DashKithez, hogy élő járműadatokat jelenítsen meg és járműparancsokat küldjön." + } + } + } + } + }, + "version": "1.0" +} \ No newline at end of file diff --git a/dashpilot-ios/dashpilot/Localizable.xcstrings b/dashpilot-ios/dashpilot/Localizable.xcstrings new file mode 100644 index 00000000..6b653c4d --- /dev/null +++ b/dashpilot-ios/dashpilot/Localizable.xcstrings @@ -0,0 +1,1866 @@ +{ + "sourceLanguage": "en", + "strings": { + "Controls": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Vezérlők" + } + } + } + }, + "Battery": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Akkumulátor" + } + } + } + }, + "Climate": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Klíma" + } + } + } + }, + "Automations": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Automatizálások" + } + } + } + }, + "Settings": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Beállítások" + } + } + } + }, + "Pinned": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Rögzítve" + } + } + } + }, + "Drive": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Vezetés" + } + } + } + }, + "Battery Temp": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Akku hőmérséklet" + } + } + } + }, + "AC Temp": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Klíma hőfok" + } + } + } + }, + "Odometer": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Kilométer-számláló" + } + } + } + }, + "Data source: connected": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Adatforrás: csatlakozva" + } + } + } + }, + "Data source: connecting…": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Adatforrás: csatlakozás…" + } + } + } + }, + "Data source": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Adatforrás" + } + } + } + }, + "Disconnect": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Kapcsolat bontása" + } + } + } + }, + "Connect to DashKit to send commands": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A parancsok küldéséhez csatlakozz a DashKithez" + } + } + } + }, + "Tip: long-press a control to pin it to the home screen": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Tipp: nyomj hosszan egy vezérlőt, hogy a kezdőképernyőre rögzítsd" + } + } + } + }, + "Battery Preheat: On": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Akku előfűtés: Be" + } + } + } + }, + "Battery Preheat: Off": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Akku előfűtés: Ki" + } + } + } + }, + "Frunk": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Első csomagtartó" + } + } + } + }, + "Trunk": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Csomagtartó" + } + } + } + }, + "Charge Port: Open": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Töltőcsatlakozó: Nyitva" + } + } + } + }, + "Charge Port: Closed": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Töltőcsatlakozó: Zárva" + } + } + } + }, + "Mirrors: Folded": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Tükrök: Behajtva" + } + } + } + }, + "Mirrors: Unfolded": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Tükrök: Kihajtva" + } + } + } + }, + "Rear Fan: On": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Hátsó ventilátor: Be" + } + } + } + }, + "Rear Fan: Off": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Hátsó ventilátor: Ki" + } + } + } + }, + "Toggle Mirror Dip": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Tükördöntés váltása" + } + } + } + }, + "Open Glovebox": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Kesztyűtartó nyitása" + } + } + } + }, + "Preheat": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Előfűtés" + } + } + } + }, + "State of charge": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Töltöttségi szint" + } + } + } + }, + "Energy": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Energia" + } + } + } + }, + "Remaining": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Hátralévő" + } + } + } + }, + "Usable": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Felhasználható" + } + } + } + }, + "Full Pack": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Teljes csomag" + } + } + } + }, + "Buffer": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Tartalék" + } + } + } + }, + "Power": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Teljesítmény" + } + } + } + }, + "Max Discharge": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Max. kisütés" + } + } + } + }, + "Max Regen": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Max. rekuperáció" + } + } + } + }, + "Pack": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Akkucsomag" + } + } + } + }, + "Voltage": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Feszültség" + } + } + } + }, + "Current": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Áramerősség" + } + } + } + }, + "Temp Min": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Min. hőmérséklet" + } + } + } + }, + "Temp Max": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Max. hőmérséklet" + } + } + } + }, + "Automation": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Automatizálás" + } + } + } + }, + "Keep climate on": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Klíma bekapcsolva tartása" + } + } + } + }, + "Keep the climate on when you leave the car. The automation stops after the set time, or when you return to the car.": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A klíma bekapcsolva marad, amikor kiszállsz az autóból. Az automatizálás a beállított idő letelte után, vagy amikor visszatérsz az autóhoz, leáll." + } + } + } + }, + "Stop after": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Leállítás ennyi idő után" + } + } + } + }, + "min": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "perc" + } + } + } + }, + "Setpoints": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Beállított hőfokok" + } + } + } + }, + "Driver": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Vezető" + } + } + } + }, + "Passenger": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Utas" + } + } + } + }, + "Fan": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Ventilátor" + } + } + } + }, + "A/C": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Légkondi" + } + } + } + }, + "Recirculation": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Belső keringetés" + } + } + } + }, + "Keep climate": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Klíma megtartása" + } + } + } + }, + "Driver setpoint": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Vezető oldali beállított hőfok" + } + } + } + }, + "Off": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Ki" + } + } + } + }, + "On": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Be" + } + } + } + }, + "Preconditioning": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Előkondicionálás" + } + } + } + }, + "Overheat protection (fan)": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Túlmelegedés-védelem (ventilátor)" + } + } + } + }, + "Overheat protection": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Túlmelegedés-védelem" + } + } + } + }, + "Auto": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Auto" + } + } + } + }, + "Recirculate": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Keringetés" + } + } + } + }, + "Fresh air": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Friss levegő" + } + } + } + }, + "Keep": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Megtartás" + } + } + } + }, + "Dog mode": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Kutya mód" + } + } + } + }, + "Camp mode": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Kemping mód" + } + } + } + }, + "Wipers": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Ablaktörlők" + } + } + } + }, + "Wiper Off": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Ablaktörlő ki" + } + } + } + }, + "Keep wipers disabled automatically": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Az ablaktörlők automatikus kikapcsolva tartása" + } + } + } + }, + "Driving": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Vezetés" + } + } + } + }, + "Kick-down": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Kick-down" + } + } + } + }, + "Switch from Chill to Standard while the accelerator is pressed past the threshold. Reverts when you ease off.": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Chill módról Standardra vált, amíg a gázpedál a küszöbérték fölött van lenyomva. Visszaáll, amikor felengeded." + } + } + } + }, + "Pedal threshold": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Pedálküszöb" + } + } + } + }, + "Multi-touch infotainment trigger": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Többujjas infotainment-indító" + } + } + } + }, + "Bind 3-, 4-, or 5-finger infotainment taps to a control": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Rendelj 3, 4 vagy 5 ujjas koppintást az infotainment képernyőn egy vezérlőhöz" + } + } + } + }, + "fingers": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "ujj" + } + } + } + }, + "action:": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "művelet:" + } + } + } + }, + "Add trigger": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Indító hozzáadása" + } + } + } + }, + "Vanilla Dashboard": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Vanilla műszerfal" + } + } + } + }, + "Ambient Dashboard": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Ambient műszerfal" + } + } + } + }, + "Analog Dashboard": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Analóg műszerfal" + } + } + } + }, + "Retro Dashboard": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Retro műszerfal" + } + } + } + }, + "Load Rive File": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Rive fájl betöltése" + } + } + } + }, + "Choose a dashboard": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Válassz műszerfalat" + } + } + } + }, + "Some settings depend on the selected theme": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Egyes beállítások a kiválasztott témától függenek" + } + } + } + }, + "Dashboard Theme": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Műszerfal témája" + } + } + } + }, + "Unsupported dashboard type: %@": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Nem támogatott műszerfaltípus: %@" + } + } + } + }, + "General": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Általános" + } + } + } + }, + "Connect to a DashKit device to manage it.": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A kezeléshez csatlakozz egy DashKit eszközhöz." + } + } + } + }, + "Dashboard": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Műszerfal" + } + } + } + }, + "Configuration": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Konfiguráció" + } + } + } + }, + "Extra Vehicle Bus": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Extra járműbusz" + } + } + } + }, + "Display": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Megjelenítés" + } + } + } + }, + "Show Car Battery": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Autó akkumulátorának mutatása" + } + } + } + }, + "Show Odometer": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Kilométer-számláló mutatása" + } + } + } + }, + "Use Imperial Units": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Angolszász mértékegységek" + } + } + } + }, + "Show Phone Battery": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Telefon akkumulátorának mutatása" + } + } + } + }, + "Dark Mode": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Sötét mód" + } + } + } + }, + "3D Visualizer": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "3D megjelenítő" + } + } + } + }, + "Always On Blind-Spot Monitor": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Mindig bekapcsolt holttérfigyelő" + } + } + } + }, + "Render Quality": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Renderelési minőség" + } + } + } + }, + "Low": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Alacsony" + } + } + } + }, + "Med": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Közepes" + } + } + } + }, + "High": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Magas" + } + } + } + }, + "Replay onboarding": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Bevezető újranézése" + } + } + } + }, + "Start Demo Mode": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Demó mód indítása" + } + } + } + }, + "Version": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Verzió" + } + } + } + }, + "Connect your comma device": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Csatlakozás a comma eszközhöz" + } + } + } + }, + "Connecting to %@...": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Csatlakozás ehhez: %@..." + } + } + } + }, + "Searching for device...": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Eszköz keresése..." + } + } + } + }, + "Connected to %@": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Csatlakozva ehhez: %@" + } + } + } + }, + "Connect": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Csatlakozás" + } + } + } + }, + "Enter IP manually": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "IP-cím megadása kézzel" + } + } + } + }, + "Device IP": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Eszköz IP-címe" + } + } + } + }, + "Cancel": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Mégse" + } + } + } + }, + "Connecting...": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Csatlakozás..." + } + } + } + }, + "Next": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Tovább" + } + } + } + }, + "Could not find device on the network": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Az eszköz nem található a hálózaton" + } + } + } + }, + "Pair a new device?": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Párosítasz egy új eszközt?" + } + } + } + }, + "Open pairing": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Párosítás megnyitása" + } + } + } + }, + "DashKit is open for pairing. Pair the new phone within 2 minutes.": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A DashKit párosításra kész. Párosítsd az új telefont 2 percen belül." + } + } + } + }, + "Connect to DashKit first to pair a new device": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Új eszköz párosításához előbb csatlakozz a DashKithez" + } + } + } + }, + "DashKit will allow one new device to pair for the next 2 minutes. Open DashPilot on the other phone and pair it now.": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A DashKit a következő 2 percben egy új eszköz párosítását engedélyezi. Nyisd meg a DashPilotot a másik telefonon, és párosítsd most." + } + } + } + }, + "Reboot DashKit?": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Újraindítod a DashKitet?" + } + } + } + }, + "Reboot": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Újraindítás" + } + } + } + }, + "Reboot command sent. DashKit is restarting.": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Újraindítási parancs elküldve. A DashKit újraindul." + } + } + } + }, + "Could not send reboot command.": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Nem sikerült elküldeni az újraindítási parancsot." + } + } + } + }, + "DashKit will restart and briefly disconnect. It should reconnect automatically once it is back up.": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A DashKit újraindul, és rövid időre megszakad a kapcsolat. Amint újra elindult, automatikusan újracsatlakozik." + } + } + } + }, + "Firmware info": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Firmware adatai" + } + } + } + }, + "Status": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Állapot" + } + } + } + }, + "Connected": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Csatlakozva" + } + } + } + }, + "Disconnected": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Nincs kapcsolat" + } + } + } + }, + "Firmware version": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Firmware verzió" + } + } + } + }, + "Unknown": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Ismeretlen" + } + } + } + }, + "Pairing": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Párosítás" + } + } + } + }, + "Pair a new device": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Új eszköz párosítása" + } + } + } + }, + "Maintenance": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Karbantartás" + } + } + } + }, + "Reboot DashKit": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "DashKit újraindítása" + } + } + } + }, + "Firmware": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Firmware" + } + } + } + }, + "Downloading firmware…": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Firmware letöltése…" + } + } + } + }, + "Checking for updates…": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Frissítések keresése…" + } + } + } + }, + "DashKit firmware is up to date": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A DashKit firmware naprakész" + } + } + } + }, + "Version %@ is available": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Elérhető a(z) %@ verzió" + } + } + } + }, + "Install update": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Frissítés telepítése" + } + } + } + }, + "Update failed: %@": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A frissítés sikertelen: %@" + } + } + } + }, + "Connecting…": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Csatlakozás…" + } + } + } + }, + "Uploading firmware… %d%%": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Firmware feltöltése… %d%%" + } + } + } + }, + "Update complete! Rebooting DashKit…": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Frissítés kész! A DashKit újraindul…" + } + } + } + }, + "Update DashKit Firmware": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "DashKit firmware frissítése" + } + } + } + }, + "Pair your DashKit": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Párosítsd a DashKitet" + } + } + } + }, + "Looking for DashKit…": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "DashKit keresése…" + } + } + } + }, + "You're all set!": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Minden készen áll!" + } + } + } + }, + "Couldn't pair": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Nem sikerült párosítani" + } + } + } + }, + "Plug the DashKit into your car's debug port, then tap below to pair over Bluetooth.": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Csatlakoztasd a DashKitet az autó diagnosztikai portjához, majd koppints alul a Bluetooth-párosításhoz." + } + } + } + }, + "Hold the device close to your phone. This usually takes a few seconds.": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Tartsd az eszközt a telefon közelében. Ez általában néhány másodpercet vesz igénybe." + } + } + } + }, + "DashKit is connected and ready to stream data to your dashboard.": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A DashKit csatlakozva van, és készen áll az adatok küldésére a műszerfalra." + } + } + } + }, + "If this DashKit is already paired with another phone, open DashPilot on that phone and tap Settings → DashKit → Pair a new device, then try again.": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Ha ez a DashKit már párosítva van egy másik telefonnal, nyisd meg a DashPilotot azon a telefonon, és koppints a Beállítások → DashKit → Új eszköz párosítása lehetőségre, majd próbáld újra." + } + } + } + }, + "Pair device": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Eszköz párosítása" + } + } + } + }, + "Pairing…": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Párosítás…" + } + } + } + }, + "Continue": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Folytatás" + } + } + } + }, + "Retry": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Újra" + } + } + } + }, + "One more thing": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Még valami" + } + } + } + }, + "You can pair additional devices and install firmware updates anytime from Settings.": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "További eszközöket párosíthatsz és firmware-frissítéseket telepíthetsz bármikor a Beállításokból." + } + } + } + }, + "Pair more DashKit devices": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "További DashKit eszközök párosítása" + } + } + } + }, + "Check for firmware updates": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Firmware-frissítések keresése" + } + } + } + }, + "Get started": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Kezdjük" + } + } + } + }, + "Setup": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Beállítás" + } + } + } + }, + "Skip": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Kihagyás" + } + } + } + }, + "%lld of %lld": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "%lld / %lld" + } + } + } + }, + "DashKit not found": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A DashKit nem található" + } + } + } + }, + "Could not connect to DashKit": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Nem sikerült csatlakozni a DashKithez" + } + } + } + }, + "Bluetooth permission denied": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A Bluetooth-engedély megtagadva" + } + } + } + }, + "Bluetooth is off": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A Bluetooth ki van kapcsolva" + } + } + } + }, + "DashKit rejected this phone's pairing. If DashKit is paired with another phone, open \"Pair a new device\" in its DashPilot settings and try again. If this phone was paired before, forget \"DashKit\" in Settings > Bluetooth first.": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A DashKit elutasította a telefon párosítását. Ha a DashKit egy másik telefonnal van párosítva, nyisd meg azon a DashPilot beállításaiban az „Új eszköz párosítása” lehetőséget, és próbáld újra. Ha ez a telefon korábban már párosítva volt, előbb felejtsd el a „DashKit” eszközt a Beállítások > Bluetooth menüben." + } + } + } + }, + "Service discovery failed": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A szolgáltatások felderítése sikertelen" + } + } + } + }, + "Could not reach update server": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A frissítési szerver nem érhető el" + } + } + } + }, + "Downloaded firmware failed integrity check": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A letöltött firmware integritás-ellenőrzése sikertelen" + } + } + } + }, + "Download failed: %@": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A letöltés sikertelen: %@" + } + } + } + }, + "Firmware file is empty": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "A firmware-fájl üres" + } + } + } + }, + "OTA service not found on device": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Az OTA-szolgáltatás nem található az eszközön" + } + } + } + }, + "OTA characteristics not found": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Az OTA-jellemzők nem találhatók" + } + } + } + }, + "Failed to enable OTA notifications": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Nem sikerült bekapcsolni az OTA-értesítéseket" + } + } + } + }, + "Write failed (%@)": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Az írás sikertelen (%@)" + } + } + } + }, + "Disconnected unexpectedly": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Váratlanul megszakadt a kapcsolat" + } + } + } + }, + "Device reported error (0x%@)": { + "localizations": { + "hu": { + "stringUnit": { + "state": "translated", + "value": "Az eszköz hibát jelzett (0x%@)" + } + } + } + } + }, + "version": "1.0" +} \ No newline at end of file diff --git a/dashpilot-ios/dashpilot/Models/DashboardConfig.swift b/dashpilot-ios/dashpilot/Models/DashboardConfig.swift index 3c500379..6acdd580 100644 --- a/dashpilot-ios/dashpilot/Models/DashboardConfig.swift +++ b/dashpilot-ios/dashpilot/Models/DashboardConfig.swift @@ -18,35 +18,35 @@ struct DashboardConfig: Identifiable { let availableDashboards: [DashboardConfig] = [ DashboardConfig( id: "vanilla", - name: "Vanilla Dashboard", + name: String(localized: "Vanilla Dashboard"), url: "vanilla", type: .web, screenshotName: "preview_vanilla" ), DashboardConfig( id: "ambient", - name: "Ambient Dashboard", + name: String(localized: "Ambient Dashboard"), url: "ambient", type: .web, screenshotName: "preview_ambient" ), DashboardConfig( id: "analog", - name: "Analog Dashboard", + name: String(localized: "Analog Dashboard"), url: "analog", type: .web, screenshotName: "preview_analog" ), DashboardConfig( id: "retro", - name: "Retro Dashboard", + name: String(localized: "Retro Dashboard"), url: "retro", type: .web, screenshotName: "preview_retro" ), DashboardConfig( id: "dev_rive", - name: "Load Rive File", + name: String(localized: "Load Rive File"), url: "", type: .devRive, screenshotName: nil diff --git a/dashpilot-ios/dashpilot/Models/VehicleControls.swift b/dashpilot-ios/dashpilot/Models/VehicleControls.swift index 963d058c..0b99ebac 100644 --- a/dashpilot-ios/dashpilot/Models/VehicleControls.swift +++ b/dashpilot-ios/dashpilot/Models/VehicleControls.swift @@ -43,7 +43,7 @@ let vehicleControls: [ControlAction] = [ ControlAction( id: "battery_preheat", icon: "thermometer", - label: { ControlsState.shared.preheatOn ? "Battery Preheat: On" : "Battery Preheat: Off" }, + label: { ControlsState.shared.preheatOn ? String(localized: "Battery Preheat: On") : String(localized: "Battery Preheat: Off") }, active: { ControlsState.shared.preheatOn }, gestureValue: 2, perform: { manager in @@ -57,7 +57,7 @@ let vehicleControls: [ControlAction] = [ ControlAction( id: "frunk", icon: "car.fill", - label: { "Frunk" }, + label: { String(localized: "Frunk") }, active: { false }, gestureValue: 4, perform: { manager in @@ -68,7 +68,7 @@ let vehicleControls: [ControlAction] = [ ControlAction( id: "trunk", icon: "shippingbox.fill", - label: { "Trunk" }, + label: { String(localized: "Trunk") }, active: { false }, gestureValue: 5, perform: { manager in @@ -79,7 +79,7 @@ let vehicleControls: [ControlAction] = [ ControlAction( id: "charge_port", icon: "bolt.car.fill", - label: { ControlsState.shared.chargePortOpen ? "Charge Port: Open" : "Charge Port: Closed" }, + label: { ControlsState.shared.chargePortOpen ? String(localized: "Charge Port: Open") : String(localized: "Charge Port: Closed") }, active: { ControlsState.shared.chargePortOpen }, gestureValue: 6, perform: { manager in @@ -94,7 +94,7 @@ let vehicleControls: [ControlAction] = [ ControlAction( id: "mirror_fold", icon: "arrow.left.arrow.right", - label: { ControlsState.shared.mirrorsFolded ? "Mirrors: Folded" : "Mirrors: Unfolded" }, + label: { ControlsState.shared.mirrorsFolded ? String(localized: "Mirrors: Folded") : String(localized: "Mirrors: Unfolded") }, active: { ControlsState.shared.mirrorsFolded }, gestureValue: 3, perform: { manager in @@ -110,7 +110,7 @@ let vehicleControls: [ControlAction] = [ ControlAction( id: "rear_fan", icon: "wind", - label: { ControlsState.shared.rearFanOn ? "Rear Fan: On" : "Rear Fan: Off" }, + label: { ControlsState.shared.rearFanOn ? String(localized: "Rear Fan: On") : String(localized: "Rear Fan: Off") }, active: { ControlsState.shared.rearFanOn }, gestureValue: 7, perform: { manager in @@ -124,7 +124,7 @@ let vehicleControls: [ControlAction] = [ ControlAction( id: "mirror_dip", icon: "arrow.down.right", - label: { "Toggle Mirror Dip" }, + label: { String(localized: "Toggle Mirror Dip") }, active: { false }, gestureValue: 8, perform: { manager in @@ -136,7 +136,7 @@ let vehicleControls: [ControlAction] = [ ControlAction( id: "glovebox", icon: "tray.fill", - label: { "Open Glovebox" }, + label: { String(localized: "Open Glovebox") }, active: { false }, gestureValue: 1, perform: { manager in diff --git a/dashpilot-ios/dashpilot/UI/AutomationsView.swift b/dashpilot-ios/dashpilot/UI/AutomationsView.swift index 58c367f6..9685c5e6 100644 --- a/dashpilot-ios/dashpilot/UI/AutomationsView.swift +++ b/dashpilot-ios/dashpilot/UI/AutomationsView.swift @@ -77,7 +77,7 @@ struct AutomationsView: View { if climateKeep { ValuePickerFooter( label: "Stop after", - unit: "min", + unit: String(localized: "min"), options: Array(climateKeepMinuteRange), value: $climateKeepMinutes, expanded: $minutesWheelExpanded @@ -281,9 +281,9 @@ struct AutomationsView: View { /// Small muted section heading (Android `SectionLabel`). private struct SectionLabel: View { - let text: String + let text: LocalizedStringKey - init(_ text: String) { + init(_ text: LocalizedStringKey) { self.text = text } @@ -301,15 +301,15 @@ private struct SectionLabel: View { /// an optional footer rendered inside the same card (Android `AutomationRow`). struct AutomationRow: View { let icon: String - let title: String - let subtitle: String? + let title: LocalizedStringKey + let subtitle: LocalizedStringKey? @Binding var isOn: Bool let footer: Footer init( icon: String, - title: String, - subtitle: String?, + title: LocalizedStringKey, + subtitle: LocalizedStringKey?, isOn: Binding, @ViewBuilder footer: () -> Footer ) { @@ -360,7 +360,7 @@ struct AutomationRow: View { } extension AutomationRow where Footer == EmptyView { - init(icon: String, title: String, subtitle: String?, isOn: Binding) { + init(icon: String, title: LocalizedStringKey, subtitle: LocalizedStringKey?, isOn: Binding) { self.init(icon: icon, title: title, subtitle: subtitle, isOn: isOn) { EmptyView() } } } @@ -370,7 +370,7 @@ extension AutomationRow where Footer == EmptyView { /// "Label N unit" line inside an automation card; tapping the value expands a /// wheel over `options` (Android `NumberPickerFooter`). struct ValuePickerFooter: View { - let label: String + let label: LocalizedStringKey let unit: String let options: [Int] @Binding var value: Int diff --git a/dashpilot-ios/dashpilot/UI/BatteryView.swift b/dashpilot-ios/dashpilot/UI/BatteryView.swift index fcf92d05..67725a65 100644 --- a/dashpilot-ios/dashpilot/UI/BatteryView.swift +++ b/dashpilot-ios/dashpilot/UI/BatteryView.swift @@ -116,7 +116,7 @@ struct BatteryView: View { // MARK: - Sections - private func section(_ title: String, rows: [(String, String)]) -> some View { + private func section(_ title: LocalizedStringKey, rows: [(LocalizedStringKey, String)]) -> some View { VStack(alignment: .leading, spacing: 8) { Text(title) .foregroundColor(.dashTextMuted) diff --git a/dashpilot-ios/dashpilot/UI/ClimateView.swift b/dashpilot-ios/dashpilot/UI/ClimateView.swift index a1f8c8d0..4c3397b8 100644 --- a/dashpilot-ios/dashpilot/UI/ClimateView.swift +++ b/dashpilot-ios/dashpilot/UI/ClimateView.swift @@ -43,7 +43,7 @@ struct ClimateView: View { if climateKeep { ValuePickerFooter( label: "Stop after", - unit: "min", + unit: String(localized: "min"), options: Array(climateKeepMinuteRange), value: $climateKeepMinutes, expanded: $minutesWheelExpanded @@ -135,13 +135,13 @@ struct ClimateView: View { // MARK: - Sections - private func sectionTitle(_ title: String) -> some View { + private func sectionTitle(_ title: LocalizedStringKey) -> some View { Text(title) .foregroundColor(.dashTextMuted) .font(.system(size: 13, weight: .semibold)) } - private func section(_ title: String, rows: [(String, String)]) -> some View { + private func section(_ title: LocalizedStringKey, rows: [(LocalizedStringKey, String)]) -> some View { VStack(alignment: .leading, spacing: 8) { sectionTitle(title) VStack(spacing: 0) { @@ -171,10 +171,16 @@ struct ClimateView: View { // MARK: - Formatters - private static let powerLabels = ["Off", "On", "Preconditioning", "Overheat protection (fan)", "Overheat protection"] - private static let acLabels = ["Auto", "Off", "On"] - private static let recircLabels = ["Auto", "Recirculate", "Fresh air"] - private static let keepLabels = ["Off", "Keep", "Dog mode", "Camp mode"] + private static let powerLabels = [ + String(localized: "Off"), + String(localized: "On"), + String(localized: "Preconditioning"), + String(localized: "Overheat protection (fan)"), + String(localized: "Overheat protection") + ] + private static let acLabels = [String(localized: "Auto"), String(localized: "Off"), String(localized: "On")] + private static let recircLabels = [String(localized: "Auto"), String(localized: "Recirculate"), String(localized: "Fresh air")] + private static let keepLabels = [String(localized: "Off"), String(localized: "Keep"), String(localized: "Dog mode"), String(localized: "Camp mode")] private func setpointText(_ value: Float?) -> String { guard let value, value != 0 else { return "—" } @@ -194,8 +200,8 @@ struct ClimateView: View { private func fanText(_ value: Float?) -> String { guard live, let value else { return "—" } switch Int(value.rounded()) { - case 0: return "Off" - case 11: return "Auto" + case 0: return String(localized: "Off") + case 11: return String(localized: "Auto") case 1...10: return "\(Int(value.rounded()))" default: return "—" } diff --git a/dashpilot-ios/dashpilot/UI/Components.swift b/dashpilot-ios/dashpilot/UI/Components.swift index 8d8cc6c9..60ad9821 100644 --- a/dashpilot-ios/dashpilot/UI/Components.swift +++ b/dashpilot-ios/dashpilot/UI/Components.swift @@ -4,7 +4,7 @@ import SwiftUI /// centered on the screen — mirrors the home screen header so all top-level /// screens line up (port of Android `ScreenHeader`). struct ScreenHeader: View { - let title: String + let title: LocalizedStringKey let onBack: () -> Void var body: some View { diff --git a/dashpilot-ios/dashpilot/UI/DashKitSettingsView.swift b/dashpilot-ios/dashpilot/UI/DashKitSettingsView.swift index 735f2d6b..fc3acc11 100644 --- a/dashpilot-ios/dashpilot/UI/DashKitSettingsView.swift +++ b/dashpilot-ios/dashpilot/UI/DashKitSettingsView.swift @@ -39,8 +39,8 @@ struct DashKitSettingsView: View { Button("Open pairing") { let ok = VehicleControl.sendEnterPairing(bleManager) pairStatus = ok - ? "DashKit is open for pairing. Pair the new phone within 2 minutes." - : "Connect to DashKit first to pair a new device" + ? String(localized: "DashKit is open for pairing. Pair the new phone within 2 minutes.") + : String(localized: "Connect to DashKit first to pair a new device") } Button("Cancel", role: .cancel) {} } message: { @@ -50,8 +50,8 @@ struct DashKitSettingsView: View { Button("Reboot") { let ok = VehicleControl.sendReboot(bleManager) rebootStatus = ok - ? "Reboot command sent. DashKit is restarting." - : "Could not send reboot command." + ? String(localized: "Reboot command sent. DashKit is restarting.") + : String(localized: "Could not send reboot command.") } Button("Cancel", role: .cancel) {} } message: { @@ -64,8 +64,8 @@ struct DashKitSettingsView: View { private var firmwareInfoSection: some View { VStack(alignment: .leading, spacing: 8) { SectionHeader("Firmware info") - InfoRow(label: "Status", value: connected ? "Connected" : "Disconnected") - InfoRow(label: "Firmware version", value: updateManager.installedVersion ?? "Unknown") + InfoRow(label: "Status", value: connected ? String(localized: "Connected") : String(localized: "Disconnected")) + InfoRow(label: "Firmware version", value: updateManager.installedVersion ?? String(localized: "Unknown")) } } @@ -180,7 +180,7 @@ private struct FirmwareUpdateSection: View { .foregroundColor(mutedText) .font(.system(size: 14)) case .uploading(let progress): - Text("Uploading firmware… \(Int(progress * 100))%") + Text(String(format: String(localized: "Uploading firmware… %d%%"), Int(progress * 100))) .foregroundColor(.white) .font(.system(size: 14)) ProgressView(value: progress) @@ -203,9 +203,9 @@ private struct FirmwareUpdateSection: View { // MARK: - Shared pieces private struct SectionHeader: View { - let title: String + let title: LocalizedStringKey - init(_ title: String) { + init(_ title: LocalizedStringKey) { self.title = title } @@ -217,7 +217,7 @@ private struct SectionHeader: View { } private struct InfoRow: View { - let label: String + let label: LocalizedStringKey let value: String var body: some View { @@ -235,7 +235,7 @@ private struct InfoRow: View { } private struct WideButton: View { - let label: String + let label: LocalizedStringKey let enabled: Bool let action: () -> Void diff --git a/dashpilot-ios/dashpilot/UI/HomeView.swift b/dashpilot-ios/dashpilot/UI/HomeView.swift index b8766b20..751f06fb 100644 --- a/dashpilot-ios/dashpilot/UI/HomeView.swift +++ b/dashpilot-ios/dashpilot/UI/HomeView.swift @@ -311,7 +311,7 @@ private struct DataSourceMenu: View { } } - private var dataSourceLabel: String { + private var dataSourceLabel: LocalizedStringKey { switch connectionVM.connectionStatus { case .connected: return "Data source: connected" case .connecting: return "Data source: connecting…" @@ -326,7 +326,7 @@ private struct DataSourceMenu: View { private struct InfoWidget: View { let icon: String - let label: String + let label: LocalizedStringKey let value: String var fillHeight: Bool = false @@ -370,7 +370,7 @@ private struct InfoWidget: View { /// and the label at the bottom, sized to match the stat tiles beside it. private struct ActionTile: View { - let label: String + let label: LocalizedStringKey let icon: String let action: () -> Void @@ -400,7 +400,7 @@ private struct ActionTile: View { /// green accent background; otherwise the standard dark surface. private struct ActionButton: View { - let label: String + let label: LocalizedStringKey let icon: String var accent: Bool = false let action: () -> Void diff --git a/dashpilot-ios/dashpilot/UI/Onboarding/OnboardingPageScaffold.swift b/dashpilot-ios/dashpilot/UI/Onboarding/OnboardingPageScaffold.swift index 147adc44..c9dedf07 100644 --- a/dashpilot-ios/dashpilot/UI/Onboarding/OnboardingPageScaffold.swift +++ b/dashpilot-ios/dashpilot/UI/Onboarding/OnboardingPageScaffold.swift @@ -26,8 +26,8 @@ enum OnboardingStyle { /// anchor mid-screen, optional extra content sits between subtitle and CTA, /// and the primary CTA pins to the bottom. struct OnboardingPageScaffold: View { - let title: String - let subtitle: String + let title: LocalizedStringKey + let subtitle: LocalizedStringKey @ViewBuilder let hero: Hero @ViewBuilder let extra: Extra @ViewBuilder let cta: Cta @@ -68,7 +68,7 @@ struct OnboardingPageScaffold: View { /// Full-width accent CTA button (port of the Android `PrimaryCta`). struct OnboardingPrimaryButton: View { - let label: String + let label: LocalizedStringKey var systemImage: String? = nil var showSpinner = false var enabled = true diff --git a/dashpilot-ios/dashpilot/UI/Onboarding/OnboardingPairingPage.swift b/dashpilot-ios/dashpilot/UI/Onboarding/OnboardingPairingPage.swift index f8da76c1..577a5cf4 100644 --- a/dashpilot-ios/dashpilot/UI/Onboarding/OnboardingPairingPage.swift +++ b/dashpilot-ios/dashpilot/UI/Onboarding/OnboardingPairingPage.swift @@ -56,7 +56,7 @@ struct OnboardingPairingPage: View { } } - private var title: String { + private var title: LocalizedStringKey { switch state { case .idle: return "Pair your DashKit" case .searching: return "Looking for DashKit…" @@ -65,7 +65,7 @@ struct OnboardingPairingPage: View { } } - private var subtitle: String { + private var subtitle: LocalizedStringKey { switch state { case .idle: return "Plug the DashKit into your car's debug port, then tap below to pair over Bluetooth." @@ -74,12 +74,11 @@ struct OnboardingPairingPage: View { case .paired: return "DashKit is connected and ready to stream data to your dashboard." case .failed: - return "If this DashKit is already paired with another phone, open DashPilot " - + "on that phone and tap Settings → DashKit → Pair a new device, then try again." + return "If this DashKit is already paired with another phone, open DashPilot on that phone and tap Settings → DashKit → Pair a new device, then try again." } } - private var ctaLabel: String { + private var ctaLabel: LocalizedStringKey { switch state { case .idle: return "Pair device" case .searching: return "Pairing…" diff --git a/dashpilot-ios/dashpilot/UI/Onboarding/OnboardingTipsPage.swift b/dashpilot-ios/dashpilot/UI/Onboarding/OnboardingTipsPage.swift index 3c5f8f04..9027810e 100644 --- a/dashpilot-ios/dashpilot/UI/Onboarding/OnboardingTipsPage.swift +++ b/dashpilot-ios/dashpilot/UI/Onboarding/OnboardingTipsPage.swift @@ -29,7 +29,7 @@ struct OnboardingTipsPage: View { private struct TipRow: View { let systemImage: String - let text: String + let text: LocalizedStringKey var body: some View { HStack(spacing: 12) { diff --git a/dashpilot-ios/dashpilot/UI/SettingsView.swift b/dashpilot-ios/dashpilot/UI/SettingsView.swift index 91f861c8..c5bab6e3 100644 --- a/dashpilot-ios/dashpilot/UI/SettingsView.swift +++ b/dashpilot-ios/dashpilot/UI/SettingsView.swift @@ -107,9 +107,11 @@ struct SettingsView: View { // MARK: - Tabs + private static let tabTitles: [LocalizedStringKey] = ["General", "DashKit"] + private var tabRow: some View { HStack(spacing: 0) { - ForEach(Array(["General", "DashKit"].enumerated()), id: \.offset) { index, title in + ForEach(Array(Self.tabTitles.enumerated()), id: \.offset) { index, title in Button { selectedTab = index } label: { @@ -324,7 +326,7 @@ struct SettingsView: View { // MARK: - Helpers - private func sectionTitle(_ title: String) -> some View { + private func sectionTitle(_ title: LocalizedStringKey) -> some View { Text(title) .foregroundColor(mutedText) .font(.system(size: 16, weight: .medium)) @@ -336,7 +338,7 @@ struct SettingsView: View { // MARK: - Toggle Row private struct SettingsToggleRow: View { - let label: String + let label: LocalizedStringKey @Binding var isOn: Bool var body: some View { @@ -358,7 +360,7 @@ private struct SettingsToggleRow: View { private struct RenderQualityPicker: View { @Binding var selected: Int - private let options: [(Int, String)] = [(1, "Low"), (2, "Med"), (3, "High")] + private let options: [(Int, LocalizedStringKey)] = [(1, "Low"), (2, "Med"), (3, "High")] private let accent = Color(red: 0x5C / 255.0, green: 0xBD / 255.0, blue: 0x68 / 255.0) var body: some View { diff --git a/dashpilot-ios/dashpilot/UI/SetupView.swift b/dashpilot-ios/dashpilot/UI/SetupView.swift index e8b3b5b1..f1ad8d5b 100644 --- a/dashpilot-ios/dashpilot/UI/SetupView.swift +++ b/dashpilot-ios/dashpilot/UI/SetupView.swift @@ -127,7 +127,7 @@ struct SetupView: View { .frame(maxWidth: .infinity) } - private func statusText(_ text: String) -> some View { + private func statusText(_ text: LocalizedStringKey) -> some View { Text(text) .foregroundColor(Color(white: 0.53)) .font(.system(size: 14)) @@ -213,14 +213,15 @@ struct SetupView: View { } private func nextButton(isConnecting: Bool) -> some View { - Button { + let label: LocalizedStringKey = isConnecting ? "Connecting..." : "Next" + return Button { if let ip = connectionVM.discoveredAddress { UserDefaults.standard.set(ip, forKey: "device_ip") } let dash = selectedDashboard() navigationPath.append(AppRoute.dashboard(type: dash.type.rawValue, url: dash.url)) } label: { - Text(isConnecting ? "Connecting..." : "Next") + Text(label) .font(.system(size: 16, weight: .semibold)) .foregroundColor(isConnecting ? Color(white: 0.67) : .black) .frame(maxWidth: .infinity) diff --git a/dashpilot-ios/dashpilot/ViewModel/ConnectionViewModel.swift b/dashpilot-ios/dashpilot/ViewModel/ConnectionViewModel.swift index a090131a..df17c528 100644 --- a/dashpilot-ios/dashpilot/ViewModel/ConnectionViewModel.swift +++ b/dashpilot-ios/dashpilot/ViewModel/ConnectionViewModel.swift @@ -198,7 +198,7 @@ final class ConnectionViewModel { guard !Task.isCancelled, let ip = foundIp else { if !Task.isCancelled { - self.discoveryError = "Could not find device on the network" + self.discoveryError = String(localized: "Could not find device on the network") self.connectionStatus = .disconnected } return From 6fc2b5241f7895a7f1d114fe2025cdc4b0f2f439 Mon Sep 17 00:00:00 2001 From: Ahmed Harmouche Date: Wed, 16 Sep 2026 16:47:01 +0200 Subject: [PATCH 2/4] Some fixes --- .../app/src/main/res/values-hu/strings.xml | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/dashpilot-android/app/src/main/res/values-hu/strings.xml b/dashpilot-android/app/src/main/res/values-hu/strings.xml index 20b0db72..ba299931 100644 --- a/dashpilot-android/app/src/main/res/values-hu/strings.xml +++ b/dashpilot-android/app/src/main/res/values-hu/strings.xml @@ -98,7 +98,7 @@ Eszköz párosítása Párosítás… Párosítsd a DashKitet - Csatlakoztasd a DashKitet az autó diagnosztikai portjához, majd koppints alul a Bluetooth-párosításhoz. + Csatlakoztasd a DashKitet az autó diagnosztikai portjához, majd nyomj az alábbi gombra a Bluetooth-párosításhoz. DashKit keresése… Tartsd az eszközt a telefon közelében. Ez általában néhány másodpercet vesz igénybe. Minden készen áll! @@ -117,9 +117,9 @@ Tesla Tesla csatlakoztatása Nincs csatlakoztatva - Autó megtalálva — Csatlakozás + Autó megtalálva - Csatlakozás Az autó nincs csatlakoztatva - A csatlakozás sikertelen — koppints az újrapróbáláshoz + A csatlakozás sikertelen - koppints az újrapróbáláshoz Csatlakoztatva Jelen Nincs jelen @@ -132,7 +132,7 @@ Tesla csatlakoztatása - A DashKit töltéskezelőként (Charging Manager) adja hozzá magát a Teslához — le tudja olvasni az állapotot és vezérli a töltést, de nem tudja kinyitni vagy vezetni az autót. + A DashKit töltéskezelőként (Charging Manager) adja hozzá magát a Teslához - le tudja olvasni az állapotot és vezérli a töltést, de nem tudja kinyitni vagy vezetni az autót. Töltéskezelő · Olvasás + töltés Csatlakozás Készítsd elő a kulcskártyát. @@ -142,7 +142,7 @@ Járműazonosító olvasása… Tesla keresése… Tesla · Alvázszám %1$s - Autó megtalálva — csatlakozás a DashKithez… + Autó megtalálva - csatlakozás a DashKithez… A DashKit nem erősítette meg az autót. Ellenőrizd a kapcsolatot, és próbáld újra. A Tesla csatlakoztatásához frissítsd a DashKit firmware-ét. Nem sikerült beolvasni az alvázszámot. Ébreszd fel a járművet, és próbáld újra. Ha a hiba továbbra is fennáll, frissítsd a DashKit firmware-ét. @@ -150,7 +150,7 @@ Érintsd oda a kulcskártyát Helyezd a kulcskártyát a középkonzolra, majd hagyd jóvá az autó érintőképernyőjén. %1$d mp van hátra - Az autó kész — érintsd oda most a kulcskártyát (%1$d mp) + Az autó kész - érintsd oda most a kulcskártyát (%1$d mp) Csatlakoztatva A DashKit mostantól töltéskezelő a Tesládon. Olvasás + töltés engedélyezve @@ -177,7 +177,7 @@ Tesla-kapcsolat eltávolítása… Nem sikerült eltávolítani a kapcsolatot. Próbáld újra. Kapcsolat eltávolítása… - Egy másik telefont párosít — a Tesla-kapcsolattól függetlenül. + Egy másik telefont párosít - a Tesla-kapcsolattól függetlenül. Vissza @@ -187,8 +187,8 @@ Rögzítve - Automatizálások - Vezérlők + Automatizációk + Vezérlés Vezetés Akkumulátor Akku hőmérséklet @@ -205,9 +205,9 @@ IP-cím - Vezérlők + Vezérlés A parancsok küldéséhez csatlakozz a DashKithez - Tipp: nyomj hosszan egy vezérlőt, hogy a kezdőképernyőre rögzítsd + Tipp: nyomj hosszan egy parancsra, hogy a kezdőképernyőre rögzítsd Rögzítve Akku előfűtés: Be Akku előfűtés: Ki @@ -223,28 +223,28 @@ Kesztyűtartó nyitása - Automatizálások + Automatizációk Ablaktörlők Ablaktörlő ki - Az ablaktörlők automatikus kikapcsolva tartása + Az ablaktörlők automatikus kikapcsolva tartása miközben aktív az Autopilot. Klíma Klíma bekapcsolva tartása - A klíma bekapcsolva marad, amikor kiszállsz az autóból. Az automatizálás a beállított idő letelte után, vagy amikor visszatérsz az autóhoz, leáll. + A klíma bekapcsolva marad, amikor kiszállsz az autóból. Az automatizáció a beállított idő letelte után, vagy amikor visszatérsz az autóhoz, leáll. Leállítás ennyi idő után Vezetés Kick-down - Chill módról Standardra vált, amíg a gázpedál a küszöbérték fölött van lenyomva. Visszaáll, amikor felengeded. + Chill módról Standardra vált, amíg a gázpedál a küszöbérték fölött van lenyomva. Visszaáll Chill-re, amikor felengeded a pedált. Pedálküszöb - Többujjas infotainment-indító - Rendelj 3, 4 vagy 5 ujjas koppintást az infotainment képernyőn egy vezérlőhöz + Többujjas infotainment parancs + Rendelj parancsokat az infotainment képernyő 3, 4, vagy 5 ujjal történő megérintéséhez (Pl.: kesztyűtartó nyitás 3 ujjas érintésre). ujj művelet: Eltávolítás - Indító hozzáadása + Parancs hozzáadása Klíma - Automatizálás + Automatizáció Vezető oldali beállított hőfok Beállított hőfokok Vezető @@ -254,7 +254,7 @@ Ventilátor Légkondi Belső keringetés - Klíma megtartása + Klíma bekapcsolva tartása Ki Be Előkondicionálás @@ -264,7 +264,7 @@ Keringetés Friss levegő Megtartás - Kutya mód + Kisállat mód Kemping mód @@ -274,13 +274,13 @@ Energia Hátralévő Felhasználható - Teljes csomag + Teljes pack Tartalék Teljesítmény Teljesítmény Max. kisütés - Max. rekuperáció - Akkucsomag + Max. újratöltés + Akkupack Feszültség Áramerősség Min. hőmérséklet @@ -289,7 +289,7 @@ A DashKit nem található Nem sikerült csatlakozni a DashKithez - A DashKit nem fogadta el a párosítást. Nyisd meg az „Új eszköz párosítása” lehetőséget a DashPilot beállításaiban egy már párosított telefonon, majd próbáld újra. + A DashKit nem fogadta el a párosítást. Nyisd meg az "Új eszköz párosítása" lehetőséget a DashPilot beállításaiban egy már párosított telefonon, majd próbáld újra. A BLE-keresés sikertelen (hibakód: %1$d) Nem sikerült elindítani a párosítást A szolgáltatások felderítése sikertelen From e0f4aa680ef88d536a4e0a41af9e72708b1833d8 Mon Sep 17 00:00:00 2001 From: Ahmed Harmouche Date: Wed, 16 Sep 2026 16:52:00 +0200 Subject: [PATCH 3/4] Fix layout bug in rendering quality settings row --- .../com/softwiredtech/dashpilot/ui/SettingsScreen.kt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/SettingsScreen.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/SettingsScreen.kt index d13e450b..bd983c68 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/SettingsScreen.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/ui/SettingsScreen.kt @@ -504,7 +504,14 @@ private fun RenderQualitySelector(selected: Int, onSelected: (Int) -> Unit) { horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { - Text(text = stringResource(R.string.settings_render_quality_title), color = Color.White, fontSize = 16.sp) + Text( + text = stringResource(R.string.settings_render_quality_title), + color = Color.White, + fontSize = 16.sp, + modifier = Modifier + .weight(1f) + .padding(end = 12.dp) + ) Row( modifier = Modifier .clip(RoundedCornerShape(8.dp)) @@ -523,7 +530,8 @@ private fun RenderQualitySelector(selected: Int, onSelected: (Int) -> Unit) { Text( text = label, color = if (isSelected) Color.White else DarkColors.TextMuted, - fontSize = 13.sp + fontSize = 13.sp, + maxLines = 1 ) } } From bbb4e5066ace6932805f717540479029f183c11c Mon Sep 17 00:00:00 2001 From: Ahmed Harmouche Date: Thu, 17 Sep 2026 09:25:31 +0200 Subject: [PATCH 4/4] [android][ios] Hungarian localization --- .../app/src/main/res/values-hu/strings.xml | 8 +- dashpilot-ios/dashpilot/InfoPlist.xcstrings | 38 +- dashpilot-ios/dashpilot/Localizable.xcstrings | 2281 +++++++++-------- dashpilot-ios/dashpilot/UI/SettingsView.swift | 5 +- 4 files changed, 1199 insertions(+), 1133 deletions(-) diff --git a/dashpilot-android/app/src/main/res/values-hu/strings.xml b/dashpilot-android/app/src/main/res/values-hu/strings.xml index ba299931..e33b45f4 100644 --- a/dashpilot-android/app/src/main/res/values-hu/strings.xml +++ b/dashpilot-android/app/src/main/res/values-hu/strings.xml @@ -188,7 +188,7 @@ Rögzítve Automatizációk - Vezérlés + Parancsok Vezetés Akkumulátor Akku hőmérséklet @@ -205,7 +205,7 @@ IP-cím - Vezérlés + Parancsok A parancsok küldéséhez csatlakozz a DashKithez Tipp: nyomj hosszan egy parancsra, hogy a kezdőképernyőre rögzítsd Rögzítve @@ -237,7 +237,7 @@ Pedálküszöb Többujjas infotainment parancs Rendelj parancsokat az infotainment képernyő 3, 4, vagy 5 ujjal történő megérintéséhez (Pl.: kesztyűtartó nyitás 3 ujjas érintésre). - ujj + ujjas művelet: Eltávolítás Parancs hozzáadása @@ -272,7 +272,7 @@ Előfűtés Töltöttségi szint Energia - Hátralévő + Bruttó kapacitás Felhasználható Teljes pack Tartalék diff --git a/dashpilot-ios/dashpilot/InfoPlist.xcstrings b/dashpilot-ios/dashpilot/InfoPlist.xcstrings index ef06fd44..52f51125 100644 --- a/dashpilot-ios/dashpilot/InfoPlist.xcstrings +++ b/dashpilot-ios/dashpilot/InfoPlist.xcstrings @@ -1,16 +1,36 @@ { - "sourceLanguage": "en", - "strings": { - "NSBluetoothAlwaysUsageDescription": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A DashPilot Bluetoothon keresztül csatlakozik a DashKithez, hogy élő járműadatokat jelenítsen meg és járműparancsokat küldjön." + "sourceLanguage" : "en", + "strings" : { + "CFBundleName" : { + "comment" : "Bundle name", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "dashpilot" + } + } + } + }, + "NSBluetoothAlwaysUsageDescription" : { + "comment" : "Privacy - Bluetooth Always Usage Description", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "DashPilot connects to your DashKit over Bluetooth to show live vehicle data and send vehicle commands." + } + }, + "hu" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "A DashPilot Bluetoothon keresztül csatlakozik a DashKithez, hogy élő járműadatokat jelenítsen meg és járműparancsokat küldjön." } } } } }, - "version": "1.0" + "version" : "1.0" } \ No newline at end of file diff --git a/dashpilot-ios/dashpilot/Localizable.xcstrings b/dashpilot-ios/dashpilot/Localizable.xcstrings index 6b653c4d..380c1b97 100644 --- a/dashpilot-ios/dashpilot/Localizable.xcstrings +++ b/dashpilot-ios/dashpilot/Localizable.xcstrings @@ -1,1866 +1,1909 @@ { - "sourceLanguage": "en", - "strings": { - "Controls": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Vezérlők" + "sourceLanguage" : "en", + "strings" : { + "" : { + + }, + "%@ (%@)" : { + "comment" : "A label displaying the current version and build number of the app.", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@ (%2$@)" } } } }, - "Battery": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Akkumulátor" + "%lld %@" : { + "comment" : "A label showing a value and its unit. The first argument is the value. The second argument is the unit.", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$lld %2$@" } } } }, - "Climate": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Klíma" + "%lld of %lld" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld / %lld" } } } }, - "Automations": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Automatizálások" + "3D Visualizer" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "3D megjelenítő" } } } }, - "Settings": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Beállítások" + "A/C" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Légkondi" } } } }, - "Pinned": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Rögzítve" + "AC Temp" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Klíma hőfok" } } } }, - "Drive": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Vezetés" + "action:" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "művelet:" } } } }, - "Battery Temp": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Akku hőmérséklet" + "Add trigger" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Parancs hozzáadása" } } } }, - "AC Temp": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Klíma hőfok" + "Always On Blind-Spot Monitor" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mindig bekapcsolt holttérfigyelő" } } } }, - "Odometer": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Kilométer-számláló" + "Ambient Dashboard" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ambient műszerfal" } } } }, - "Data source: connected": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Adatforrás: csatlakozva" + "Analog Dashboard" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Analóg műszerfal" } } } }, - "Data source: connecting…": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Adatforrás: csatlakozás…" + "Auto" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Auto" } } } }, - "Data source": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Adatforrás" + "Automation" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatizáció" } } } }, - "Disconnect": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Kapcsolat bontása" + "Automations" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatizációk" } } } }, - "Connect to DashKit to send commands": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A parancsok küldéséhez csatlakozz a DashKithez" + "Battery" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Akkumulátor" } } } }, - "Tip: long-press a control to pin it to the home screen": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Tipp: nyomj hosszan egy vezérlőt, hogy a kezdőképernyőre rögzítsd" + "Battery Preheat: Off" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Akku előfűtés: Ki" } } } }, - "Battery Preheat: On": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Akku előfűtés: Be" + "Battery Preheat: On" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Akku előfűtés: Be" } } } }, - "Battery Preheat: Off": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Akku előfűtés: Ki" + "Battery Temp" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Akku hőmérséklet" } } } }, - "Frunk": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Első csomagtartó" + "Bind 3-, 4-, or 5-finger infotainment taps to a control" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rendelj parancsokat az infotainment képernyő 3, 4, vagy 5 ujjal történő megérintéséhez (Pl.: kesztyűtartó nyitás 3 ujjas érintésre)." } } } }, - "Trunk": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Csomagtartó" + "Bluetooth is off" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A Bluetooth ki van kapcsolva" } } } }, - "Charge Port: Open": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Töltőcsatlakozó: Nyitva" + "Bluetooth permission denied" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A Bluetooth-engedély megtagadva" } } } }, - "Charge Port: Closed": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Töltőcsatlakozó: Zárva" + "Buffer" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tartalék" } } } }, - "Mirrors: Folded": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Tükrök: Behajtva" + "Camp mode" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kemping mód" } } } }, - "Mirrors: Unfolded": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Tükrök: Kihajtva" + "Cancel" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mégse" } } } }, - "Rear Fan: On": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Hátsó ventilátor: Be" + "Charge Port: Closed" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Töltőcsatlakozó: Zárva" } } } }, - "Rear Fan: Off": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Hátsó ventilátor: Ki" + "Charge Port: Open" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Töltőcsatlakozó: Nyitva" } } } }, - "Toggle Mirror Dip": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Tükördöntés váltása" + "Check for firmware updates" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Firmware-frissítések keresése" } } } }, - "Open Glovebox": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Kesztyűtartó nyitása" + "Checking for updates…" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Frissítések keresése…" } } } }, - "Preheat": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Előfűtés" + "Choose a dashboard" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Válassz műszerfalat" } } } }, - "State of charge": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Töltöttségi szint" + "Climate" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Klíma" } } } }, - "Energy": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Energia" + "comma" : { + "comment" : "A button that opens a WiFi connection.", + "isCommentAutoGenerated" : true + }, + "Configuration" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Konfiguráció" } } } }, - "Remaining": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Hátralévő" + "Connect" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Csatlakozás" } } } }, - "Usable": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Felhasználható" + "Connect to a DashKit device to manage it." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A kezeléshez csatlakozz egy DashKit eszközhöz." } } } }, - "Full Pack": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Teljes csomag" + "Connect to DashKit first to pair a new device" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Új eszköz párosításához előbb csatlakozz a DashKithez" } } } }, - "Buffer": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Tartalék" + "Connect to DashKit to send commands" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A parancsok küldéséhez csatlakozz a DashKithez" } } } }, - "Power": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Teljesítmény" + "Connect your comma device" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Csatlakozás a comma eszközhöz" } } } }, - "Max Discharge": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Max. kisütés" + "Connected" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Csatlakozva" } } } }, - "Max Regen": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Max. rekuperáció" + "Connected to %@" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Csatlakozva ehhez: %@" } } } }, - "Pack": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Akkucsomag" + "Connecting to %@..." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Csatlakozás ehhez: %@..." } } } }, - "Voltage": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Feszültség" + "Connecting..." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Csatlakozás..." } } } }, - "Current": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Áramerősség" + "Connecting…" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Csatlakozás…" } } } }, - "Temp Min": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Min. hőmérséklet" + "Continue" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Folytatás" } } } }, - "Temp Max": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Max. hőmérséklet" + "Controls" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Parancsok" } } } }, - "Automation": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Automatizálás" + "Could not connect to DashKit" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nem sikerült csatlakozni a DashKithez" } } } }, - "Keep climate on": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Klíma bekapcsolva tartása" + "Could not find device on the network" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Az eszköz nem található a hálózaton" } } } }, - "Keep the climate on when you leave the car. The automation stops after the set time, or when you return to the car.": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A klíma bekapcsolva marad, amikor kiszállsz az autóból. Az automatizálás a beállított idő letelte után, vagy amikor visszatérsz az autóhoz, leáll." + "Could not reach update server" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A frissítési szerver nem érhető el" } } } }, - "Stop after": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Leállítás ennyi idő után" + "Could not send reboot command." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nem sikerült elküldeni az újraindítási parancsot." } } } }, - "min": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "perc" + "Couldn't pair" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nem sikerült párosítani" } } } }, - "Setpoints": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Beállított hőfokok" + "Current" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Áramerősség" } } } }, - "Driver": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Vezető" + "Dark Mode" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sötét mód" } } } }, - "Passenger": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Utas" + "Dashboard" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Műszerfal" } } } }, - "Fan": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Ventilátor" + "Dashboard Theme" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Műszerfal témája" + } + } + } + }, + "DashKit" : { + "comment" : "A button that connects to DashKit.", + "isCommentAutoGenerated" : true + }, + "DashKit firmware is up to date" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A DashKit firmware naprakész" } } } }, - "A/C": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Légkondi" + "DashKit is connected and ready to stream data to your dashboard." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A DashKit csatlakozva van, és készen áll az adatok küldésére a műszerfalra." } } } }, - "Recirculation": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Belső keringetés" + "DashKit is open for pairing. Pair the new phone within 2 minutes." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A DashKit párosításra kész. Párosítsd az új telefont 2 percen belül." } } } }, - "Keep climate": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Klíma megtartása" + "DashKit not found" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A DashKit nem található" } } } }, - "Driver setpoint": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Vezető oldali beállított hőfok" + "DashKit rejected this phone's pairing. If DashKit is paired with another phone, open \"Pair a new device\" in its DashPilot settings and try again. If this phone was paired before, forget \"DashKit\" in Settings > Bluetooth first." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A DashKit elutasította a telefon párosítását. Ha a DashKit egy másik telefonnal van párosítva, nyisd meg azon a DashPilot beállításaiban az \"Új eszköz párosítása\" lehetőséget, és próbáld újra. Ha ez a telefon korábban már párosítva volt, előbb felejtsd el a \"DashKit\" eszközt a Beállítások > Bluetooth menüben." } } } }, - "Off": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Ki" + "DashKit will allow one new device to pair for the next 2 minutes. Open DashPilot on the other phone and pair it now." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A DashKit a következő 2 percben egy új eszköz párosítását engedélyezi. Nyisd meg a DashPilotot a másik telefonon, és párosítsd most." } } } }, - "On": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Be" + "DashKit will restart and briefly disconnect. It should reconnect automatically once it is back up." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A DashKit újraindul, és rövid időre megszakad a kapcsolat. Amint újra elindult, automatikusan újracsatlakozik." + } + } + } + }, + "dashpilot" : { + "comment" : "The name of the app.", + "isCommentAutoGenerated" : true + }, + "DashPilot" : { + "comment" : "The name of the app.", + "isCommentAutoGenerated" : true + }, + "Data source" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adatforrás" } } } }, - "Preconditioning": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Előkondicionálás" + "Data source: connected" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adatforrás: csatlakozva" } } } }, - "Overheat protection (fan)": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Túlmelegedés-védelem (ventilátor)" + "Data source: connecting…" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adatforrás: csatlakozás…" } } } }, - "Overheat protection": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Túlmelegedés-védelem" + "Device IP" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eszköz IP-címe" } } } }, - "Auto": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Auto" + "Device reported error (0x%@)" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Az eszköz hibát jelzett (0x%@)" } } } }, - "Recirculate": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Keringetés" + "Disconnect" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kapcsolat bontása" } } } }, - "Fresh air": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Friss levegő" + "Disconnected" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs kapcsolat" } } } }, - "Keep": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Megtartás" + "Disconnected unexpectedly" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Váratlanul megszakadt a kapcsolat" } } } }, - "Dog mode": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Kutya mód" + "Display" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Megjelenítés" } } } }, - "Camp mode": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Kemping mód" + "Dog mode" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kisállat mód" } } } }, - "Wipers": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Ablaktörlők" + "Download failed: %@" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A letöltés sikertelen: %@" } } } }, - "Wiper Off": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Ablaktörlő ki" + "Downloaded firmware failed integrity check" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A letöltött firmware integritás-ellenőrzése sikertelen" } } } }, - "Keep wipers disabled automatically": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Az ablaktörlők automatikus kikapcsolva tartása" + "Downloading firmware…" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Firmware letöltése…" } } } }, - "Driving": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Vezetés" + "Drive" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vezetés" } } } }, - "Kick-down": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Kick-down" + "Driver" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vezető" } } } }, - "Switch from Chill to Standard while the accelerator is pressed past the threshold. Reverts when you ease off.": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Chill módról Standardra vált, amíg a gázpedál a küszöbérték fölött van lenyomva. Visszaáll, amikor felengeded." + "Driver setpoint" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vezető oldali beállított hőfok" } } } }, - "Pedal threshold": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Pedálküszöb" + "Driving" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vezetés" } } } }, - "Multi-touch infotainment trigger": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Többujjas infotainment-indító" + "Energy" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Energia" } } } }, - "Bind 3-, 4-, or 5-finger infotainment taps to a control": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Rendelj 3, 4 vagy 5 ujjas koppintást az infotainment képernyőn egy vezérlőhöz" + "Enter IP manually" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "IP-cím megadása kézzel" } } } }, - "fingers": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "ujj" + "Extra Vehicle Bus" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Extra járműbusz" } } } }, - "action:": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "művelet:" + "Failed to enable OTA notifications" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nem sikerült bekapcsolni az OTA-értesítéseket" } } } }, - "Add trigger": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Indító hozzáadása" + "Fan" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ventilátor" } } } }, - "Vanilla Dashboard": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Vanilla műszerfal" + "fingers" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "ujjas" } } } }, - "Ambient Dashboard": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Ambient műszerfal" + "Firmware" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Firmware" } } } }, - "Analog Dashboard": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Analóg műszerfal" + "Firmware file is empty" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A firmware-fájl üres" } } } }, - "Retro Dashboard": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Retro műszerfal" + "Firmware info" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Firmware adatai" } } } }, - "Load Rive File": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Rive fájl betöltése" + "Firmware version" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Firmware verzió" } } } }, - "Choose a dashboard": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Válassz műszerfalat" + "Fresh air" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Friss levegő" } } } }, - "Some settings depend on the selected theme": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Egyes beállítások a kiválasztott témától függenek" + "Frunk" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Első csomagtartó" } } } }, - "Dashboard Theme": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Műszerfal témája" + "Full Pack" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Teljes pack" } } } }, - "Unsupported dashboard type: %@": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Nem támogatott műszerfaltípus: %@" + "General" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Általános" } } } }, - "General": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Általános" + "Get started" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kezdjük" } } } }, - "Connect to a DashKit device to manage it.": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A kezeléshez csatlakozz egy DashKit eszközhöz." + "High" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Magas" } } } }, - "Dashboard": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Műszerfal" + "Hold the device close to your phone. This usually takes a few seconds." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tartsd az eszközt a telefon közelében. Ez általában néhány másodpercet vesz igénybe." } } } }, - "Configuration": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Konfiguráció" + "If this DashKit is already paired with another phone, open DashPilot on that phone and tap Settings → DashKit → Pair a new device, then try again." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ha ez a DashKit már párosítva van egy másik telefonnal, nyisd meg a DashPilotot azon a telefonon, és koppints a Beállítások → DashKit → Új eszköz párosítása lehetőségre, majd próbáld újra." } } } }, - "Extra Vehicle Bus": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Extra járműbusz" + "Install update" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Frissítés telepítése" } } } }, - "Display": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Megjelenítés" + "Keep" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Megtartás" } } } }, - "Show Car Battery": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Autó akkumulátorának mutatása" + "Keep climate" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Klíma bekapcsolva tartása" } } } }, - "Show Odometer": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Kilométer-számláló mutatása" + "Keep climate on" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Klíma bekapcsolva tartása" } } } }, - "Use Imperial Units": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Angolszász mértékegységek" + "Keep the climate on when you leave the car. The automation stops after the set time, or when you return to the car." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A klíma bekapcsolva marad, amikor kiszállsz az autóból. Az automatizáció a beállított idő letelte után, vagy amikor visszatérsz az autóhoz, leáll." } } } }, - "Show Phone Battery": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Telefon akkumulátorának mutatása" + "Keep wipers disabled automatically" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Az ablaktörlők automatikus kikapcsolva tartása miközben aktív az Autopilot." } } } }, - "Dark Mode": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Sötét mód" + "Kick-down" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kick-down" } } } }, - "3D Visualizer": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "3D megjelenítő" + "Load Rive File" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rive fájl betöltése" } } } }, - "Always On Blind-Spot Monitor": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Mindig bekapcsolt holttérfigyelő" + "Looking for DashKit…" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "DashKit keresése…" } } } }, - "Render Quality": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Renderelési minőség" + "Low" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alacsony" } } } }, - "Low": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Alacsony" + "Maintenance" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Karbantartás" } } } }, - "Med": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Közepes" + "Max Discharge" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Max. kisütés" } } } }, - "High": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Magas" + "Max Regen" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Max. újratöltés" } } } }, - "Replay onboarding": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Bevezető újranézése" + "Med" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Közepes" } } } }, - "Start Demo Mode": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Demó mód indítása" + "min" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "perc" } } } }, - "Version": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Verzió" + "Mirrors: Folded" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tükrök: Behajtva" } } } }, - "Connect your comma device": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Csatlakozás a comma eszközhöz" + "Mirrors: Unfolded" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tükrök: Kihajtva" } } } }, - "Connecting to %@...": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Csatlakozás ehhez: %@..." + "Multi-touch infotainment trigger" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Többujjas infotainment parancs" } } } }, - "Searching for device...": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Eszköz keresése..." + "Next" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tovább" } } } }, - "Connected to %@": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Csatlakozva ehhez: %@" + "Odometer" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kilométer-számláló" } } } }, - "Connect": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Csatlakozás" + "Off" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ki" } } } }, - "Enter IP manually": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "IP-cím megadása kézzel" + "On" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Be" } } } }, - "Device IP": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Eszköz IP-címe" + "One more thing" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Még valami" } } } }, - "Cancel": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Mégse" + "Open Glovebox" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kesztyűtartó nyitása" } } } }, - "Connecting...": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Csatlakozás..." + "Open pairing" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Párosítás megnyitása" } } } }, - "Next": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Tovább" + "OTA characteristics not found" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Az OTA-jellemzők nem találhatók" } } } }, - "Could not find device on the network": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Az eszköz nem található a hálózaton" + "OTA service not found on device" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Az OTA-szolgáltatás nem található az eszközön" } } } }, - "Pair a new device?": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Párosítasz egy új eszközt?" + "Overheat protection" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Túlmelegedés-védelem" } } } }, - "Open pairing": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Párosítás megnyitása" + "Overheat protection (fan)" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Túlmelegedés-védelem (ventilátor)" } } } }, - "DashKit is open for pairing. Pair the new phone within 2 minutes.": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A DashKit párosításra kész. Párosítsd az új telefont 2 percen belül." + "Pack" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Akkupack" } } } }, - "Connect to DashKit first to pair a new device": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Új eszköz párosításához előbb csatlakozz a DashKithez" + "Pair a new device" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Új eszköz párosítása" } } } }, - "DashKit will allow one new device to pair for the next 2 minutes. Open DashPilot on the other phone and pair it now.": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A DashKit a következő 2 percben egy új eszköz párosítását engedélyezi. Nyisd meg a DashPilotot a másik telefonon, és párosítsd most." + "Pair a new device?" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Párosítasz egy új eszközt?" } } } }, - "Reboot DashKit?": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Újraindítod a DashKitet?" + "Pair device" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eszköz párosítása" } } } }, - "Reboot": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Újraindítás" + "Pair more DashKit devices" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "További DashKit eszközök párosítása" } } } }, - "Reboot command sent. DashKit is restarting.": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Újraindítási parancs elküldve. A DashKit újraindul." + "Pair your DashKit" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Párosítsd a DashKitet" } } } }, - "Could not send reboot command.": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Nem sikerült elküldeni az újraindítási parancsot." + "Pairing" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Párosítás" } } } }, - "DashKit will restart and briefly disconnect. It should reconnect automatically once it is back up.": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A DashKit újraindul, és rövid időre megszakad a kapcsolat. Amint újra elindult, automatikusan újracsatlakozik." + "Pairing…" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Párosítás…" } } } }, - "Firmware info": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Firmware adatai" + "Passenger" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Utas" } } } }, - "Status": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Állapot" + "Pedal threshold" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pedálküszöb" } } } }, - "Connected": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Csatlakozva" + "Pinned" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rögzítve" } } } }, - "Disconnected": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Nincs kapcsolat" + "Plug the DashKit into your car's debug port, then tap below to pair over Bluetooth." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Csatlakoztasd a DashKitet az autó diagnosztikai portjához, majd nyomj az alábbi gombra a Bluetooth-párosításhoz." } } } }, - "Firmware version": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Firmware verzió" + "Power" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Teljesítmény" } } } }, - "Unknown": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Ismeretlen" + "Preconditioning" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Előkondicionálás" } } } }, - "Pairing": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Párosítás" + "Preheat" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Előfűtés" } } } }, - "Pair a new device": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Új eszköz párosítása" + "Rear Fan: Off" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hátsó ventilátor: Ki" } } } }, - "Maintenance": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Karbantartás" + "Rear Fan: On" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hátsó ventilátor: Be" } } } }, - "Reboot DashKit": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "DashKit újraindítása" + "Reboot" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Újraindítás" } } } }, - "Firmware": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Firmware" + "Reboot command sent. DashKit is restarting." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Újraindítási parancs elküldve. A DashKit újraindul." } } } }, - "Downloading firmware…": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Firmware letöltése…" + "Reboot DashKit" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "DashKit újraindítása" } } } }, - "Checking for updates…": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Frissítések keresése…" + "Reboot DashKit?" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Újraindítod a DashKitet?" } } } }, - "DashKit firmware is up to date": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A DashKit firmware naprakész" + "Recirculate" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keringetés" } } } }, - "Version %@ is available": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Elérhető a(z) %@ verzió" + "Recirculation" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Belső keringetés" } } } }, - "Install update": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Frissítés telepítése" + "Remaining" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bruttó kapacitás" } } } }, - "Update failed: %@": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A frissítés sikertelen: %@" + "Render Quality" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Renderelési minőség" } } } }, - "Connecting…": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Csatlakozás…" + "Replay onboarding" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bevezető újranézése" } } } }, - "Uploading firmware… %d%%": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Firmware feltöltése… %d%%" + "Retro Dashboard" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Retro műszerfal" } } } }, - "Update complete! Rebooting DashKit…": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Frissítés kész! A DashKit újraindul…" + "Retry" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Újra" } } } }, - "Update DashKit Firmware": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "DashKit firmware frissítése" + "Searching for device..." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eszköz keresése..." } } } }, - "Pair your DashKit": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Párosítsd a DashKitet" + "Service discovery failed" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A szolgáltatások felderítése sikertelen" } } } }, - "Looking for DashKit…": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "DashKit keresése…" + "Setpoints" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Beállított hőfokok" } } } }, - "You're all set!": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Minden készen áll!" + "Settings" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Beállítások" } } } }, - "Couldn't pair": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Nem sikerült párosítani" + "Setup" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Beállítás" } } } }, - "Plug the DashKit into your car's debug port, then tap below to pair over Bluetooth.": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Csatlakoztasd a DashKitet az autó diagnosztikai portjához, majd koppints alul a Bluetooth-párosításhoz." + "Show Car Battery" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Autó akkumulátorának mutatása" } } } }, - "Hold the device close to your phone. This usually takes a few seconds.": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Tartsd az eszközt a telefon közelében. Ez általában néhány másodpercet vesz igénybe." + "Show Odometer" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kilométer-számláló mutatása" } } } }, - "DashKit is connected and ready to stream data to your dashboard.": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A DashKit csatlakozva van, és készen áll az adatok küldésére a műszerfalra." + "Show Phone Battery" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Telefon akkumulátorának mutatása" } } } }, - "If this DashKit is already paired with another phone, open DashPilot on that phone and tap Settings → DashKit → Pair a new device, then try again.": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Ha ez a DashKit már párosítva van egy másik telefonnal, nyisd meg a DashPilotot azon a telefonon, és koppints a Beállítások → DashKit → Új eszköz párosítása lehetőségre, majd próbáld újra." + "Skip" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kihagyás" } } } }, - "Pair device": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Eszköz párosítása" + "Some settings depend on the selected theme" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Egyes beállítások a kiválasztott témától függenek" } } } }, - "Pairing…": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Párosítás…" + "Start Demo Mode" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Demó mód indítása" } } } }, - "Continue": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Folytatás" + "State of charge" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Töltöttségi szint" } } } }, - "Retry": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Újra" + "Status" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Állapot" } } } }, - "One more thing": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Még valami" + "Stop after" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Leállítás ennyi idő után" } } } }, - "You can pair additional devices and install firmware updates anytime from Settings.": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "További eszközöket párosíthatsz és firmware-frissítéseket telepíthetsz bármikor a Beállításokból." + "Switch from Chill to Standard while the accelerator is pressed past the threshold. Reverts when you ease off." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chill módról Standardra vált, amíg a gázpedál a küszöbérték fölött van lenyomva. Visszaáll Chill-re, amikor felengeded a pedált." } } } }, - "Pair more DashKit devices": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "További DashKit eszközök párosítása" + "Temp Max" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Max. hőmérséklet" } } } }, - "Check for firmware updates": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Firmware-frissítések keresése" + "Temp Min" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Min. hőmérséklet" } } } }, - "Get started": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Kezdjük" + "Tip: long-press a control to pin it to the home screen" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tipp: nyomj hosszan egy parancsra, hogy a kezdőképernyőre rögzítsd" } } } }, - "Setup": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Beállítás" + "Toggle Mirror Dip" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tükördöntés váltása" } } } }, - "Skip": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Kihagyás" + "Trunk" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Csomagtartó" } } } }, - "%lld of %lld": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "%lld / %lld" + "Unknown" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ismeretlen" } } } }, - "DashKit not found": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A DashKit nem található" + "Unsupported dashboard type: %@" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nem támogatott műszerfaltípus: %@" } } } }, - "Could not connect to DashKit": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Nem sikerült csatlakozni a DashKithez" + "Update complete! Rebooting DashKit…" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Frissítés kész! A DashKit újraindul…" } } } }, - "Bluetooth permission denied": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A Bluetooth-engedély megtagadva" + "Update DashKit Firmware" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "DashKit firmware frissítése" } } } }, - "Bluetooth is off": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A Bluetooth ki van kapcsolva" + "Update failed: %@" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A frissítés sikertelen: %@" } } } }, - "DashKit rejected this phone's pairing. If DashKit is paired with another phone, open \"Pair a new device\" in its DashPilot settings and try again. If this phone was paired before, forget \"DashKit\" in Settings > Bluetooth first.": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A DashKit elutasította a telefon párosítását. Ha a DashKit egy másik telefonnal van párosítva, nyisd meg azon a DashPilot beállításaiban az „Új eszköz párosítása” lehetőséget, és próbáld újra. Ha ez a telefon korábban már párosítva volt, előbb felejtsd el a „DashKit” eszközt a Beállítások > Bluetooth menüben." + "Uploading firmware… %d%%" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Firmware feltöltése… %d%%" } } } }, - "Service discovery failed": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A szolgáltatások felderítése sikertelen" + "Usable" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Felhasználható" } } } }, - "Could not reach update server": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A frissítési szerver nem érhető el" + "Use Imperial Units" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Angolszász mértékegységek" } } } }, - "Downloaded firmware failed integrity check": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A letöltött firmware integritás-ellenőrzése sikertelen" + "Vanilla Dashboard" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vanilla műszerfal" } } } }, - "Download failed: %@": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A letöltés sikertelen: %@" + "Version" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verzió" } } } }, - "Firmware file is empty": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "A firmware-fájl üres" + "Version %@ is available" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Elérhető a(z) %@ verzió" } } } }, - "OTA service not found on device": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Az OTA-szolgáltatás nem található az eszközön" + "Voltage" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Feszültség" } } } }, - "OTA characteristics not found": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Az OTA-jellemzők nem találhatók" + "Wiper Off" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ablaktörlő ki" } } } }, - "Failed to enable OTA notifications": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Nem sikerült bekapcsolni az OTA-értesítéseket" + "Wipers" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ablaktörlők" } } } }, - "Write failed (%@)": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Az írás sikertelen (%@)" + "Write failed (%@)" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Az írás sikertelen (%@)" } } } }, - "Disconnected unexpectedly": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Váratlanul megszakadt a kapcsolat" + "You can pair additional devices and install firmware updates anytime from Settings." : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "További eszközöket párosíthatsz és firmware-frissítéseket telepíthetsz bármikor a Beállításokból." } } } }, - "Device reported error (0x%@)": { - "localizations": { - "hu": { - "stringUnit": { - "state": "translated", - "value": "Az eszköz hibát jelzett (0x%@)" + "You're all set!" : { + "localizations" : { + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Minden készen áll!" } } } } }, - "version": "1.0" + "version" : "1.1" } \ No newline at end of file diff --git a/dashpilot-ios/dashpilot/UI/SettingsView.swift b/dashpilot-ios/dashpilot/UI/SettingsView.swift index c5bab6e3..1777f808 100644 --- a/dashpilot-ios/dashpilot/UI/SettingsView.swift +++ b/dashpilot-ios/dashpilot/UI/SettingsView.swift @@ -253,8 +253,9 @@ struct SettingsView: View { Text("Render Quality") .foregroundColor(.white) .font(.system(size: 16)) - Spacer() + Spacer(minLength: 12) RenderQualityPicker(selected: $renderQuality) + .layoutPriority(1) } .padding(.vertical, 4) } @@ -371,6 +372,8 @@ private struct RenderQualityPicker: View { } label: { Text(label) .font(.system(size: 13, weight: .medium)) + .lineLimit(1) + .fixedSize() .foregroundColor(selected == value ? .white : Color(white: 0.53)) .padding(.horizontal, 14) .padding(.vertical, 8)