mirror of
https://github.com/spalencsar/bearwave.git
synced 2026-07-06 22:24:17 +02:00
Add English and German UI localization
This commit is contained in:
@@ -10,7 +10,7 @@ set(CMAKE_AUTORCC ON)
|
|||||||
set(CMAKE_AUTOUIC ON)
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
|
||||||
# Qt6
|
# Qt6
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Core DBus Quick QuickControls2 Widgets)
|
find_package(Qt6 REQUIRED COMPONENTS Core DBus Quick QuickControls2 Widgets LinguistTools)
|
||||||
|
|
||||||
# KDE Frameworks
|
# KDE Frameworks
|
||||||
find_package(KF6Kirigami REQUIRED)
|
find_package(KF6Kirigami REQUIRED)
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -121,13 +121,14 @@ If support for other distributions becomes reliable, they should be added here e
|
|||||||
|
|
||||||
### Language Support
|
### Language Support
|
||||||
|
|
||||||
The current application UI is primarily in German.
|
BearWave currently supports English and German.
|
||||||
|
|
||||||
- UI labels, dialogs, and user-facing controls are currently mostly German
|
- the application uses the system locale to select its UI language
|
||||||
- README, repository metadata, and development-facing material are in English
|
- English is the base UI language
|
||||||
- full localization support is not implemented yet
|
- German is provided as a bundled translation
|
||||||
|
- README, repository metadata, and development-facing material remain in English
|
||||||
|
|
||||||
If you expect a fully translated multi-language UI, that is not the current state yet.
|
If the system language is German, BearWave appears in German. Otherwise it falls back to English.
|
||||||
|
|
||||||
## Installation Status
|
## Installation Status
|
||||||
|
|
||||||
@@ -284,7 +285,6 @@ If desktop caches are stale, a logout/login cycle may still be required.
|
|||||||
|
|
||||||
## Current Limitations
|
## Current Limitations
|
||||||
|
|
||||||
- UI language is currently primarily German
|
|
||||||
- packaging and install guidance are strongest on Arch Linux
|
- packaging and install guidance are strongest on Arch Linux
|
||||||
- broader distro support is not yet validated to the same standard
|
- broader distro support is not yet validated to the same standard
|
||||||
- there are no official binary releases for non-technical end users yet
|
- there are no official binary releases for non-technical end users yet
|
||||||
|
|||||||
@@ -18,6 +18,22 @@ add_executable(bearwave ${SOURCES})
|
|||||||
# Qt Resources
|
# Qt Resources
|
||||||
target_sources(bearwave PRIVATE qml.qrc)
|
target_sources(bearwave PRIVATE qml.qrc)
|
||||||
|
|
||||||
|
qt_add_lrelease(
|
||||||
|
TS_FILES
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/../translations/bearwave_de.ts
|
||||||
|
QM_FILES_OUTPUT_VARIABLE bearwave_qm_files
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach(qm_file IN LISTS bearwave_qm_files)
|
||||||
|
get_filename_component(qm_name "${qm_file}" NAME)
|
||||||
|
set_source_files_properties("${qm_file}" PROPERTIES QT_RESOURCE_ALIAS "${qm_name}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
qt_add_resources(bearwave bearwave_translations
|
||||||
|
PREFIX /i18n
|
||||||
|
FILES ${bearwave_qm_files}
|
||||||
|
)
|
||||||
|
|
||||||
# Link libraries
|
# Link libraries
|
||||||
target_link_libraries(bearwave PRIVATE
|
target_link_libraries(bearwave PRIVATE
|
||||||
Qt6::Core
|
Qt6::Core
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDBusConnection>
|
#include <QDBusConnection>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
|
#include <QLocale>
|
||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
|
#include <QTranslator>
|
||||||
|
|
||||||
#include "radiobackend.h"
|
#include "radiobackend.h"
|
||||||
#include "mprisadaptor.h"
|
#include "mprisadaptor.h"
|
||||||
@@ -20,6 +22,11 @@ int main(int argc, char *argv[])
|
|||||||
app.setWindowIcon(QIcon::fromTheme(QStringLiteral("org.kde.bearwave")));
|
app.setWindowIcon(QIcon::fromTheme(QStringLiteral("org.kde.bearwave")));
|
||||||
app.setQuitOnLastWindowClosed(false);
|
app.setQuitOnLastWindowClosed(false);
|
||||||
|
|
||||||
|
QTranslator appTranslator;
|
||||||
|
if (appTranslator.load(QLocale::system(), QStringLiteral("bearwave"), QStringLiteral("_"), QStringLiteral(":/i18n"))) {
|
||||||
|
app.installTranslator(&appTranslator);
|
||||||
|
}
|
||||||
|
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
|
|
||||||
RadioBackend backend;
|
RadioBackend backend;
|
||||||
|
|||||||
104
src/qml/Main.qml
104
src/qml/Main.qml
@@ -5,7 +5,7 @@ import Qt.labs.platform 1.1 as Platform
|
|||||||
|
|
||||||
ApplicationWindow {
|
ApplicationWindow {
|
||||||
id: root
|
id: root
|
||||||
title: "BearWave"
|
title: qsTr("BearWave")
|
||||||
width: 980
|
width: 980
|
||||||
height: 700
|
height: 700
|
||||||
minimumWidth: 520
|
minimumWidth: 520
|
||||||
@@ -21,11 +21,11 @@ ApplicationWindow {
|
|||||||
id: systray
|
id: systray
|
||||||
visible: true
|
visible: true
|
||||||
icon.name: "multimedia-player"
|
icon.name: "multimedia-player"
|
||||||
tooltip: "BearWave"
|
tooltip: qsTr("BearWave")
|
||||||
|
|
||||||
menu: Platform.Menu {
|
menu: Platform.Menu {
|
||||||
Platform.MenuItem {
|
Platform.MenuItem {
|
||||||
text: backend && backend.player && backend.player.playing ? "Pause" : "Play"
|
text: backend && backend.player && backend.player.playing ? qsTr("Pause") : qsTr("Play")
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (backend && backend.player) {
|
if (backend && backend.player) {
|
||||||
backend.player.togglePlayPause()
|
backend.player.togglePlayPause()
|
||||||
@@ -33,7 +33,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Platform.MenuItem {
|
Platform.MenuItem {
|
||||||
text: root.visible ? "Verstecken" : "Zeigen"
|
text: root.visible ? qsTr("Hide") : qsTr("Show")
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (root.visible) {
|
if (root.visible) {
|
||||||
root.hide()
|
root.hide()
|
||||||
@@ -46,7 +46,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
Platform.MenuSeparator {}
|
Platform.MenuSeparator {}
|
||||||
Platform.MenuItem {
|
Platform.MenuItem {
|
||||||
text: "Beenden"
|
text: qsTr("Quit")
|
||||||
onTriggered: Qt.quit()
|
onTriggered: Qt.quit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,7 +142,7 @@ ApplicationWindow {
|
|||||||
spacing: 8
|
spacing: 8
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: "BearWave"
|
text: qsTr("BearWave")
|
||||||
color: textMain
|
color: textMain
|
||||||
font.pixelSize: compactMode ? 18 : 22
|
font.pixelSize: compactMode ? 18 : 22
|
||||||
font.bold: true
|
font.bold: true
|
||||||
@@ -156,7 +156,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: "Top"
|
text: qsTr("Top")
|
||||||
highlighted: currentPage === "top"
|
highlighted: currentPage === "top"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!backend) return
|
if (!backend) return
|
||||||
@@ -167,7 +167,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: "DE"
|
text: qsTr("DE")
|
||||||
highlighted: currentPage === "german"
|
highlighted: currentPage === "german"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!backend) return
|
if (!backend) return
|
||||||
@@ -178,7 +178,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: "NL"
|
text: qsTr("NL")
|
||||||
highlighted: currentPage === "dutch"
|
highlighted: currentPage === "dutch"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!backend) return
|
if (!backend) return
|
||||||
@@ -189,7 +189,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: "Favoriten"
|
text: qsTr("Favorites")
|
||||||
highlighted: currentPage === "favorites"
|
highlighted: currentPage === "favorites"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
currentPage = "favorites"
|
currentPage = "favorites"
|
||||||
@@ -200,18 +200,18 @@ ApplicationWindow {
|
|||||||
Item { Layout.fillWidth: true }
|
Item { Layout.fillWidth: true }
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: compactMode ? "+" : "Manuell +"
|
text: compactMode ? "+" : qsTr("Manual +")
|
||||||
onClicked: addDialog.open()
|
onClicked: addDialog.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: "About"
|
text: qsTr("About")
|
||||||
onClicked: aboutDialog.open()
|
onClicked: aboutDialog.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
visible: backend && backend.canResumeLastStation
|
visible: backend && backend.canResumeLastStation
|
||||||
text: compactMode ? "↺" : "Resume"
|
text: compactMode ? "↺" : qsTr("Resume")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (backend) {
|
if (backend) {
|
||||||
backend.resumeLastStation()
|
backend.resumeLastStation()
|
||||||
@@ -227,7 +227,7 @@ ApplicationWindow {
|
|||||||
TextField {
|
TextField {
|
||||||
id: searchField
|
id: searchField
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
placeholderText: "Sender suchen (Name, Genre, Land)"
|
placeholderText: qsTr("Search stations (name, genre, country)")
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
if (backend) {
|
if (backend) {
|
||||||
backend.filterQuery = text
|
backend.filterQuery = text
|
||||||
@@ -241,7 +241,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: "Suche"
|
text: qsTr("Search")
|
||||||
highlighted: true
|
highlighted: true
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (searchField.text.length < 2 || !backend) return
|
if (searchField.text.length < 2 || !backend) return
|
||||||
@@ -251,7 +251,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: compactMode ? "A-Z" : "Sort A-Z"
|
text: compactMode ? "A-Z" : qsTr("Sort A-Z")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (backend && currentPage !== "favorites") {
|
if (backend && currentPage !== "favorites") {
|
||||||
backend.sortStations("name")
|
backend.sortStations("name")
|
||||||
@@ -260,7 +260,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: compactMode ? "kb" : "Sort Bitrate"
|
text: compactMode ? "kb" : qsTr("Sort Bitrate")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (backend && currentPage !== "favorites") {
|
if (backend && currentPage !== "favorites") {
|
||||||
backend.sortStations("bitrate")
|
backend.sortStations("bitrate")
|
||||||
@@ -269,7 +269,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: compactMode ? "❤" : "Sort Votes"
|
text: compactMode ? "❤" : qsTr("Sort Votes")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (backend && currentPage !== "favorites") {
|
if (backend && currentPage !== "favorites") {
|
||||||
backend.sortStations("votes")
|
backend.sortStations("votes")
|
||||||
@@ -280,7 +280,7 @@ ApplicationWindow {
|
|||||||
|
|
||||||
Label {
|
Label {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: "Tipp: Du bist nicht auf DE/NL begrenzt - suche nach Ländern, Genres oder Sendernamen weltweit."
|
text: qsTr("Tip: you are not limited to DE/NL. Search worldwide by country, genre, or station name.")
|
||||||
color: textMuted
|
color: textMuted
|
||||||
font.pixelSize: 11
|
font.pixelSize: 11
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
@@ -291,13 +291,13 @@ ApplicationWindow {
|
|||||||
spacing: 6
|
spacing: 6
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: "Genre:"
|
text: qsTr("Genre:")
|
||||||
color: textMuted
|
color: textMuted
|
||||||
font.pixelSize: 11
|
font.pixelSize: 11
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: "Rock"
|
text: qsTr("Rock")
|
||||||
highlighted: activeQuickFilter === "tag:rock"
|
highlighted: activeQuickFilter === "tag:rock"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!backend) return
|
if (!backend) return
|
||||||
@@ -308,7 +308,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: "News"
|
text: qsTr("News")
|
||||||
highlighted: activeQuickFilter === "tag:news"
|
highlighted: activeQuickFilter === "tag:news"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!backend) return
|
if (!backend) return
|
||||||
@@ -319,7 +319,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: "Jazz"
|
text: qsTr("Jazz")
|
||||||
highlighted: activeQuickFilter === "tag:jazz"
|
highlighted: activeQuickFilter === "tag:jazz"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!backend) return
|
if (!backend) return
|
||||||
@@ -332,13 +332,13 @@ ApplicationWindow {
|
|||||||
Item { Layout.preferredWidth: 10 }
|
Item { Layout.preferredWidth: 10 }
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: "Land:"
|
text: qsTr("Country:")
|
||||||
color: textMuted
|
color: textMuted
|
||||||
font.pixelSize: 11
|
font.pixelSize: 11
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: "US"
|
text: qsTr("US")
|
||||||
highlighted: activeQuickFilter === "cc:US"
|
highlighted: activeQuickFilter === "cc:US"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!backend) return
|
if (!backend) return
|
||||||
@@ -349,7 +349,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: "UK"
|
text: qsTr("UK")
|
||||||
highlighted: activeQuickFilter === "cc:GB"
|
highlighted: activeQuickFilter === "cc:GB"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!backend) return
|
if (!backend) return
|
||||||
@@ -360,7 +360,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: "FR"
|
text: qsTr("FR")
|
||||||
highlighted: activeQuickFilter === "cc:FR"
|
highlighted: activeQuickFilter === "cc:FR"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!backend) return
|
if (!backend) return
|
||||||
@@ -371,7 +371,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: "WORLD"
|
text: qsTr("WORLD")
|
||||||
highlighted: activeQuickFilter === "world"
|
highlighted: activeQuickFilter === "world"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!backend) return
|
if (!backend) return
|
||||||
@@ -387,7 +387,7 @@ ApplicationWindow {
|
|||||||
Label {
|
Label {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
visible: backend && backend.lastError.length > 0
|
visible: backend && backend.lastError.length > 0
|
||||||
text: backend ? ("Fehler: " + backend.lastError) : ""
|
text: backend ? (qsTr("Error: ") + backend.lastError) : ""
|
||||||
color: warn
|
color: warn
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
font.pixelSize: 12
|
font.pixelSize: 12
|
||||||
@@ -473,7 +473,7 @@ ApplicationWindow {
|
|||||||
|
|
||||||
Label {
|
Label {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "FM"
|
text: qsTr("FM")
|
||||||
color: "#d8ecff"
|
color: "#d8ecff"
|
||||||
font.bold: true
|
font.bold: true
|
||||||
visible: !parent.children[0].visible
|
visible: !parent.children[0].visible
|
||||||
@@ -496,7 +496,7 @@ ApplicationWindow {
|
|||||||
Label {
|
Label {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: stationCard.modelData.country + " • "
|
text: stationCard.modelData.country + " • "
|
||||||
+ (stationCard.modelData.bitrate > 0 ? stationCard.modelData.bitrate + " kbps" : "Stream")
|
+ (stationCard.modelData.bitrate > 0 ? stationCard.modelData.bitrate + " kbps" : qsTr("Stream"))
|
||||||
color: textMuted
|
color: textMuted
|
||||||
font.pixelSize: 11
|
font.pixelSize: 11
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
@@ -510,7 +510,7 @@ ApplicationWindow {
|
|||||||
onClicked: {
|
onClicked: {
|
||||||
if (!backend) return
|
if (!backend) return
|
||||||
backend.toggleFavoriteById(stationCard.modelData.uuid, stationCard.modelData.urlResolved)
|
backend.toggleFavoriteById(stationCard.modelData.uuid, stationCard.modelData.urlResolved)
|
||||||
toast(stationCard.modelData.isFavorite ? "Aus Favoriten entfernt" : "Zu Favoriten hinzugefügt")
|
toast(stationCard.modelData.isFavorite ? qsTr("Removed from favorites") : qsTr("Added to favorites"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,13 +538,13 @@ ApplicationWindow {
|
|||||||
visible: stationList.count === 0
|
visible: stationList.count === 0
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: "Noch keine Sender geladen"
|
text: qsTr("No stations loaded yet")
|
||||||
color: textMain
|
color: textMain
|
||||||
font.bold: true
|
font.bold: true
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: "Lade DE/NL oder nutze die Suche"
|
text: qsTr("Load DE/NL stations or use search")
|
||||||
color: textMuted
|
color: textMuted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -588,7 +588,7 @@ ApplicationWindow {
|
|||||||
|
|
||||||
Label {
|
Label {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: backend && backend.player ? (backend.player.currentStationName || "Kein Sender ausgewählt") : "Kein Sender ausgewählt"
|
text: backend && backend.player ? (backend.player.currentStationName || qsTr("No station selected")) : qsTr("No station selected")
|
||||||
color: textMain
|
color: textMain
|
||||||
font.pixelSize: 16
|
font.pixelSize: 16
|
||||||
font.bold: true
|
font.bold: true
|
||||||
@@ -598,8 +598,8 @@ ApplicationWindow {
|
|||||||
Label {
|
Label {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: backend && backend.player && backend.player.currentNowPlaying.length > 0
|
text: backend && backend.player && backend.player.currentNowPlaying.length > 0
|
||||||
? ("Jetzt läuft: " + backend.player.currentNowPlaying)
|
? (qsTr("Now playing: ") + backend.player.currentNowPlaying)
|
||||||
: "Jetzt läuft: Keine Titelinfo"
|
: qsTr("Now playing: No track info")
|
||||||
color: textMuted
|
color: textMuted
|
||||||
font.pixelSize: 12
|
font.pixelSize: 12
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
@@ -652,7 +652,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: "Lautstärke"
|
text: qsTr("Volume")
|
||||||
color: textMuted
|
color: textMuted
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,7 +699,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: "Lade Sender..."
|
text: qsTr("Loading stations...")
|
||||||
color: textMain
|
color: textMain
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
@@ -715,7 +715,7 @@ ApplicationWindow {
|
|||||||
|
|
||||||
Dialog {
|
Dialog {
|
||||||
id: addDialog
|
id: addDialog
|
||||||
title: "Sender manuell hinzufügen"
|
title: qsTr("Add station manually")
|
||||||
modal: true
|
modal: true
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: compactMode ? 320 : 420
|
width: compactMode ? 320 : 420
|
||||||
@@ -723,15 +723,15 @@ ApplicationWindow {
|
|||||||
|
|
||||||
contentItem: ColumnLayout {
|
contentItem: ColumnLayout {
|
||||||
spacing: 8
|
spacing: 8
|
||||||
TextField { id: manualName; Layout.fillWidth: true; placeholderText: "Name" }
|
TextField { id: manualName; Layout.fillWidth: true; placeholderText: qsTr("Name") }
|
||||||
TextField { id: manualUrl; Layout.fillWidth: true; placeholderText: "Stream URL (http/https)" }
|
TextField { id: manualUrl; Layout.fillWidth: true; placeholderText: qsTr("Stream URL (http/https)") }
|
||||||
TextField { id: manualCountry; Layout.fillWidth: true; placeholderText: "Land (optional)" }
|
TextField { id: manualCountry; Layout.fillWidth: true; placeholderText: qsTr("Country (optional)") }
|
||||||
}
|
}
|
||||||
|
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
if (backend) {
|
if (backend) {
|
||||||
backend.addManualStation(manualName.text, manualUrl.text, manualCountry.text)
|
backend.addManualStation(manualName.text, manualUrl.text, manualCountry.text)
|
||||||
toast("Sender hinzugefügt")
|
toast(qsTr("Station added"))
|
||||||
}
|
}
|
||||||
manualName.text = ""
|
manualName.text = ""
|
||||||
manualUrl.text = ""
|
manualUrl.text = ""
|
||||||
@@ -768,7 +768,7 @@ ApplicationWindow {
|
|||||||
|
|
||||||
Label {
|
Label {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
text: "BearWave"
|
text: qsTr("BearWave")
|
||||||
color: textMain
|
color: textMain
|
||||||
font.bold: true
|
font.bold: true
|
||||||
font.pixelSize: 26
|
font.pixelSize: 26
|
||||||
@@ -776,7 +776,7 @@ ApplicationWindow {
|
|||||||
|
|
||||||
Label {
|
Label {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
text: "Internet Radio Player for KDE"
|
text: qsTr("Internet Radio Player for KDE")
|
||||||
color: textMuted
|
color: textMuted
|
||||||
font.pixelSize: 14
|
font.pixelSize: 14
|
||||||
}
|
}
|
||||||
@@ -791,7 +791,7 @@ ApplicationWindow {
|
|||||||
|
|
||||||
Label {
|
Label {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
text: "Autor: Sebastian Palencsár"
|
text: qsTr("Author: Sebastian Palencsár")
|
||||||
color: textMain
|
color: textMain
|
||||||
font.bold: true
|
font.bold: true
|
||||||
font.pixelSize: 14
|
font.pixelSize: 14
|
||||||
@@ -809,7 +809,7 @@ ApplicationWindow {
|
|||||||
icon.height: 19
|
icon.height: 19
|
||||||
onClicked: Qt.openUrlExternally("https://palencsar.pro")
|
onClicked: Qt.openUrlExternally("https://palencsar.pro")
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
ToolTip.text: "Website öffnen"
|
ToolTip.text: qsTr("Open website")
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
radius: 20
|
radius: 20
|
||||||
color: parent.hovered ? "#274261" : "#1f3147"
|
color: parent.hovered ? "#274261" : "#1f3147"
|
||||||
@@ -826,7 +826,7 @@ ApplicationWindow {
|
|||||||
icon.height: 19
|
icon.height: 19
|
||||||
onClicked: Qt.openUrlExternally("https://github.com/spalencsar")
|
onClicked: Qt.openUrlExternally("https://github.com/spalencsar")
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
ToolTip.text: "GitHub öffnen"
|
ToolTip.text: qsTr("Open GitHub")
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
radius: 20
|
radius: 20
|
||||||
color: parent.hovered ? "#274261" : "#1f3147"
|
color: parent.hovered ? "#274261" : "#1f3147"
|
||||||
@@ -843,7 +843,7 @@ ApplicationWindow {
|
|||||||
icon.height: 19
|
icon.height: 19
|
||||||
onClicked: Qt.openUrlExternally("https://www.linkedin.com/in/spalencsar/")
|
onClicked: Qt.openUrlExternally("https://www.linkedin.com/in/spalencsar/")
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
ToolTip.text: "LinkedIn öffnen"
|
ToolTip.text: qsTr("Open LinkedIn")
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
radius: 20
|
radius: 20
|
||||||
color: parent.hovered ? "#274261" : "#1f3147"
|
color: parent.hovered ? "#274261" : "#1f3147"
|
||||||
@@ -864,12 +864,12 @@ ApplicationWindow {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Label {
|
Label {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: "MIT License"
|
text: qsTr("MIT License")
|
||||||
color: textMain
|
color: textMain
|
||||||
font.bold: true
|
font.bold: true
|
||||||
}
|
}
|
||||||
Label {
|
Label {
|
||||||
text: "Copyright (c) 2026"
|
text: qsTr("Copyright (c) 2026")
|
||||||
color: textMuted
|
color: textMuted
|
||||||
font.pixelSize: 11
|
font.pixelSize: 11
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ void RadioBackend::addManualStation(const QString &name, const QString &url, con
|
|||||||
station->setName(name.trimmed());
|
station->setName(name.trimmed());
|
||||||
station->setUrl(url.trimmed());
|
station->setUrl(url.trimmed());
|
||||||
station->setUrlResolved(url.trimmed());
|
station->setUrlResolved(url.trimmed());
|
||||||
station->setCountry(country.trimmed().isEmpty() ? QStringLiteral("Manual") : country.trimmed());
|
station->setCountry(country.trimmed().isEmpty() ? tr("Manual") : country.trimmed());
|
||||||
station->setCodec(QStringLiteral("unknown"));
|
station->setCodec(QStringLiteral("unknown"));
|
||||||
station->setBitrate(0);
|
station->setBitrate(0);
|
||||||
station->setVotes(0);
|
station->setVotes(0);
|
||||||
@@ -406,11 +406,11 @@ void RadioBackend::resumeLastStation()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QVariantMap station;
|
QVariantMap station;
|
||||||
station.insert(QStringLiteral("name"), m_lastStationName.isEmpty() ? QStringLiteral("Zuletzt gehoert") : m_lastStationName);
|
station.insert(QStringLiteral("name"), m_lastStationName.isEmpty() ? tr("Last played") : m_lastStationName);
|
||||||
station.insert(QStringLiteral("urlResolved"), m_lastStationUrl);
|
station.insert(QStringLiteral("urlResolved"), m_lastStationUrl);
|
||||||
recordRecentStation(station);
|
recordRecentStation(station);
|
||||||
saveState();
|
saveState();
|
||||||
m_player->playUrl(m_lastStationUrl, m_lastStationName.isEmpty() ? QStringLiteral("Zuletzt gehört") : m_lastStationName);
|
m_player->playUrl(m_lastStationUrl, m_lastStationName.isEmpty() ? tr("Last played") : m_lastStationName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioBackend::loadFavorites()
|
void RadioBackend::loadFavorites()
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ void RadioBrowser::onReplyFinished()
|
|||||||
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
|
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
|
||||||
|
|
||||||
if (!reply) {
|
if (!reply) {
|
||||||
emit error("Network error");
|
emit error(tr("Network error"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
233
translations/bearwave_de.ts
Normal file
233
translations/bearwave_de.ts
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE TS>
|
||||||
|
<TS version="2.1" language="de_DE">
|
||||||
|
<context>
|
||||||
|
<name>Main</name>
|
||||||
|
<message>
|
||||||
|
<source>BearWave</source>
|
||||||
|
<translation>BearWave</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Pause</source>
|
||||||
|
<translation>Pause</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Play</source>
|
||||||
|
<translation>Wiedergabe</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Hide</source>
|
||||||
|
<translation>Verstecken</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show</source>
|
||||||
|
<translation>Zeigen</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Quit</source>
|
||||||
|
<translation>Beenden</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Top</source>
|
||||||
|
<translation>Top</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>DE</source>
|
||||||
|
<translation>DE</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>NL</source>
|
||||||
|
<translation>NL</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Favorites</source>
|
||||||
|
<translation>Favoriten</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Manual +</source>
|
||||||
|
<translation>Manuell +</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>About</source>
|
||||||
|
<translation>About</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Resume</source>
|
||||||
|
<translation>Fortsetzen</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Search stations (name, genre, country)</source>
|
||||||
|
<translation>Sender suchen (Name, Genre, Land)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Search</source>
|
||||||
|
<translation>Suche</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Sort A-Z</source>
|
||||||
|
<translation>Sort A-Z</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Sort Bitrate</source>
|
||||||
|
<translation>Sort Bitrate</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Sort Votes</source>
|
||||||
|
<translation>Sort Votes</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Tip: you are not limited to DE/NL. Search worldwide by country, genre, or station name.</source>
|
||||||
|
<translation>Tipp: Du bist nicht auf DE/NL begrenzt. Suche weltweit nach Ländern, Genres oder Sendernamen.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Genre:</source>
|
||||||
|
<translation>Genre:</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Rock</source>
|
||||||
|
<translation>Rock</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>News</source>
|
||||||
|
<translation>News</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Jazz</source>
|
||||||
|
<translation>Jazz</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Country:</source>
|
||||||
|
<translation>Land:</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>US</source>
|
||||||
|
<translation>US</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>UK</source>
|
||||||
|
<translation>UK</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>FR</source>
|
||||||
|
<translation>FR</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>WORLD</source>
|
||||||
|
<translation>WELT</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Error: </source>
|
||||||
|
<translation>Fehler: </translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>FM</source>
|
||||||
|
<translation>FM</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Stream</source>
|
||||||
|
<translation>Stream</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Removed from favorites</source>
|
||||||
|
<translation>Aus Favoriten entfernt</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Added to favorites</source>
|
||||||
|
<translation>Zu Favoriten hinzugefügt</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>No stations loaded yet</source>
|
||||||
|
<translation>Noch keine Sender geladen</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Load DE/NL stations or use search</source>
|
||||||
|
<translation>Lade DE/NL oder nutze die Suche</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>No station selected</source>
|
||||||
|
<translation>Kein Sender ausgewählt</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Now playing: </source>
|
||||||
|
<translation>Jetzt läuft: </translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Now playing: No track info</source>
|
||||||
|
<translation>Jetzt läuft: Keine Titelinfo</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Volume</source>
|
||||||
|
<translation>Lautstärke</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Loading stations...</source>
|
||||||
|
<translation>Lade Sender...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Add station manually</source>
|
||||||
|
<translation>Sender manuell hinzufügen</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Name</source>
|
||||||
|
<translation>Name</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Stream URL (http/https)</source>
|
||||||
|
<translation>Stream URL (http/https)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Country (optional)</source>
|
||||||
|
<translation>Land (optional)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Station added</source>
|
||||||
|
<translation>Sender hinzugefügt</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Internet Radio Player for KDE</source>
|
||||||
|
<translation>Internet Radio Player für KDE</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Author: Sebastian Palencsár</source>
|
||||||
|
<translation>Autor: Sebastian Palencsár</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Open website</source>
|
||||||
|
<translation>Website öffnen</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Open GitHub</source>
|
||||||
|
<translation>GitHub öffnen</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Open LinkedIn</source>
|
||||||
|
<translation>LinkedIn öffnen</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>MIT License</source>
|
||||||
|
<translation>MIT License</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Copyright (c) 2026</source>
|
||||||
|
<translation>Copyright (c) 2026</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>RadioBackend</name>
|
||||||
|
<message>
|
||||||
|
<source>Manual</source>
|
||||||
|
<translation>Manuell</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Last played</source>
|
||||||
|
<translation>Zuletzt gehört</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>RadioBrowser</name>
|
||||||
|
<message>
|
||||||
|
<source>Network error</source>
|
||||||
|
<translation>Netzwerkfehler</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
</TS>
|
||||||
Reference in New Issue
Block a user