commit debed0496a59a9ba77c89b1d795ae8d27a870449
parent 80302eb67ec2ae535f377c4a1916f5f401708970
Author: MTRNord <MTRNord@users.noreply.github.com>
Date: Tue, 29 Jul 2025 15:44:57 +0200
Improve and translate the EventDetailsView
Diffstat:
6 files changed, 330 insertions(+), 60 deletions(-)
diff --git a/app/src/main/java/space/midnightthoughts/nordiccalendar/NordicCalendarApp.kt b/app/src/main/java/space/midnightthoughts/nordiccalendar/NordicCalendarApp.kt
@@ -1,7 +1,22 @@
package space.midnightthoughts.nordiccalendar
import android.app.Application
+import android.app.LocaleManager
+import android.content.Context
+import android.os.Build
+import android.os.LocaleList
import dagger.hilt.android.HiltAndroidApp
+import java.util.Locale
@HiltAndroidApp
class NordicCalendarApp : Application()
+
+fun getCurrentAppLocale(context: Context): Locale {
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ val localeManager = context.getSystemService(LocaleManager::class.java)
+ val appLocales: LocaleList = localeManager.applicationLocales
+ if (!appLocales.isEmpty) appLocales[0] else Locale.getDefault()
+ } else {
+ Locale.getDefault()
+ }
+}
diff --git a/app/src/main/java/space/midnightthoughts/nordiccalendar/screens/CalendarScreen.kt b/app/src/main/java/space/midnightthoughts/nordiccalendar/screens/CalendarScreen.kt
@@ -3,8 +3,11 @@ package space.midnightthoughts.nordiccalendar.screens
import android.annotation.SuppressLint
import android.util.Log
import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -47,6 +50,9 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.StrokeCap
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
@@ -58,12 +64,13 @@ import androidx.navigation.NavController
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import space.midnightthoughts.nordiccalendar.R
+import space.midnightthoughts.nordiccalendar.getCurrentAppLocale
import space.midnightthoughts.nordiccalendar.util.Event
import space.midnightthoughts.nordiccalendar.viewmodels.CalendarViewModel
-import java.text.SimpleDateFormat
+import java.time.ZoneId
+import java.time.format.DateTimeFormatter
import java.util.Calendar
import java.util.Date
-import java.util.Locale
@SuppressLint("UnusedBoxWithConstraintsScope")
@@ -180,7 +187,8 @@ fun DayView(
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
- val hourFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
+ val appLocale = getCurrentAppLocale(LocalContext.current)
+ val hourFormat = DateTimeFormatter.ofPattern("HH:mm", appLocale)
val scrollState = rememberScrollState()
val coroutineScope = rememberCoroutineScope()
var now by remember { mutableLongStateOf(System.currentTimeMillis()) }
@@ -217,7 +225,8 @@ fun DayView(
.padding(horizontal = 8.dp, vertical = 4.dp)
) {
Text(
- hourFormat.format(Date(dayStart + hour * 60 * 60 * 1000)),
+ Date(dayStart + hour * 60 * 60 * 1000).toInstant()
+ .atZone(ZoneId.systemDefault()).toLocalDateTime().format(hourFormat),
style = MaterialTheme.typography.labelMedium,
modifier = Modifier.width(timeColumnWidth)
)
@@ -260,7 +269,6 @@ fun DayView(
EventCard(
event = event,
isCompact = isCompact,
- hourFormat = hourFormat,
onClick = { navController.navigate("eventDetails/${event.eventId}") },
modifier = Modifier
.width(with(density) { columnWidthPx.toDp() })
@@ -278,13 +286,23 @@ fun DayView(
.offset { IntOffset(0, nowOffsetY.toInt()) },
verticalAlignment = Alignment.CenterVertically
) {
- Text(
- stringResource(R.string.now),
- color = lineColor,
- style = MaterialTheme.typography.labelSmall,
- modifier = Modifier.padding(start = 16.dp, end = 24.dp)
- )
- androidx.compose.foundation.Canvas(
+ Box(
+ modifier = Modifier
+ .padding(start = 4.dp)
+ .background(
+ color = lineColor,
+ shape = MaterialTheme.shapes.small
+ )
+ .padding(horizontal = 12.dp, vertical = 4.dp)
+ ) {
+ Text(
+ Date(now).toInstant()
+ .atZone(ZoneId.systemDefault()).toLocalDateTime().format(hourFormat),
+ color = MaterialTheme.colorScheme.onError,
+ style = MaterialTheme.typography.labelSmall
+ )
+ }
+ Canvas(
modifier = Modifier
.fillMaxWidth()
.height(lineThickness)
@@ -292,7 +310,7 @@ fun DayView(
) {
drawLine(
color = lineColor,
- start = androidx.compose.ui.geometry.Offset(
+ start = Offset(
0f,
size.height / 2
),
@@ -301,7 +319,7 @@ fun DayView(
size.height / 2
),
strokeWidth = size.height,
- cap = androidx.compose.ui.graphics.StrokeCap.Round
+ cap = StrokeCap.Round
)
}
}
@@ -341,19 +359,28 @@ fun DateRangeHeader(
val endMillis = remember(calendarViewModel) {
calendarViewModel.endMillis
}.collectAsState(initial = System.currentTimeMillis())
- val dateFormat = when (selectedTab) {
- 0, 1 -> SimpleDateFormat("dd.MM.yyyy", Locale.getDefault())
- 2 -> SimpleDateFormat("dd.MM.yyyy", Locale.getDefault())
- else -> SimpleDateFormat("dd.MM.yyyy", Locale.getDefault())
+ val appLocale = getCurrentAppLocale(LocalContext.current)
+ val dateFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy", appLocale)
+
+ val startDate = remember(startMillis.value) {
+ Date(startMillis.value)
+ }
+ val endDate = remember(endMillis.value) {
+ Date(endMillis.value)
}
+
val rangeText = when (selectedTab) {
- 0, 1 -> dateFormat.format(Date(startMillis.value)) + " – " + dateFormat.format(
- Date(
- endMillis.value
- )
- )
+ 0, 1 -> "${
+ startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
+ .format(dateFormat)
+ } – ${
+ endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().format(dateFormat)
+ }"
+
+ 2 -> startDate.toInstant()
+ .atZone(ZoneId.systemDefault()).toLocalDate()
+ .format(dateFormat)
- 2 -> dateFormat.format(Date(startMillis.value))
else -> ""
}
val isToday = when (selectedTab) {
@@ -419,10 +446,18 @@ fun DateRangeHeader(
fun EventCard(
event: Event,
isCompact: Boolean,
- hourFormat: SimpleDateFormat,
modifier: Modifier = Modifier,
onClick: (() -> Unit)? = null
) {
+ val appLocale = getCurrentAppLocale(LocalContext.current)
+ val hourFormat = DateTimeFormatter.ofPattern("HH:mm", appLocale)
+ val startDate = remember(event.startTime) {
+ Date(event.startTime)
+ }
+ val endDate = remember(event.endTime) {
+ Date(event.endTime)
+ }
+
Card(
modifier = modifier
.defaultMinSize(minHeight = 24.dp)
@@ -451,7 +486,13 @@ fun EventCard(
if (!isCompact) {
Spacer(modifier = Modifier.height(4.dp))
Text(
- hourFormat.format(Date(event.startTime)) + " - " + hourFormat.format(Date(event.endTime)),
+ "${
+ startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
+ .format(hourFormat)
+ } - ${
+ endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
+ .format(hourFormat)
+ }",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.primary
)
@@ -481,12 +522,21 @@ fun EventCardPreview() {
calendarId = 1L,
location = "Beispielort",
allDay = false,
- organizer = "Beispielorganisator"
+ organizer = "Beispielorganisator",
+ calendar = space.midnightthoughts.nordiccalendar.util.Calendar(
+ id = 1L,
+ name = "Beispielkalender",
+ color = 0xFF6200EE, // Beispiel-Farbe
+ selected = true,
+ accountName = "Beispielkonto",
+ accountType = "com.example",
+ syncEvents = true,
+ visible = true
+ )
)
EventCard(
event = sampleEvent,
isCompact = false,
- hourFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
)
}
diff --git a/app/src/main/java/space/midnightthoughts/nordiccalendar/screens/EventDetailsView.kt b/app/src/main/java/space/midnightthoughts/nordiccalendar/screens/EventDetailsView.kt
@@ -1,11 +1,19 @@
package space.midnightthoughts.nordiccalendar.screens
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.DividerDefaults
@@ -15,9 +23,13 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavBackStackEntry
@@ -25,9 +37,12 @@ import androidx.navigation.NavHostController
import sh.calvin.autolinktext.rememberAutoLinkText
import space.midnightthoughts.nordiccalendar.R
import space.midnightthoughts.nordiccalendar.components.AppScaffold
+import space.midnightthoughts.nordiccalendar.getCurrentAppLocale
import space.midnightthoughts.nordiccalendar.viewmodels.EventDetailsViewModel
-import java.text.SimpleDateFormat
-import java.util.Locale
+import java.time.ZoneId
+import java.time.format.DateTimeFormatter
+import java.util.Calendar
+import java.util.Date
@Composable
fun EventDetailsView(
@@ -38,7 +53,28 @@ fun EventDetailsView(
val event = remember(viewModel) {
viewModel.event
}.collectAsState(initial = null)
- val dateTimeFormat = SimpleDateFormat("dd.MM.yyyy HH:mm", Locale.getDefault())
+ val startDate = remember(event.value?.startTime) {
+ Date(event.value?.startTime ?: 0L)
+ }
+ val endDate = remember(event.value?.endTime) {
+ Date(event.value?.endTime ?: 0L)
+ }
+ val startCalendar = remember(startDate) {
+ val calendar = Calendar.getInstance()
+ calendar.time = startDate
+ calendar
+ }
+ val endCalendar = remember(endDate) {
+ val calendar = Calendar.getInstance()
+ calendar.time = endDate
+ calendar
+ }
+
+ val appLocale = getCurrentAppLocale(
+ LocalContext.current
+ )
+ val dateFormat = DateTimeFormatter.ofPattern("EEEE, dd.MM.yyyy", appLocale)
+ val timeFormat = DateTimeFormatter.ofPattern("HH:mm", appLocale)
val scrollState = rememberScrollState()
@@ -55,56 +91,178 @@ fun EventDetailsView(
Column(
modifier = Modifier
.verticalScroll(scrollState)
- .padding(24.dp)
+ .padding(16.dp)
.fillMaxSize(),
) {
if (event.value != null) {
Text(
- dateTimeFormat.format(
- java.util.Date(
- event.value?.startTime ?: 0L
+ // Check if the event is starting and ending on the same day or not
+ text = if (startCalendar.get(Calendar.DAY_OF_YEAR) == endCalendar.get(
+ Calendar.DAY_OF_YEAR
)
- ) + " - " + dateTimeFormat.format(
- java.util.Date(event.value?.endTime ?: 0L)
- ),
+ && startCalendar.get(Calendar.YEAR) == endCalendar.get(Calendar.YEAR)
+ ) {
+ startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
+ .format(dateFormat)
+ } else {
+ stringResource(
+ R.string.event_date_range,
+ startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
+ .format(dateFormat),
+ endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
+ .format(dateFormat)
+ )
+ },
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.primary,
)
- if (!event.value?.location.isNullOrBlank()) {
- Spacer(modifier = Modifier.height(16.dp))
+ Text(
+ text = stringResource(
+ R.string.event_time_range,
+ startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalTime()
+ .format(timeFormat),
+ endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalTime()
+ .format(timeFormat)
+ ),
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.colorScheme.primary,
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ HorizontalDivider(
+ Modifier,
+ DividerDefaults.Thickness,
+ color = MaterialTheme.colorScheme.outlineVariant
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ verticalAlignment = Alignment.Top,
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
Text(
- text = AnnotatedString.rememberAutoLinkText(
- event.value?.location ?: ""
- ),
- style = MaterialTheme.typography.labelLarge.copy(color = MaterialTheme.colorScheme.onSurface),
- modifier = Modifier.padding(bottom = 4.dp)
+ text = stringResource(R.string.calendar_label),
+ style = MaterialTheme.typography.titleMedium,
+ fontWeight = FontWeight.Bold
)
+ Spacer(modifier = Modifier.width(48.dp))
+ Row(
+ modifier = Modifier.fillMaxSize(),
+ verticalAlignment = Alignment.Top,
+ horizontalArrangement = Arrangement.Start
+ ) {
+ if (event.value?.calendar?.color != null) {
+ // Round color dot
+ Box(
+ modifier = Modifier
+ .padding(top = 4.dp)
+ .size(16.dp)
+ .background(
+ color = if (event.value?.calendar?.color != null) {
+ Color(event.value?.calendar?.color ?: 0)
+ } else {
+ MaterialTheme.colorScheme.primary
+ },
+ shape = CircleShape
+ )
+ )
+ Spacer(modifier = Modifier.width(8.dp))
+ }
+ Text(
+ text = event.value?.calendar?.name ?: "",
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.colorScheme.onSurface,
+ )
+ }
}
- if (!event.value?.organizer.isNullOrBlank()) {
- Spacer(modifier = Modifier.height(16.dp))
+ Spacer(modifier = Modifier.height(16.dp))
+ HorizontalDivider(
+ Modifier,
+ DividerDefaults.Thickness,
+ color = MaterialTheme.colorScheme.outlineVariant
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ verticalAlignment = Alignment.Top,
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ Text(
+ text = stringResource(R.string.organizer),
+ style = MaterialTheme.typography.titleMedium,
+ fontWeight = FontWeight.Bold
+ )
+ Spacer(modifier = Modifier.width(24.dp))
Text(
- event.value?.organizer ?: "",
- style = MaterialTheme.typography.labelLarge,
+ text = if (event.value?.organizer?.trim().isNullOrEmpty()) {
+ stringResource(R.string.no_organizer_available)
+ } else {
+ event.value?.organizer ?: ""
+ },
+ style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurface,
)
}
- Spacer(modifier = Modifier.height(24.dp))
+ Spacer(modifier = Modifier.height(16.dp))
HorizontalDivider(
Modifier,
DividerDefaults.Thickness,
color = MaterialTheme.colorScheme.outlineVariant
)
- if (!event.value?.description.isNullOrBlank()) {
- Spacer(modifier = Modifier.height(24.dp))
+ Spacer(modifier = Modifier.height(16.dp))
+ // TODO: map if location is a valid address
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ verticalAlignment = Alignment.Top,
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ Text(
+ text = stringResource(R.string.location),
+ style = MaterialTheme.typography.titleMedium,
+ fontWeight = FontWeight.Bold
+ )
+ Spacer(modifier = Modifier.width(24.dp))
+ Text(
+ text = if (event.value?.location?.trim().isNullOrEmpty()) {
+ stringResource(R.string.no_location_available)
+ } else {
+ event.value?.location ?: ""
+ },
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.colorScheme.onSurface,
+ )
+ }
+ // TODO: Invitees and attendees and alerts
+ Spacer(modifier = Modifier.height(16.dp))
+ HorizontalDivider(
+ Modifier,
+ DividerDefaults.Thickness,
+ color = MaterialTheme.colorScheme.outlineVariant
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ Column(
+ modifier = Modifier.fillMaxWidth(),
+ verticalArrangement = Arrangement.spacedBy(8.dp),
+ ) {
+ Text(
+ text = stringResource(R.string.description),
+ style = MaterialTheme.typography.titleMedium,
+ fontWeight = FontWeight.Bold
+ )
+ Spacer(modifier = Modifier.height(8.dp))
Text(
text = AnnotatedString.rememberAutoLinkText(
- event.value?.description ?: ""
+ if (event.value?.description?.trim().isNullOrEmpty()) {
+ stringResource(R.string.no_description_available)
+ } else {
+ event.value?.description ?: ""
+ }
),
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onSurface),
)
}
+
} else {
Text(
stringResource(
@@ -113,7 +271,9 @@ fun EventDetailsView(
)
)
Spacer(modifier = Modifier.height(24.dp))
- Text("Event nicht gefunden oder wird geladen...")
+ Text(
+ stringResource(R.string.event_not_found),
+ )
}
}
}
diff --git a/app/src/main/java/space/midnightthoughts/nordiccalendar/util/CalendarData.kt b/app/src/main/java/space/midnightthoughts/nordiccalendar/util/CalendarData.kt
@@ -9,12 +9,11 @@ import android.util.Log
data class Calendar(
val id: Long,
val name: String,
- val color: Int,
+ val color: Long,
val accountName: String,
val accountType: String,
val syncEvents: Boolean,
val visible: Boolean,
- // TODO: Store this somewhere so it is kept across app restarts
val selected: Boolean = true
)
@@ -29,7 +28,9 @@ data class Event(
val location: String?,
val allDay: Boolean,
val organizer: String?,
- val attendees: List<String> = emptyList()
+ val attendees: List<String> = emptyList(),
+ // Reference to the calendar this event belongs to
+ val calendar: Calendar
)
// Helper for the android calendar provider/CalendarContract
@@ -72,7 +73,7 @@ class CalendarData {
val calId = cur.getLong(PROJECTION_ID_INDEX)
val displayName = cur.getString(PROJECTION_DISPLAY_NAME_INDEX)
val name = cur.getString(PROJECTION_NAME_INDEX)
- val color = cur.getInt(PROJECTION_CALENDAR_COLOR_INDEX)
+ val color = cur.getLong(PROJECTION_CALENDAR_COLOR_INDEX)
val visible = cur.getInt(PROJECTION_VISIBLE_INDEX)
val syncEvents = cur.getInt(PROJECTION_SYNC_EVENTS_INDEX)
val accountName = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX)
@@ -173,7 +174,17 @@ class CalendarData {
calendarId = calId,
location = location,
allDay = allDay,
- organizer = organizer
+ organizer = organizer,
+ calendar = getCalendars(contentResolver).firstOrNull { it.id == calId }
+ ?: Calendar(
+ id = calId,
+ name = "Unknown Calendar",
+ color = 0xFF000000, // Default black color
+ accountName = "Unknown Account",
+ accountType = "Unknown Type",
+ syncEvents = false,
+ visible = false
+ ) // Fallback if calendar not found
)
)
}
@@ -277,7 +288,17 @@ class CalendarData {
calendarId = cur.getLong(6),
location = cur.getString(7),
allDay = cur.getInt(8) == 1,
- organizer = cur.getString(9)
+ organizer = cur.getString(9),
+ calendar = getCalendars(contentResolver).firstOrNull { it.id == cur.getLong(6) }
+ ?: Calendar(
+ id = cur.getLong(6),
+ name = "Unknown Calendar",
+ color = 0xFF000000, // Default black color
+ accountName = "Unknown Account",
+ accountType = "Unknown Type",
+ syncEvents = false,
+ visible = false
+ ) // Fallback if calendar not found
)
} else null
cur?.close()
diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml
@@ -26,5 +26,17 @@
<string name="tab_week">Week</string>
<string name="tab_day">Day</string>
<string name="now">Now</string>
+ <string name="calendar_label">Calendar:</string>
+ <string name="organizer">Organizer:</string>
+ <string name="no_organizer_available">No organizer available</string>
+ <string name="attendees">Attendees:</string>
+ <string name="no_attendees_available">No attendees available</string>
+ <string name="location">Location:</string>
+ <string name="no_location_available">No location specified</string>
+ <string name="description">Description:</string>
+ <string name="no_description_available">No description available</string>
+ <string name="event_not_found">Event not found or loading…</string>
+ <string name="event_time_range">From %1$s to %2$s</string>
+ <string name="event_date_range">%1$s until %2$s</string>
</resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
@@ -26,5 +26,17 @@
<string name="tab_week">Woche</string>
<string name="tab_day">Tag</string>
<string name="now">Jetzt</string>
+ <string name="calendar_label">Kalender:</string>
+ <string name="organizer">Organisator:</string>
+ <string name="no_organizer_available">Kein Organisator gefunden</string>
+ <string name="attendees">Teilnehmer:</string>
+ <string name="no_attendees_available">Keine Teilnehmer gefunden</string>
+ <string name="location">Ort:</string>
+ <string name="no_location_available">Kein Ort angegeben</string>
+ <string name="description">Beschreibung:</string>
+ <string name="no_description_available">Keine Beschreibung verfügbar</string>
+ <string name="event_not_found">Event nicht gefunden oder wird geladen…</string>
+ <string name="event_time_range">Von %1$s bis %2$s</string>
+ <string name="event_date_range">%1$s bis %2$s</string>
</resources>