Add German translation (#77)

* Add German translation

popupMediaSelectCastLabel is intentionally left blank due to German grammar.

* Fix receiver selector spacing for blank labels
This commit is contained in:
Matthias Aßhauer
2019-08-26 01:18:01 +02:00
committed by Matt Hensman
parent 347ed58a85
commit d96b45cca8
5 changed files with 385 additions and 23 deletions

View File

@@ -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)

View File

@@ -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 <option> text for current site's sender application."
}
, "popupMediaTypeTab": {
"message": "Diesen Tab"
, "description": "Receiver selector media type <option> text for current tab."
}
, "popupMediaTypeScreen": {
"message": "Bildschirm"
, "description": "Receiver selector media type <option> text for screen."
}
, "popupMediaTypeFile": {
"message": "Durchsuchen..."
, "description": "Receiver selector media type <option> text for opening a file selector dialog."
}
, "popupMediaSelectCastLabel": {
"message": ""
, "description": "(Cast) <select> to:"
}
, "popupMediaSelectToLabel": {
"message": "streamen an:"
, "description": "Cast <select> (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."
}
}

View File

@@ -115,10 +115,12 @@ class PopupApp extends Component<{}, PopupAppState> {
return (
<div>
<div className="media-select">
{ _("popupMediaSelectCastLabel") }
<div className="media-select__label-cast">
{ _("popupMediaSelectCastLabel") }
</div>
<select value={ this.state.mediaType }
onChange={ this.onSelectChange }
className="media-select-dropdown">
className="media-select__dropdown">
<option value={ ReceiverSelectorMediaType.App }
disabled={ !(this.state.availableMediaTypes
& ReceiverSelectorMediaType.App) }>
@@ -145,7 +147,9 @@ class PopupApp extends Component<{}, PopupAppState> {
: _("popupMediaTypeFile") }
</option>
</select>
{ _("popupMediaSelectToLabel") }
<div className="media-select__label-to">
{ _("popupMediaSelectToLabel") }
</div>
</div>
<ul className="receivers">
{ this.state.receivers && this.state.receivers.map(
@@ -238,16 +242,16 @@ class ReceiverEntry extends Component<ReceiverEntryProps, ReceiverEntryState> {
return (
<li className="receiver">
<div className="receiver-name">
<div className="receiver__name">
{ this.props.receiver.friendlyName }
</div>
<div className="receiver-address"
<div className="receiver__address"
title={ !application.isIdleScreen && application.statusText }>
{ application.isIdleScreen
? `${this.props.receiver.host}:${this.props.receiver.port}`
: application.statusText }
</div>
<button className="receiver-connect"
<button className="receiver__connect"
onClick={ this.handleCast }
disabled={this.props.isLoading || !this.props.canCast}>
{ this.state.isLoading

View File

@@ -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;

View File

@@ -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;
}