feat: Add i18n

This commit is contained in:
Myzel394 2023-08-06 14:40:52 +02:00
parent 46f74e8a8b
commit a8cb592632
No known key found for this signature in database
GPG Key ID: 79CC92F37B3E1A2B
16 changed files with 154 additions and 65 deletions

View File

@ -13,8 +13,10 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import app.myzel394.locationtest.R
import app.myzel394.locationtest.services.RecorderService
@Composable
@ -27,10 +29,10 @@ fun ConfirmDeletionDialog(
onDismiss()
},
title = {
Text("Delete Recording?")
Text(stringResource(R.string.ui_audioRecorder_action_delete_confirm_title))
},
text = {
Text("Are you sure you want to delete this recording?")
Text(stringResource(R.string.ui_audioRecorder_action_delete_confirm_message))
},
icon = {
Icon(
@ -39,10 +41,11 @@ fun ConfirmDeletionDialog(
)
},
confirmButton = {
val label = stringResource(R.string.ui_audioRecorder_action_delete_label)
Button(
modifier = Modifier
.semantics {
contentDescription = "Confirm Recording Deletion"
contentDescription = label
},
onClick = {
onConfirm()
@ -54,14 +57,15 @@ fun ConfirmDeletionDialog(
modifier = Modifier.size(ButtonDefaults.IconSize),
)
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
Text("Delete")
Text(label)
}
},
dismissButton = {
val label = stringResource(R.string.dialog_close_cancel_label)
Button(
modifier = Modifier
.semantics {
contentDescription = "Cancel Recording Deletion"
contentDescription = label
},
onClick = {
onDismiss()
@ -74,7 +78,7 @@ fun ConfirmDeletionDialog(
modifier = Modifier.size(ButtonDefaults.IconSize),
)
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
Text("Cancel")
Text(label)
}
}
)

View File

@ -33,9 +33,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import app.myzel394.locationtest.R
import app.myzel394.locationtest.services.RecorderService
import app.myzel394.locationtest.ui.BIG_PRIMARY_BUTTON_SIZE
import app.myzel394.locationtest.ui.components.AudioRecorder.atoms.ConfirmDeletionDialog
@ -124,10 +126,11 @@ fun RecordingStatus(
},
)
}
val label = stringResource(R.string.ui_audioRecorder_action_delete_label)
Button(
modifier = Modifier
.semantics {
contentDescription = "Delete Recording"
contentDescription = label
},
onClick = {
showDeleteDialog = true
@ -140,16 +143,17 @@ fun RecordingStatus(
modifier = Modifier.size(ButtonDefaults.IconSize),
)
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
Text("Delete")
Text(label)
}
}
val label = stringResource(R.string.ui_audioRecorder_action_save_label)
Button(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth()
.height(BIG_PRIMARY_BUTTON_SIZE)
.semantics {
contentDescription = "Save Recording"
contentDescription = label
},
onClick = {
RecorderService.stopService(context)
@ -163,7 +167,7 @@ fun RecordingStatus(
modifier = Modifier.size(ButtonDefaults.IconSize),
)
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
Text("Save Recording")
Text(label)
}
}
}

View File

@ -25,17 +25,18 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import app.myzel394.locationtest.R
import app.myzel394.locationtest.services.RecorderService
import app.myzel394.locationtest.ui.BIG_PRIMARY_BUTTON_SIZE
import app.myzel394.locationtest.ui.components.AudioRecorder.atoms.AudioVisualizer
import app.myzel394.locationtest.ui.components.atoms.PermissionRequester
import app.myzel394.locationtest.ui.utils.rememberFileSaverDialog
import java.time.format.DateTimeFormatter
val VISUALIZER_HEIGHT = 200.dp
import java.time.format.FormatStyle
@Composable
fun StartRecording(
@ -66,13 +67,14 @@ fun StartRecording(
RecorderService.startService(context, connection)
},
) { trigger ->
val label = stringResource(R.string.ui_audioRecorder_action_start_label)
Button(
onClick = {
trigger()
},
modifier = Modifier
.semantics {
contentDescription = "Start recording"
contentDescription = label
}
.size(200.dp)
.clip(shape = CircleShape),
@ -89,7 +91,7 @@ fun StartRecording(
)
Spacer(modifier = Modifier.height(ButtonDefaults.IconSpacing))
Text(
"Start Recording",
label,
style = MaterialTheme.typography.titleSmall,
)
}
@ -124,7 +126,12 @@ fun StartRecording(
.size(ButtonDefaults.IconSize),
)
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
Text("Save Recording from ${service.recordingStart!!.format(DateTimeFormatter.ISO_DATE_TIME)}")
Text(
stringResource(
R.string.ui_audioRecorder_action_saveOldRecording_label,
DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).format(service.recordingStart!!),
),
)
}
}
else

View File

@ -17,8 +17,10 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import app.myzel394.locationtest.R
import app.myzel394.locationtest.dataStore
import app.myzel394.locationtest.db.AppSettings
import app.myzel394.locationtest.db.AudioRecorderSettings
@ -55,13 +57,15 @@ fun BitrateTile() {
}
}
val notNumberLabel = stringResource(R.string.form_error_type_notNumber)
val notInRangeLabel = stringResource(R.string.form_error_value_notInRange, 1, 320)
InputDialog(
state = showDialog,
selection = InputSelection(
input = listOf(
InputTextField(
header = InputHeader(
title = "Set the bitrate for the audio recording",
title = stringResource(id = R.string.ui_settings_option_bitrate_explanation),
icon = IconSource(Icons.Default.Tune),
),
keyboardOptions = KeyboardOptions(
@ -73,14 +77,14 @@ fun BitrateTile() {
val bitRate = text?.toIntOrNull()
if (bitRate == null) {
ValidationResult.Invalid("Please enter a valid number")
ValidationResult.Invalid(notNumberLabel)
}
if (bitRate in 1..320) {
ValidationResult.Valid
} else {
ValidationResult.Invalid("Please enter a number between 1 and 320")
if (bitRate !in 1..320) {
ValidationResult.Invalid(notInRangeLabel)
}
ValidationResult.Valid
},
key = "bitrate",
)
@ -92,8 +96,8 @@ fun BitrateTile() {
}
)
SettingsTile(
title = "Bitrate",
description = "A higher bitrate means better quality but also larger file size",
title = stringResource(R.string.ui_settings_option_bitrate_title),
description = stringResource(R.string.ui_settings_option_bitrate_description),
leading = {
Icon(
Icons.Default.Tune,
@ -109,7 +113,10 @@ fun BitrateTile() {
shape = MaterialTheme.shapes.medium,
) {
Text(
text = "${settings.audioRecorderSettings.bitRate / 1000} KB/s",
stringResource(
R.string.format_kbps,
settings.audioRecorderSettings.bitRate / 1000,
),
)
}
},
@ -119,7 +126,10 @@ fun BitrateTile() {
onItemSelected = ::updateValue,
) {bitRate ->
Text(
text = "${bitRate / 1000} KB/s",
stringResource(
R.string.format_kbps,
bitRate / 1000,
),
)
}
}

View File

@ -13,6 +13,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import app.myzel394.locationtest.R
import app.myzel394.locationtest.dataStore
import app.myzel394.locationtest.db.AppSettings
import app.myzel394.locationtest.db.AudioRecorderSettings
@ -60,7 +62,7 @@ fun EncoderTile() {
},
)
SettingsTile(
title = "Encoder",
title = stringResource(R.string.ui_settings_option_encoder_title),
leading = {
Icon(
Icons.Default.Memory,
@ -77,7 +79,7 @@ fun EncoderTile() {
) {
Text(
text = if (settings.audioRecorderSettings.encoder == null) {
"Auto"
stringResource(R.string.ui_settings_value_auto_label)
} else {
AudioRecorderSettings.ENCODER_INDEX_TEXT_MAP[settings.audioRecorderSettings.encoder]!!
}
@ -89,9 +91,7 @@ fun EncoderTile() {
items = listOf(null),
onItemSelected = ::updateValue,
) {
Text(
text = "Auto"
)
Text(stringResource(R.string.ui_settings_value_auto_label))
}
}
)

View File

@ -11,6 +11,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import app.myzel394.locationtest.R
import app.myzel394.locationtest.dataStore
import app.myzel394.locationtest.db.AppSettings
import app.myzel394.locationtest.db.AudioRecorderSettings
@ -42,8 +44,8 @@ fun ForceExactMaxDurationTile() {
SettingsTile(
title = "Force exact duration",
description = "Force to strip the output file to be the exactly specified duration. If this is disabled, the output file may be a bit longer due to batches of audio samples being encoded together.",
title = stringResource(R.string.ui_settings_option_forceExactDuration_title),
description = stringResource(R.string.ui_settings_option_forceExactDuration_description),
leading = {
Icon(
Icons.Default.GraphicEq,

View File

@ -17,7 +17,9 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import app.myzel394.locationtest.R
import app.myzel394.locationtest.dataStore
import app.myzel394.locationtest.db.AppSettings
import app.myzel394.locationtest.db.AudioRecorderSettings
@ -66,8 +68,8 @@ fun IntervalDurationTile() {
)
)
SettingsTile(
title = "Batch duration",
description = "Record a single batch for this duration. Alibi records multiple batches and deletes the oldest one. When exporting the audio, all batches will be merged together",
title = stringResource(R.string.ui_settings_option_intervalDuration_title),
description = stringResource(R.string.ui_settings_option_intervalDuration_description),
leading = {
Icon(
Icons.Default.Mic,

View File

@ -18,8 +18,10 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import app.myzel394.locationtest.R
import app.myzel394.locationtest.dataStore
import app.myzel394.locationtest.db.AppSettings
import app.myzel394.locationtest.db.AudioRecorderSettings
@ -74,8 +76,8 @@ fun MaxDurationTile() {
)
)
SettingsTile(
title = "Max duration",
description = "Set the maximum duration of the recording",
title = stringResource(R.string.ui_settings_option_maxDuration_title),
description = stringResource(R.string.ui_settings_option_maxDuration_description),
leading = {
Icon(
Icons.Default.Timer,

View File

@ -15,7 +15,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import app.myzel394.locationtest.R
import app.myzel394.locationtest.dataStore
import app.myzel394.locationtest.db.AppSettings
import app.myzel394.locationtest.db.AudioRecorderSettings
@ -70,7 +72,7 @@ fun OutputFormatTile() {
},
)
SettingsTile(
title = "Output Format",
title = stringResource(R.string.ui_settings_option_outputFormat_title),
leading = {
Icon(
Icons.Default.AudioFile,
@ -87,7 +89,7 @@ fun OutputFormatTile() {
) {
Text(
text = if (settings.audioRecorderSettings.outputFormat == null) {
"Auto"
stringResource(R.string.ui_settings_value_auto_label)
} else {
AudioRecorderSettings.OUTPUT_FORMAT_INDEX_TEXT_MAP[settings.audioRecorderSettings.outputFormat]!!
}
@ -99,9 +101,7 @@ fun OutputFormatTile() {
items = listOf(null),
onItemSelected = ::updateValue,
) {
Text(
text = "Auto"
)
Text(stringResource(R.string.ui_settings_value_auto_label))
}
}
)

View File

@ -13,7 +13,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import app.myzel394.locationtest.R
import app.myzel394.locationtest.dataStore
import app.myzel394.locationtest.db.AppSettings
import app.myzel394.locationtest.db.AudioRecorderSettings
@ -50,13 +52,15 @@ fun SamplingRateTile() {
}
}
val notNumberLabel = stringResource(R.string.form_error_type_notNumber)
val mustBeGreaterThanLabel = stringResource(R.string.form_error_value_mustBeGreaterThan, 1000)
InputDialog(
state = showDialog,
selection = InputSelection(
input = listOf(
InputTextField(
header = InputHeader(
title = "Set the sampling rate",
title = stringResource(R.string.ui_settings_option_samplingRate_explanation),
icon = IconSource(Icons.Default.RadioButtonChecked),
),
keyboardOptions = KeyboardOptions(
@ -68,11 +72,11 @@ fun SamplingRateTile() {
val samplingRate = text?.toIntOrNull()
if (samplingRate == null) {
ValidationResult.Invalid("Please enter a valid number")
ValidationResult.Invalid(notNumberLabel)
}
if (samplingRate!! <= 1000) {
ValidationResult.Invalid("Sampling rate must be greater than 1000")
ValidationResult.Invalid(mustBeGreaterThanLabel)
}
ValidationResult.Valid
@ -87,8 +91,8 @@ fun SamplingRateTile() {
}
)
SettingsTile(
title = "Sampling rate",
description = "Define how many samples per second are taken from the audio signal",
title = stringResource(R.string.ui_settings_option_samplingRate_title),
description = stringResource(R.string.ui_settings_option_samplingRate_description),
leading = {
Icon(
Icons.Default.RadioButtonChecked,
@ -104,7 +108,7 @@ fun SamplingRateTile() {
shape = MaterialTheme.shapes.medium,
) {
Text(
text = (settings.audioRecorderSettings.samplingRate ?: "Auto").toString()
(settings.audioRecorderSettings.samplingRate ?: stringResource(R.string.ui_settings_value_auto_label)).toString()
)
}
},
@ -114,7 +118,7 @@ fun SamplingRateTile() {
onItemSelected = ::updateValue,
) {samplingRate ->
Text(
text = (samplingRate ?: "Auto").toString()
(samplingRate ?: stringResource(R.string.ui_settings_value_auto_label)).toString()
)
}
}

View File

@ -23,7 +23,9 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import app.myzel394.locationtest.R
import app.myzel394.locationtest.ui.BIG_PRIMARY_BUTTON_SIZE
@Composable
@ -50,12 +52,12 @@ fun ExplanationPage(
)
Spacer(modifier = Modifier.height(32.dp))
Text(
"Welcome to Alibi!",
stringResource(R.string.ui_welcome_explanation_title),
style = MaterialTheme.typography.titleLarge,
)
Spacer(modifier = Modifier.height(16.dp))
Text(
"Alibi is like a dashcam for your phone. It allows you to record your audio continuously and save the last 30 minutes when you need it.",
stringResource(R.string.ui_welcome_explanation_message),
)
}
Spacer(modifier = Modifier.weight(1f))
@ -72,7 +74,7 @@ fun ExplanationPage(
modifier = Modifier.size(ButtonDefaults.IconSize)
)
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
Text("Continue")
Text(stringResource(R.string.continue_label))
}
}
}

View File

@ -21,7 +21,9 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import app.myzel394.locationtest.R
import app.myzel394.locationtest.ui.BIG_PRIMARY_BUTTON_SIZE
@Composable
@ -48,12 +50,12 @@ fun ResponsibilityPage(
)
Spacer(modifier = Modifier.height(32.dp))
Text(
"You are solely responsible for the use of this app",
stringResource(R.string.ui_welcome_responsibility_title),
style = MaterialTheme.typography.titleLarge,
)
Spacer(modifier = Modifier.height(16.dp))
Text(
"Alibi does not take any responsibility for the use of this app. You are solely responsible. Use it at your own risk.",
stringResource(R.string.ui_welcome_responsibility_message),
)
}
Spacer(modifier = Modifier.weight(1f))
@ -70,7 +72,7 @@ fun ResponsibilityPage(
modifier = Modifier.size(ButtonDefaults.IconSize)
)
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
Text("Start Alibi")
Text(stringResource(R.string.ui_welcome_start_label))
}
}
}

View File

@ -9,7 +9,6 @@ import androidx.compose.material.icons.filled.OpenInNew
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@ -19,6 +18,8 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import app.myzel394.locationtest.R
import app.myzel394.locationtest.ui.utils.PermissionHelper
import app.myzel394.locationtest.ui.utils.openAppSystemSettings
@ -51,10 +52,10 @@ fun PermissionRequester(
},
icon = icon,
title = {
Text("Permission denied")
Text(stringResource(R.string.ui_permissions_request_title))
},
text = {
Text("Please grant the permission to continue. You will be redirected to the app settings to grant the permission there.")
Text(stringResource(R.string.ui_permissions_request_message))
},
confirmButton = {
Button(
@ -69,7 +70,7 @@ fun PermissionRequester(
modifier = Modifier.size(ButtonDefaults.IconSize),
)
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
Text("OK")
Text(stringResource(R.string.dialog_close_neutral_label))
}
},
dismissButton = {
@ -85,7 +86,7 @@ fun PermissionRequester(
modifier = Modifier.size(ButtonDefaults.IconSize),
)
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
Text("Cancel")
Text(stringResource(R.string.dialog_close_cancel_label))
}
}
)

View File

@ -14,12 +14,14 @@ import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.navigation.NavController
import app.myzel394.locationtest.services.bindToRecorderService
import app.myzel394.locationtest.ui.components.AudioRecorder.molecules.RecordingStatus
import app.myzel394.locationtest.ui.components.AudioRecorder.molecules.StartRecording
import app.myzel394.locationtest.ui.enums.Screen
import app.myzel394.locationtest.ui.utils.rememberFileSaverDialog
import app.myzel394.locationtest.R
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -34,7 +36,7 @@ fun AudioRecorder(
topBar = {
TopAppBar(
title = {
Text("Alibi")
Text(stringResource(R.string.app_name))
},
actions = {
IconButton(

View File

@ -35,8 +35,10 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import app.myzel394.locationtest.R
import app.myzel394.locationtest.dataStore
import app.myzel394.locationtest.db.AppSettings
import app.myzel394.locationtest.db.AudioRecorderSettings
@ -75,7 +77,7 @@ fun SettingsScreen(
topBar = {
LargeTopAppBar(
title = {
Text(text = "Settings")
Text(stringResource(R.string.ui_settings_title))
},
navigationIcon = {
IconButton(onClick = navController::popBackStack) {
@ -113,12 +115,12 @@ fun SettingsScreen(
) {
MessageBox(
type = MessageType.WARNING,
title = "You are recording",
message = "Your changes will be applied the next time you start recording",
title = stringResource(R.string.ui_settings_hint_recordingActive_title),
message = stringResource(R.string.ui_settings_hint_recordingActive_message),
)
}
GlobalSwitch(
label = "Advanced Settings",
label = stringResource(R.string.ui_settings_advancedSettings_label),
checked = settings.showAdvancedSettings,
onCheckedChange = {
scope.launch {

View File

@ -1,3 +1,48 @@
<resources>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name">LocationTest</string>
<string name="dialog_close_cancel_label">Cancel</string>
<string name="dialog_close_neutral_label">OK</string>
<string name="continue_label">Continue</string>
<string name="format_kbps"><xliff:g name="value">%s</xliff:g> KB/s</string>
<string name="form_error_type_notNumber">Please enter a valid number</string>
<string name="form_error_value_notInRange">Please enter a number between <xliff:g name="min">%s</xliff:g> and <xliff:g name="max">%s</xliff:g></string>
<string name="form_error_value_mustBeGreaterThan">Please enter a number greater than <xliff:g name="min">%s</xliff:g></string>
<string name="ui_permissions_request_title">Permission denied</string>
<string name="ui_permissions_request_message">Please grant the permission to continue. You will be redirected to the app settings to grant the permission there.</string>
<string name="ui_audioRecorder_action_start_label">Start Recording</string>
<string name="ui_audioRecorder_action_saveOldRecording_label">Save Recording from <xliff:g name="date">%s</xliff:g></string>
<string name="ui_audioRecorder_action_delete_label">Delete</string>
<string name="ui_audioRecorder_action_delete_confirm_title">Delete Recording?</string>
<string name="ui_audioRecorder_action_delete_confirm_message">Are you sure you want to delete this recording?</string>
<string name="ui_audioRecorder_action_save_label">Save Recording</string>
<string name="ui_welcome_explanation_title">Welcome to Alibi!</string>
<string name="ui_welcome_explanation_message">Alibi is like a dashcam for your phone. It allows you to record your audio continuously and save the last 30 minutes when you need it.</string>
<string name="ui_welcome_responsibility_title">You are solely responsible for the use of this app</string>
<string name="ui_welcome_responsibility_message">Alibi does not take any responsibility for the use of this app. You are solely responsible. Use it at your own risk.</string>
<string name="ui_welcome_start_label">Start Alibi</string>
<string name="ui_settings_title">Settings</string>
<string name="ui_settings_advancedSettings_label">Advanced Settings</string>
<string name="ui_settings_hint_recordingActive_title">You are recording</string>
<string name="ui_settings_hint_recordingActive_message">Your changes will be applied the next time you start recording</string>
<string name="ui_settings_option_maxDuration_title">Max duration</string>
<string name="ui_settings_option_maxDuration_description">Set the maximum duration of the recording</string>
<string name="ui_settings_option_intervalDuration_title">Batch duration</string>
<string name="ui_settings_option_intervalDuration_description">Record a single batch for this duration. Alibi records multiple batches and deletes the oldest one. When exporting the audio, all batches will be merged together</string>
<string name="ui_settings_option_forceExactDuration_title">Force exact duration</string>
<string name="ui_settings_option_forceExactDuration_description">Force to strip the output file to be the exactly specified duration. If this is disabled, the output file may be a bit longer due to batches of audio samples being encoded together.</string>
<string name="ui_settings_option_bitrate_title">Bitrate</string>
<string name="ui_settings_option_bitrate_description">A higher bitrate means better quality but also larger file size</string>
<string name="ui_settings_option_bitrate_explanation">Set the bitrate for the audio recording</string>
<string name="ui_settings_option_outputFormat_title">Output Format</string>
<string name="ui_settings_value_auto_label">Auto</string>
<string name="ui_settings_option_samplingRate_title">Sampling rate</string>
<string name="ui_settings_option_samplingRate_description">Define how many samples per second are taken from the audio signal</string>
<string name="ui_settings_option_samplingRate_explanation">Set the sampling rate</string>
<string name="ui_settings_option_encoder_title">Encoder</string>
</resources>