diff --git a/app/NativeMacReceiverSelector/ViewController.swift b/app/NativeMacReceiverSelector/ViewController.swift index 2fb3a5f..4fc8057 100644 --- a/app/NativeMacReceiverSelector/ViewController.swift +++ b/app/NativeMacReceiverSelector/ViewController.swift @@ -91,11 +91,19 @@ class ViewController : NSViewController { withTag: initData.defaultMediaType.rawValue) - let mediaTypeStackView = NSStackView(views: [ - makeLabel(initData.i18n_mediaSelectCastLabel), - self.mediaTypePopUpButton, - makeLabel(initData.i18n_mediaSelectToLabel) - ]) + let mediaTypeStackView = NSStackView() + + if initData.i18n_mediaSelectCastLabel != "" { + mediaTypeStackView.addView( + makeLabel(initData.i18n_mediaSelectCastLabel), in: .leading) + } + + mediaTypeStackView.addView(self.mediaTypePopUpButton, in: .leading) + + if initData.i18n_mediaSelectToLabel != "" { + mediaTypeStackView.addView( + makeLabel(initData.i18n_mediaSelectToLabel), in: .leading) + } stackView.addArrangedSubview(mediaTypeStackView) diff --git a/ext/src/_locales/de/messages.json b/ext/src/_locales/de/messages.json new file mode 100644 index 0000000..7ae96d7 --- /dev/null +++ b/ext/src/_locales/de/messages.json @@ -0,0 +1,339 @@ +{ + "extensionName": { + "message": "EXTENSION_NAME" + , "description": "Name of the extension and the native receiver selector window title." + } + , "extensionDescription": { + "message": "Aktiviert Chromecast-Support zum Streamen von Web-Apps (wie Netflix oder BBC iPlayer), HTML5-Video und Bildschirm-/Tabfreigaben." + , "description": "Description of the extension shown in the add-ons manager." + } + + + , "popupMediaTypeApp": { + "message": "Die App dieser Seite" + , "description": "Receiver selector media type text for current site's sender application." + } + , "popupMediaTypeTab": { + "message": "Diesen Tab" + , "description": "Receiver selector media type text for current tab." + } + , "popupMediaTypeScreen": { + "message": "Bildschirm" + , "description": "Receiver selector media type text for screen." + } + , "popupMediaTypeFile": { + "message": "Durchsuchen..." + , "description": "Receiver selector media type text for opening a file selector dialog." + } + + , "popupMediaSelectCastLabel": { + "message": "" + , "description": "(Cast) to:" + } + , "popupMediaSelectToLabel": { + "message": "streamen an:" + , "description": "Cast (to:)" + } + , "popupCastButtonTitle": { + "message": "Streamen" + , "description": "Button text for each receiver entry in the receiver selector." + } + , "popupCastingButtonTitle": { + "message": "Streame$ellipsis$" + , "description": "Button text while establishing a session in the receiver selector. Ellipsis cycles (. → .. → ...) as loading indicator." + , "placeholders": { + "ellipsis": { + "content": "$1" + , "example": "..." + } + } + } + + + , "contextCast": { + "message": "Streamen..." + , "description": "Main context menu item title. Ellipsis indicates additional information required as it triggers opening of receiver selector." + } + + , "contextAddToWhitelist": { + "message": "Zur Whitelist hinzufügen" + , "description": "Top-level whitelist context menu item title." + } + , "contextAddToWhitelistRecommended": { + "message": "$matchPattern$ hinzufügen (empfohlen)" + , "description": "Context menu item title for recomended match pattern." + , "placeholders": { + "matchPattern": { + "content": "$1" + , "example": "https://example.com/*" + } + } + } + , "contextAddToWhitelistAdvancedAdd": { + "message": "$matchPattern$ hinzufügen" + , "description": "Context menu item title for all other match patterns." + , "placeholders": { + "matchPattern": { + "content": "$1" + , "example": "*://*.example.com/*" + } + } + } + + + , "optionsBridgeLoading": { + "message": "Lade Bridge-Informationen..." + , "description": "Loading placeholder text for bridge section on options page." + } + , "optionsBridgeFoundStatusTitle": { + "message": "Bridge gefunden" + , "description": "Bridge OK status title text." + } + , "optionsBridgeIssueStatusTitle": { + "message": "Bridge-Fehler" + , "description": "Bridge error status title text." + } + , "optionsBridgeNotFoundStatusTitle": { + "message": "Bridge nicht gefunden" + , "description": "Bridge missing status title text." + } + , "optionsBridgeNotFoundStatusText": { + "message": "Versuchen Sie die neuste Version herunterzuladen und zu installieren." + , "description": "Bridge not found additional description text" + } + + , "optionsBridgeStatsName": { + "message": "Name:" + , "description": "Bridge stats name row title." + } + , "optionsBridgeStatsVersion": { + "message": "Version:" + , "description": "Bridge stats version row title." + } + , "optionsBridgeStatsExpectedVersion": { + "message": "Erwartete Version:" + , "description": "Bridge stats expected version row title." + } + , "optionsBridgeStatsCompatibility": { + "message": "Kompatibilität:" + , "description": "Bridge stats compatibility row title." + } + , "optionsBridgeStatsRecommendedAction": { + "message": "Handlungsempfehlung:" + , "description": "Bridge stats recommended action row title." + } + , "optionsBridgeCompatible": { + "message": "KOMPATIBEL" + , "description": "Compatibility status is definitely compatible." + } + , "optionsBridgeLikelyCompatible": { + "message": "WAHRSCHEINLICH KOMPATIBEL" + , "description": "Compatibility status is probably compatible." + } + , "optionsBridgeIncompatible": { + "message": "NICHT KOMPATIBEL" + , "description": "Compatibility status is definitely incompatible." + } + , "optionsBridgeOlderAction": { + "message": "Bridge-Version älter als erwartet, versuchen Sie auf die neuste Version zu aktualisieren." + , "description": "Recommended action for when the installed bridge version is older than the installed extension version." + } + , "optionsBridgeNewerAction": { + "message": "Bridge-Version neuer als erwartet, versuchen Sie die Erweiterung auf die neuste Version zu aktualisieren." + , "description": "Recommended action for when the installed bridge version is newer than the installed extension version." + } + , "optionsBridgeNoAction": { + "message": "Kein Handlungsbedarf." + , "description": "Recommended action for when both bridge and extension versions are compatible or likely compatible." + } + , "optionsBridgeUpdateCheck": { + "message": "Nach Aktualisierungen suchen" + , "description": "Update check button title." + } + , "optionsBridgeUpdateChecking": { + "message": "Suche nach Aktualisierungen$ellipsis$" + , "description": "Update check button title while in progress. Ellipsis cycles (. → .. → ...) as loading indicator." + , "placeholders": { + "ellipsis": { + "content": "$1" + , "example": ".." + } + } + } + , "optionsBridgeUpdateStatusNoUpdates": { + "message": "Keine Aktualisierungen verfügbar" + , "description": "Update status if no updates are found." + } + , "optionsBridgeUpdateStatusError": { + "message": "Fehler beim Suchen nach Aktualisierungen" + , "description": "Update status if an error was encountered checking for updates." + } + , "optionsBridgeUpdateAvailable": { + "message": "Eine Aktualisierung ist verfügbar:" + , "description": "Update status if an update was found." + } + , "optionsBridgeUpdate": { + "message": "Jetzt aktualisieren..." + , "description": "Update now button title. Ellipsis indicates additional information as it triggers an update window popup." + } + + , "optionsMediaCategoryName": { + "message": "Medien streamen" + , "description": "Options page media casting category title." + } + , "optionsMediaCategoryDescription": { + "message": "HTML5-Video/-Audio Medien streamen." + , "description": "Options page media casting category description." + } + , "optionsMediaEnabled": { + "message": "Streamen von Medien aktivieren" + , "description": "Media casting enabled checkbox label." + } + , "optionsMediaSyncElement": { + "message": "Empfängerstatus mit Media-Element synchronisieren" + , "description": "Media casting sync checkbox label." + } + , "optionsMediaSyncElementDescription": { + "message": "Status (Wiedergabe, Lautstärke, Untertitel, etc...) zwischen dem Media-Element und dem Empfängergerät synchronisieren." + , "description": "Media casting sync option description." + } + , "optionsMediaStopOnUnload": { + "message": "Wiedergabe auf dem Empfänger beim verlassen der Seite beenden" + , "description": "Media stop on unload checkbox label." + } + + , "optionsLocalMediaCategoryName": { + "message": "Streamen lokaler Medien" + , "description": "Options page local media category title." + } + , "optionsLocalMediaCategoryDescription": { + "message": "HTTP-Server, der von der Bridge zum Streamen lokaler Mediendateien an den Empfänger gestartet wird." + , "description": "Options page local media category description." + } + , "optionsLocalMediaEnabled": { + "message": "Streamen lokaler Medien aktivieren" + , "description": "Local media enabled checkbox label." + } + , "optionsLocalMediaServerPort": { + "message": "HTTP-Serverport:" + , "description": "HTTP server port input label." + } + + , "optionsReceiverSelectorCategoryName": { + "message": "Empfängerauswahl" + , "description": "Options page receiver selector category title." + } + , "optionsReceiverSelectorCategoryDescription": { + "message": "Auswahloberfläche für Empfängergeräte." + , "description": "Options page receiver selector category description." + } + , "optionsReceiverSelectorType": { + "message": "Art:" + , "description": "Receiver selector type option label." + } + , "optionsReceiverSelectorTypeBrowser": { + "message": "Browser" + , "description": "Receiver selector type browser radio option label." + } + , "optionsReceiverSelectorTypeNative": { + "message": "Nativ" + , "description": "Receiver selector type native radio option label." + } + , "optionsReceiverSelectorWaitForConnection": { + "message": "Auf Verbindung warten" + , "description": "Receiver selector wait for connection option checkbox label." + } + , "optionsReceiverSelectorWaitForConnectionDescription": { + "message": "Empfängerauswahl bleibt geöffnet bis die Verbindung aufgebaut ist oder die Verbindung fehlschlägt." + , "description": "Receiver selector wait for connection option description." + } + , "optionsReceiverSelectorCloseIfFocusLost": { + "message": "Nach Fokusverlust schließen" + , "description": "Receiver selector close if focus lost option checkbox label." + } + + , "optionsUserAgentWhitelistCategoryName": { + "message": "Useragent-Whitelist" + , "description": "Options page whitelist category title." + } + , "optionsUserAgentWhitelistCategoryDescription": { + "message": "Seiten auf denen der Useragent aus kompatibilitätsgründen mit einer Chrome-Version ersetzt wird. Suchmuster müssen gültig sein." + , "description": "Options page whitelist category description." + } + , "optionsUserAgentWhitelistEnabled": { + "message": "Webseiten-Whitelist aktivieren" + , "description": "Whitelist enabled checkbox label." + } + , "optionsUserAgentWhitelistContent": { + "message": "Suchmuster (Eins pro Zeile):" + , "description": "Match patterns editor widget label." + } + , "optionsUserAgentWhitelistBasicView": { + "message": "Einfache Ansicht" + , "description": "Switch to basic view button title." + } + , "optionsUserAgentWhitelistRawView": { + "message": "Rohdatenansicht" + , "description": "Switch to raw view button title." + } + , "optionsUserAgentWhitelistSaveRaw": { + "message": "Rohdaten speichern" + , "description": "Save raw view edits button title." + } + , "optionsUserAgentWhitelistAddItem": { + "message": "Eintrag hinzufügen" + , "description": "Add new whitelist item button title." + } + , "optionsUserAgentWhitelistEditItem": { + "message": "Bearbeiten" + , "description": "Edit whitelist item button title. Displayed on each item." + } + , "optionsUserAgentWhitelistRemoveItem": { + "message": "Entfernen" + , "description": "Remove whitelist item button title. Displayed on each item." + } + , "optionsUserAgentWhitelistInvalidMatchPattern": { + "message": "Ungültiges Suchmuster $matchPattern$" + , "description": "Error displayed by input indicating an invalid match pattern." + , "placeholders": { + "matchPattern": { + "content": "$1" + , "example": "http://example" + } + } + } + + , "optionsMirroringCategoryName": { + "message": "Bildschirm duplizieren" + , "description": "Options page mirroring category name." + } + , "optionsMirroringCategoryDescription": { + "message": "Bildschirm/Tab an eine Chromecast-Empfänger-App duplizieren." + , "description": "Options page mirroring category description." + } + , "optionsMirroringEnabled": { + "message": "Bildschirm duplizieren aktivieren" + , "description": "Mirroring enabled checkbox label." + } + , "optionsMirroringAppId": { + "message": "Empfänger-App-ID:" + , "description": "Mirroring app ID input label." + } + , "optionsMirroringAppIdDescription": { + "message": "App-ID einer registrierten Chromecast-Empfängeranwendung. Nur für fortgeschrittene Anwender. Muss mit der Standard-App kompatibel sein (siehe GitHub-Repository)." + , "description": "Mirroring app ID option description." + } + + , "optionsReset": { + "message": "Standardwerte wiederherstellen" + , "description": "Restore default options button label." + } + , "optionsSave": { + "message": "Speichern" + , "description": "Save options button label." + } + , "optionsSaved": { + "message": "Gespeichert!" + , "description": "Status text displayed by save button once options have been successfully saved." + } +} diff --git a/ext/src/ui/popup/index.tsx b/ext/src/ui/popup/index.tsx index 212a9a6..a7976b2 100755 --- a/ext/src/ui/popup/index.tsx +++ b/ext/src/ui/popup/index.tsx @@ -115,10 +115,12 @@ class PopupApp extends Component<{}, PopupAppState> { return ( - { _("popupMediaSelectCastLabel") } + + { _("popupMediaSelectCastLabel") } + + className="media-select__dropdown"> @@ -145,7 +147,9 @@ class PopupApp extends Component<{}, PopupAppState> { : _("popupMediaTypeFile") } - { _("popupMediaSelectToLabel") } + + { _("popupMediaSelectToLabel") } + { this.state.receivers && this.state.receivers.map( @@ -238,16 +242,16 @@ class ReceiverEntry extends Component { return ( - + { this.props.receiver.friendlyName } - { application.isIdleScreen ? `${this.props.receiver.host}:${this.props.receiver.port}` : application.statusText } - { this.state.isLoading diff --git a/ext/src/ui/popup/styles/index.css b/ext/src/ui/popup/styles/index.css index 68af036..789a8ad 100755 --- a/ext/src/ui/popup/styles/index.css +++ b/ext/src/ui/popup/styles/index.css @@ -11,16 +11,28 @@ body { padding: 0.75em 0; } -.media-select-dropdown { +.media-select__label-cast, +.media-select__label-to { display: inline-block; - margin: 0 0.5em; } +.media-select__label-cast:not(:empty) { + margin-inline-end: 0.5em; +} +.media-select__label-to:not(:empty) { + margin-inline-start: 0.5em; +} + +.media-select__dropdown { + display: inline-block; +} + .receivers { list-style: none; margin: initial; padding: initial; } + .receiver { column-gap: 0.75em; display: grid; @@ -35,30 +47,29 @@ body { position: relative; } - .receiver:not(:last-child) { border-bottom: 1px solid rgba(0, 0, 0, 0.25); } -.receiver-name, -.receiver-address { +.receiver__name, +.receiver__address { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.receiver-name { +.receiver__name { font-size: 1.1em; grid-area: name; } -.receiver-address { +.receiver__address { color: GrayText; grid-area: address; } -.receiver-status { +.receiver__status { grid-area: status; } -.receiver-connect { +.receiver__connect { align-self: center; grid-area: connect; justify-self: end; diff --git a/ext/src/ui/popup/styles/mac.css b/ext/src/ui/popup/styles/mac.css index 1616f28..a8f7da6 100755 --- a/ext/src/ui/popup/styles/mac.css +++ b/ext/src/ui/popup/styles/mac.css @@ -12,11 +12,11 @@ button:not([disabled]):hover:active { color: -moz-mac-buttonactivetext; } -.receiver-address, -.receiver-status { +.receiver__address, +.receiver__status { font: message-box; } -.receiver-connect { +.receiver__connect { height: 22px; }