From f3cd19efe025bf3d6846d1d4b8108cb3be1dde73 Mon Sep 17 00:00:00 2001 From: magdev Date: Thu, 29 Jan 2026 12:03:05 +0100 Subject: [PATCH] feat: Add license management and tabbed settings (v0.3.0) - Implement license management using magdev/wc-licensed-product-client - Reorganize settings page into License, Default Settings, Integrations tabs - Add license validation and activation via AJAX - Frontend features require valid license (admin works always) - Update translations with German (de_CH) for license strings Co-Authored-By: Claude Opus 4.5 --- CHANGELOG.md | 22 + CLAUDE.md | 44 +- assets/css/admin.css | 120 +- assets/js/admin.js | 110 +- composer.json | 7 + composer.lock | 652 ++++++++- includes/Frontend/Ajax.php | 12 + includes/Frontend/Shortcodes.php | 33 +- includes/Installer.php | 17 +- includes/License/Manager.php | 653 +++++++++ includes/Plugin.php | 391 ++++- languages/wp-fedistream-de_CH.mo | Bin 0 -> 9096 bytes languages/wp-fedistream-de_CH.po | 2287 ++++++++++++++++++++++++++++++ languages/wp-fedistream.pot | 2286 ++++++++++++++++++++++++++++- wp-fedistream.php | 4 +- 15 files changed, 6539 insertions(+), 99 deletions(-) create mode 100644 includes/License/Manager.php create mode 100644 languages/wp-fedistream-de_CH.mo create mode 100644 languages/wp-fedistream-de_CH.po diff --git a/CHANGELOG.md b/CHANGELOG.md index be25231..63dacc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.3.0] - 2026-01-29 + +### Added + +- License management integration using `magdev/wc-licensed-product-client` package +- Tabbed settings page with License, Default Settings, and Integrations tabs +- License validation and activation via AJAX with real-time status updates +- License status banner showing current license state and expiration +- License checks for frontend components (unlicensed sites show message instead of content) + +### Changed + +- Reorganized settings page into three tabs for better organization +- Frontend features (player, shortcodes, ActivityPub) now require valid license +- Admin/backend functionality works regardless of license status + +### Security + +- Server secret stored securely in WordPress options +- HMAC signature verification for license server responses +- Nonce verification for all license AJAX operations + ## [0.2.0] - 2026-01-28 ### Added diff --git a/CLAUDE.md b/CLAUDE.md index d443e4e..b0f3c4e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -24,9 +24,7 @@ This project is proudly **"vibe-coded"** using Claude.AI - the entire codebase w **Note for AI Assistants:** Clean this section after the specific features are done or new releases are made. Effective changes are tracked in `CHANGELOG.md`. Do not add completed versions here - document them in the Session History section at the end of this file. -### Version 0.2.1 (Bugfix) - -### Version 0.3.0 (Minor) +(No pending features - all roadmap items completed) ## Technical Stack @@ -426,3 +424,43 @@ wp-fedistream/ - All releases pushed to origin (v0.1.1 and v0.2.0 tags) - Markdown linting fixes applied to USERGUIDE.md + +### 2026-01-29 - License Management v0.3.0 + +**Summary:** Implemented license management integration and reorganized settings page into tabs. + +**Features:** + +- License management using `magdev/wc-licensed-product-client` package +- Tabbed settings page: License, Default Settings, Integrations +- License validation and activation via AJAX +- License status banner with expiration display +- Frontend license checks (unlicensed sites show message instead of content) +- Admin/backend works regardless of license status + +**License Behavior:** + +- Backend (admin): Full access always +- Frontend (player, shortcodes, ActivityPub): Requires valid license + +**Files Created:** + +- `includes/License/Manager.php` - License management wrapper class + +**Files Modified:** + +- `composer.json` - Added VCS repository and `magdev/wc-licensed-product-client` dependency +- `includes/Plugin.php` - Tabbed settings page, license manager initialization, conditional frontend loading +- `includes/Installer.php` - Added default license options +- `includes/Frontend/Shortcodes.php` - Added unlicensed mode support +- `includes/Frontend/Ajax.php` - Added license checks to public AJAX endpoints +- `assets/js/admin.js` - License validation AJAX handlers +- `assets/css/admin.css` - Tab and license status styling +- `wp-fedistream.php` - Version bump to 0.3.0 +- `CHANGELOG.md` - Added v0.3.0 entry + +**Notes:** + +- Package name is `magdev/wc-licensed-product-client` (not `wc-license-product-client`) +- Uses Symfony HTTP Client via the license client package +- License validation cached for 24 hours using WordPress transients diff --git a/assets/css/admin.css b/assets/css/admin.css index b0413b9..f317e93 100644 --- a/assets/css/admin.css +++ b/assets/css/admin.css @@ -4,4 +4,122 @@ * @package WP_FediStream */ -/* Admin styles will be added here */ +/* Settings page tabs */ +.nav-tab-wrapper + .fedistream-settings-content { + margin-top: -1px; +} + +.fedistream-settings-content { + background: #fff; + border: 1px solid #c3c4c7; + border-top: none; + padding: 20px; +} + +/* Active tab styling */ +.wrap .nav-tab-wrapper .nav-tab-active { + background: #fff; + border-bottom-color: #fff; +} + +/* License status banner */ +.fedistream-license-status { + margin-bottom: 20px; +} + +.fedistream-license-status .dashicons { + color: inherit; +} + +.fedistream-license-status.notice-success .dashicons { + color: #00a32a; +} + +.fedistream-license-status.notice-error .dashicons { + color: #d63638; +} + +.fedistream-license-status.notice-warning .dashicons { + color: #dba617; +} + +.fedistream-license-status.notice-info .dashicons { + color: #72aee6; +} + +/* License form buttons */ +#fedistream-license-form .button .dashicons { + font-size: 16px; + width: 16px; + height: 16px; + line-height: 1.3; +} + +/* License message display */ +#fedistream-license-message { + padding: 10px 15px; +} + +#fedistream-license-message p { + margin: 0; +} + +/* Dashboard stats grid */ +.fedistream-stats { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 20px; + margin: 20px 0; +} + +.fedistream-stat-box { + background: #fff; + padding: 20px; + border: 1px solid #ccd0d4; + border-radius: 4px; +} + +.fedistream-stat-box h3 { + margin: 0 0 10px; +} + +.fedistream-stat-box p { + font-size: 2em; + margin: 0; + color: #2271b1; +} + +/* Quick actions */ +.fedistream-quick-actions { + background: #fff; + padding: 20px; + border: 1px solid #ccd0d4; + border-radius: 4px; + margin: 20px 0; +} + +/* Info box */ +.fedistream-info { + background: #fff; + padding: 20px; + border: 1px solid #ccd0d4; + border-radius: 4px; +} + +/* Responsive adjustments */ +@media screen and (max-width: 782px) { + .fedistream-stats { + grid-template-columns: repeat(2, 1fr); + } + + #fedistream-license-form .button { + display: block; + margin: 10px 0 0 0 !important; + } +} + +@media screen and (max-width: 480px) { + .fedistream-stats { + grid-template-columns: 1fr; + } +} diff --git a/assets/js/admin.js b/assets/js/admin.js index c79908e..fb6aa33 100644 --- a/assets/js/admin.js +++ b/assets/js/admin.js @@ -8,7 +8,115 @@ 'use strict'; $(document).ready(function() { - // Admin scripts will be added here + // License validation functionality + initLicenseValidation(); }); + /** + * Initialize license validation AJAX handlers. + */ + function initLicenseValidation() { + var $validateBtn = $('#fedistream-validate-license'); + var $activateBtn = $('#fedistream-activate-license'); + var $spinner = $('#fedistream-license-spinner'); + var $message = $('#fedistream-license-message'); + + if (!$validateBtn.length) { + return; + } + + // Validate license button + $validateBtn.on('click', function(e) { + e.preventDefault(); + performLicenseAction('fedistream_validate_license', 'Validating...'); + }); + + // Activate license button + $activateBtn.on('click', function(e) { + e.preventDefault(); + performLicenseAction('fedistream_activate_license', 'Activating...'); + }); + + /** + * Perform license AJAX action. + * + * @param {string} action AJAX action name. + * @param {string} loadingText Loading button text. + */ + function performLicenseAction(action, loadingText) { + var originalText = $validateBtn.text(); + + // Show loading state + $spinner.addClass('is-active'); + $validateBtn.prop('disabled', true); + $activateBtn.prop('disabled', true); + $message.hide(); + + $.ajax({ + url: ajaxurl, + type: 'POST', + data: { + action: action, + nonce: fedistreamLicenseNonce + }, + success: function(response) { + $spinner.removeClass('is-active'); + $validateBtn.prop('disabled', false); + $activateBtn.prop('disabled', false); + + if (response.success) { + showMessage('success', response.data.message); + // Reload page to show updated status + setTimeout(function() { + window.location.reload(); + }, 1500); + } else { + showMessage('error', response.data.message || 'An error occurred.'); + } + }, + error: function(xhr, status, error) { + $spinner.removeClass('is-active'); + $validateBtn.prop('disabled', false); + $activateBtn.prop('disabled', false); + showMessage('error', 'Request failed. Please try again.'); + } + }); + } + + /** + * Show a message to the user. + * + * @param {string} type Message type: 'success', 'error', 'warning', 'info'. + * @param {string} text Message text. + */ + function showMessage(type, text) { + var classMap = { + 'success': 'notice-success', + 'error': 'notice-error', + 'warning': 'notice-warning', + 'info': 'notice-info' + }; + + var noticeClass = classMap[type] || 'notice-info'; + + $message + .removeClass('notice-success notice-error notice-warning notice-info') + .addClass('notice ' + noticeClass) + .html('

' + escapeHtml(text) + '

') + .show(); + } + + /** + * Escape HTML entities. + * + * @param {string} text Text to escape. + * @return {string} Escaped text. + */ + function escapeHtml(text) { + var div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + } + } + })(jQuery); diff --git a/composer.json b/composer.json index bc80e1a..3640392 100644 --- a/composer.json +++ b/composer.json @@ -14,8 +14,15 @@ "support": { "issues": "https://src.bundespruefstelle.ch/magdev/wp-fedistream/issues" }, + "repositories": [ + { + "type": "vcs", + "url": "https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client.git" + } + ], "require": { "php": ">=8.3", + "magdev/wc-licensed-product-client": "^0.1", "twig/twig": "^3.0" }, "require-dev": { diff --git a/composer.lock b/composer.lock index d979ca9..5ac7bd5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,312 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c8fb50541e5730c8ad92b76392765aca", + "content-hash": "29e8e4e069b25dee0a610019a77dab50", "packages": [ + { + "name": "magdev/wc-licensed-product-client", + "version": "v0.1.0", + "source": { + "type": "git", + "url": "https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client.git", + "reference": "83037ea0c2d9e365cf9ec0ad50251d3ebc7e4782" + }, + "require": { + "php": "^8.3", + "psr/cache": "^3.0", + "psr/http-client": "^1.0", + "psr/log": "^3.0", + "symfony/http-client": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Magdev\\WcLicensedProductClient\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Magdev\\WcLicensedProductClient\\Tests\\": "tests/" + } + }, + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "Marco Graetsch", + "email": "magdev3.0@gmail.com", + "homepage": "https://src.bundespruefstelle.ch/magdev" + } + ], + "description": "Client library for WooCommerce Licensed Product Plugin - Activate, validate and check the status of licenses via REST API", + "homepage": "https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client", + "support": { + "issues": "https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client/issues", + "source": "https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client" + }, + "time": "2026-01-22T15:24:57+00:00" + }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, { "name": "symfony/deprecation-contracts", "version": "v3.6.0", @@ -73,6 +377,185 @@ ], "time": "2024-09-25T14:21:43+00:00" }, + { + "name": "symfony/http-client", + "version": "v7.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client.git", + "reference": "84bb634857a893cc146cceb467e31b3f02c5fe9f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client/zipball/84bb634857a893cc146cceb467e31b3f02c5fe9f", + "reference": "84bb634857a893cc146cceb467e31b3f02c5fe9f", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-client-contracts": "~3.4.4|^3.5.2", + "symfony/polyfill-php83": "^1.29", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "amphp/amp": "<2.5", + "amphp/socket": "<1.1", + "php-http/discovery": "<1.15", + "symfony/http-foundation": "<6.4" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "3.0" + }, + "require-dev": { + "amphp/http-client": "^4.2.1|^5.0", + "amphp/http-tunnel": "^1.0|^2.0", + "guzzlehttp/promises": "^1.4|^2.0", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/amphp-http-client-meta": "^1.0|^2.0", + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "keywords": [ + "http" + ], + "support": { + "source": "https://github.com/symfony/http-client/tree/v7.4.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-01-27T16:16:02+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "75d7043853a42837e68111812f4d964b01e5101c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c", + "reference": "75d7043853a42837e68111812f4d964b01e5101c", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-29T11:18:49+00:00" + }, { "name": "symfony/polyfill-ctype", "version": "v1.33.0", @@ -241,6 +724,173 @@ ], "time": "2024-12-23T08:48:59+00:00" }, + { + "name": "symfony/polyfill-php83", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php83\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-08T02:45:35+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.6.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-15T11:30:57+00:00" + }, { "name": "twig/twig", "version": "v3.23.0", diff --git a/includes/Frontend/Ajax.php b/includes/Frontend/Ajax.php index 0cd03e3..1f08ec8 100644 --- a/includes/Frontend/Ajax.php +++ b/includes/Frontend/Ajax.php @@ -7,6 +7,8 @@ namespace WP_FediStream\Frontend; +use WP_FediStream\License\Manager as LicenseManager; + // Prevent direct file access. if ( ! defined( 'ABSPATH' ) ) { exit; @@ -36,6 +38,11 @@ class Ajax { * @return void */ public function get_track(): void { + // Check license. + if ( ! LicenseManager::is_license_valid() ) { + wp_send_json_error( array( 'message' => __( 'This feature requires a valid license.', 'wp-fedistream' ) ) ); + } + // Verify nonce. if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'wp-fedistream-nonce' ) ) { wp_send_json_error( array( 'message' => __( 'Invalid nonce.', 'wp-fedistream' ) ) ); @@ -125,6 +132,11 @@ class Ajax { * @return void */ public function record_play(): void { + // Check license. + if ( ! LicenseManager::is_license_valid() ) { + wp_send_json_error( array( 'message' => __( 'This feature requires a valid license.', 'wp-fedistream' ) ) ); + } + // Verify nonce. if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'wp-fedistream-nonce' ) ) { wp_send_json_error( array( 'message' => __( 'Invalid nonce.', 'wp-fedistream' ) ) ); diff --git a/includes/Frontend/Shortcodes.php b/includes/Frontend/Shortcodes.php index 12c0759..411456f 100644 --- a/includes/Frontend/Shortcodes.php +++ b/includes/Frontend/Shortcodes.php @@ -27,13 +27,35 @@ class Shortcodes { private Plugin $plugin; /** - * Constructor. + * Whether running in unlicensed mode. + * + * @var bool */ - public function __construct() { - $this->plugin = Plugin::get_instance(); + private bool $unlicensed_mode = false; + + /** + * Constructor. + * + * @param bool $unlicensed_mode Whether to run in unlicensed mode. + */ + public function __construct( bool $unlicensed_mode = false ) { + $this->plugin = Plugin::get_instance(); + $this->unlicensed_mode = $unlicensed_mode; $this->register_shortcodes(); } + /** + * Get the unlicensed message HTML. + * + * @return string + */ + private function get_unlicensed_message(): string { + return '
' + . '

' + . esc_html__( 'This content requires a valid FediStream license.', 'wp-fedistream' ) + . '

'; + } + /** * Register all shortcodes. * @@ -501,6 +523,11 @@ class Shortcodes { * @return string */ private function render_template( string $template, array $context ): string { + // Check for unlicensed mode. + if ( $this->unlicensed_mode ) { + return $this->get_unlicensed_message(); + } + try { return $this->plugin->render( $template, $context ); } catch ( \Exception $e ) { diff --git a/includes/Installer.php b/includes/Installer.php index 9f9cd29..9be9892 100644 --- a/includes/Installer.php +++ b/includes/Installer.php @@ -345,11 +345,18 @@ class Installer { */ private static function set_default_options(): void { $defaults = array( - 'wp_fedistream_enable_activitypub' => 1, - 'wp_fedistream_enable_woocommerce' => 0, - 'wp_fedistream_audio_formats' => array( 'mp3', 'wav', 'flac', 'ogg' ), - 'wp_fedistream_max_upload_size' => 50, // MB - 'wp_fedistream_default_license' => 'all-rights-reserved', + 'wp_fedistream_enable_activitypub' => 1, + 'wp_fedistream_enable_woocommerce' => 0, + 'wp_fedistream_audio_formats' => array( 'mp3', 'wav', 'flac', 'ogg' ), + 'wp_fedistream_max_upload_size' => 50, // MB + 'wp_fedistream_default_license' => 'all-rights-reserved', + // License management options. + 'wp_fedistream_license_key' => '', + 'wp_fedistream_license_server_url' => '', + 'wp_fedistream_license_server_secret' => '', + 'wp_fedistream_license_status' => 'unchecked', + 'wp_fedistream_license_data' => array(), + 'wp_fedistream_license_last_check' => 0, ); foreach ( $defaults as $option => $value ) { diff --git a/includes/License/Manager.php b/includes/License/Manager.php new file mode 100644 index 0000000..f388480 --- /dev/null +++ b/includes/License/Manager.php @@ -0,0 +1,653 @@ +init_hooks(); + } + + /** + * Initialize WordPress hooks. + * + * @return void + */ + private function init_hooks(): void { + add_action( 'wp_ajax_fedistream_validate_license', array( $this, 'ajax_validate_license' ) ); + add_action( 'wp_ajax_fedistream_activate_license', array( $this, 'ajax_activate_license' ) ); + add_action( 'wp_ajax_fedistream_deactivate_license', array( $this, 'ajax_deactivate_license' ) ); + add_action( 'wp_ajax_fedistream_check_license_status', array( $this, 'ajax_check_status' ) ); + } + + /** + * Initialize the license client. + * + * @return bool True if client was initialized successfully. + */ + private function init_client(): bool { + if ( null !== $this->client ) { + return true; + } + + $server_url = self::get_server_url(); + $server_secret = self::get_server_secret(); + + if ( empty( $server_url ) || empty( $server_secret ) ) { + return false; + } + + try { + $this->client = new SecureLicenseClient( + httpClient: HttpClient::create(), + baseUrl: $server_url, + serverSecret: $server_secret, + ); + return true; + } catch ( \Throwable $e ) { + return false; + } + } + + /** + * Validate the current license. + * + * @return array{success: bool, message: string, data?: array} + */ + public function validate(): array { + if ( ! $this->init_client() ) { + return array( + 'success' => false, + 'message' => __( 'License server configuration is incomplete.', 'wp-fedistream' ), + ); + } + + $license_key = self::get_license_key(); + if ( empty( $license_key ) ) { + return array( + 'success' => false, + 'message' => __( 'No license key provided.', 'wp-fedistream' ), + ); + } + + $domain = wp_parse_url( home_url(), PHP_URL_HOST ); + + try { + $result = $this->client->validate( $license_key, $domain ); + + // Update cached status. + $this->update_cached_status( 'valid', array( + 'product_id' => $result->productId, + 'expires_at' => $result->expiresAt?->format( 'c' ), + 'version_id' => $result->versionId, + ) ); + + return array( + 'success' => true, + 'message' => __( 'License validated successfully.', 'wp-fedistream' ), + 'data' => array( + 'status' => 'valid', + 'product_id' => $result->productId, + 'expires_at' => $result->expiresAt?->format( 'Y-m-d' ), + 'lifetime' => $result->isLifetime(), + ), + ); + } catch ( LicenseNotFoundException $e ) { + $this->update_cached_status( 'invalid' ); + return array( + 'success' => false, + 'message' => __( 'License key not found. Please check your license key.', 'wp-fedistream' ), + ); + } catch ( LicenseExpiredException $e ) { + $this->update_cached_status( 'expired' ); + return array( + 'success' => false, + 'message' => __( 'Your license has expired. Please renew to continue.', 'wp-fedistream' ), + ); + } catch ( LicenseRevokedException $e ) { + $this->update_cached_status( 'revoked' ); + return array( + 'success' => false, + 'message' => __( 'Your license has been revoked.', 'wp-fedistream' ), + ); + } catch ( LicenseInactiveException $e ) { + $this->update_cached_status( 'inactive' ); + return array( + 'success' => false, + 'message' => __( 'License is inactive. Please activate it first.', 'wp-fedistream' ), + ); + } catch ( DomainMismatchException $e ) { + $this->update_cached_status( 'invalid' ); + return array( + 'success' => false, + 'message' => __( 'This license is not activated for this domain.', 'wp-fedistream' ), + ); + } catch ( SignatureException $e ) { + return array( + 'success' => false, + 'message' => __( 'License verification failed. Please check your server secret.', 'wp-fedistream' ), + ); + } catch ( RateLimitExceededException $e ) { + return array( + 'success' => false, + 'message' => __( 'Too many requests. Please try again later.', 'wp-fedistream' ), + ); + } catch ( LicenseException $e ) { + return array( + 'success' => false, + 'message' => sprintf( + /* translators: %s: Error message */ + __( 'License validation failed: %s', 'wp-fedistream' ), + $e->getMessage() + ), + ); + } catch ( \Throwable $e ) { + return array( + 'success' => false, + 'message' => __( 'Unable to verify license. Please try again later.', 'wp-fedistream' ), + ); + } + } + + /** + * Activate the license for this domain. + * + * @return array{success: bool, message: string, data?: array} + */ + public function activate(): array { + if ( ! $this->init_client() ) { + return array( + 'success' => false, + 'message' => __( 'License server configuration is incomplete.', 'wp-fedistream' ), + ); + } + + $license_key = self::get_license_key(); + if ( empty( $license_key ) ) { + return array( + 'success' => false, + 'message' => __( 'No license key provided.', 'wp-fedistream' ), + ); + } + + $domain = wp_parse_url( home_url(), PHP_URL_HOST ); + + try { + $result = $this->client->activate( $license_key, $domain ); + + if ( $result->success ) { + // Validate after activation to get full license info. + return $this->validate(); + } + + return array( + 'success' => false, + 'message' => $result->message, + ); + } catch ( MaxActivationsReachedException $e ) { + return array( + 'success' => false, + 'message' => __( 'Maximum number of activations reached. Please deactivate another site first.', 'wp-fedistream' ), + ); + } catch ( LicenseNotFoundException $e ) { + return array( + 'success' => false, + 'message' => __( 'License key not found. Please check your license key.', 'wp-fedistream' ), + ); + } catch ( LicenseExpiredException $e ) { + return array( + 'success' => false, + 'message' => __( 'Your license has expired. Please renew to continue.', 'wp-fedistream' ), + ); + } catch ( SignatureException $e ) { + return array( + 'success' => false, + 'message' => __( 'License verification failed. Please check your server secret.', 'wp-fedistream' ), + ); + } catch ( LicenseException $e ) { + return array( + 'success' => false, + 'message' => sprintf( + /* translators: %s: Error message */ + __( 'License activation failed: %s', 'wp-fedistream' ), + $e->getMessage() + ), + ); + } catch ( \Throwable $e ) { + return array( + 'success' => false, + 'message' => __( 'Unable to activate license. Please try again later.', 'wp-fedistream' ), + ); + } + } + + /** + * Get the current license status. + * + * @param bool $force_refresh Force a fresh check from the server. + * @return array{success: bool, message: string, data?: array} + */ + public function get_status( bool $force_refresh = false ): array { + // Check cached status first. + if ( ! $force_refresh ) { + $cached = $this->get_cached_validation(); + if ( null !== $cached ) { + return $cached; + } + } + + if ( ! $this->init_client() ) { + return array( + 'success' => false, + 'message' => __( 'License server configuration is incomplete.', 'wp-fedistream' ), + 'data' => array( + 'status' => 'unconfigured', + ), + ); + } + + $license_key = self::get_license_key(); + if ( empty( $license_key ) ) { + return array( + 'success' => false, + 'message' => __( 'No license key configured.', 'wp-fedistream' ), + 'data' => array( + 'status' => 'unchecked', + ), + ); + } + + try { + $result = $this->client->status( $license_key ); + + $status_map = array( + LicenseState::Active->value => 'valid', + LicenseState::Inactive->value => 'inactive', + LicenseState::Expired->value => 'expired', + LicenseState::Revoked->value => 'revoked', + ); + + $status = $status_map[ $result->status->value ] ?? 'invalid'; + + $data = array( + 'status' => $status, + 'valid' => $result->valid, + 'domain' => $result->domain, + 'expires_at' => $result->expiresAt?->format( 'Y-m-d' ), + 'lifetime' => $result->isLifetime(), + 'activations_count' => $result->activationsCount, + 'max_activations' => $result->maxActivations, + ); + + // Cache the result. + $this->cache_validation( array( + 'success' => $result->valid, + 'message' => $result->valid + ? __( 'License is active.', 'wp-fedistream' ) + : __( 'License is not active.', 'wp-fedistream' ), + 'data' => $data, + ) ); + + $this->update_cached_status( $status, $data ); + + return array( + 'success' => $result->valid, + 'message' => $result->valid + ? __( 'License is active.', 'wp-fedistream' ) + : __( 'License is not active.', 'wp-fedistream' ), + 'data' => $data, + ); + } catch ( LicenseNotFoundException $e ) { + $this->update_cached_status( 'invalid' ); + return array( + 'success' => false, + 'message' => __( 'License key not found.', 'wp-fedistream' ), + 'data' => array( + 'status' => 'invalid', + ), + ); + } catch ( SignatureException $e ) { + return array( + 'success' => false, + 'message' => __( 'License verification failed. Please check your server secret.', 'wp-fedistream' ), + 'data' => array( + 'status' => 'error', + ), + ); + } catch ( \Throwable $e ) { + return array( + 'success' => false, + 'message' => __( 'Unable to check license status.', 'wp-fedistream' ), + 'data' => array( + 'status' => 'error', + ), + ); + } + } + + /** + * Deactivate the license (clear local data). + * + * @return bool + */ + public function deactivate(): bool { + self::clear_license_data(); + return true; + } + + /** + * Check if the license is currently valid. + * + * Uses cached status for performance. + * + * @return bool + */ + public static function is_license_valid(): bool { + $status = get_option( self::OPTION_LICENSE_STATUS, 'unchecked' ); + return 'valid' === $status; + } + + /** + * Get the license key. + * + * @return string + */ + public static function get_license_key(): string { + return get_option( self::OPTION_LICENSE_KEY, '' ); + } + + /** + * Get the license server URL. + * + * @return string + */ + public static function get_server_url(): string { + return get_option( self::OPTION_SERVER_URL, '' ); + } + + /** + * Get the server secret. + * + * @return string + */ + public static function get_server_secret(): string { + return get_option( self::OPTION_SERVER_SECRET, '' ); + } + + /** + * Get cached license status. + * + * @return string + */ + public static function get_cached_status(): string { + return get_option( self::OPTION_LICENSE_STATUS, 'unchecked' ); + } + + /** + * Get cached license data. + * + * @return array + */ + public static function get_cached_data(): array { + return get_option( self::OPTION_LICENSE_DATA, array() ); + } + + /** + * Get last check timestamp. + * + * @return int + */ + public static function get_last_check(): int { + return (int) get_option( self::OPTION_LAST_CHECK, 0 ); + } + + /** + * Save license settings. + * + * @param array $data Settings data. + * @return bool + */ + public static function save_settings( array $data ): bool { + if ( isset( $data['license_key'] ) ) { + update_option( self::OPTION_LICENSE_KEY, sanitize_text_field( $data['license_key'] ) ); + } + + if ( isset( $data['server_url'] ) ) { + update_option( self::OPTION_SERVER_URL, esc_url_raw( $data['server_url'] ) ); + } + + if ( isset( $data['server_secret'] ) ) { + // Only update if a new secret is provided. + $secret = sanitize_text_field( $data['server_secret'] ); + if ( ! empty( $secret ) ) { + update_option( self::OPTION_SERVER_SECRET, $secret ); + } + } + + // Reset status when settings change. + update_option( self::OPTION_LICENSE_STATUS, 'unchecked' ); + delete_transient( self::TRANSIENT_LICENSE_CHECK ); + + return true; + } + + /** + * Clear all license data. + * + * @return void + */ + public static function clear_license_data(): void { + update_option( self::OPTION_LICENSE_STATUS, 'unchecked' ); + update_option( self::OPTION_LICENSE_DATA, array() ); + update_option( self::OPTION_LAST_CHECK, 0 ); + delete_transient( self::TRANSIENT_LICENSE_CHECK ); + } + + /** + * Update cached license status. + * + * @param string $status Status value. + * @param array $data Additional data. + * @return void + */ + private function update_cached_status( string $status, array $data = array() ): void { + update_option( self::OPTION_LICENSE_STATUS, $status ); + update_option( self::OPTION_LICENSE_DATA, $data ); + update_option( self::OPTION_LAST_CHECK, time() ); + } + + /** + * Cache validation result. + * + * @param array $result Validation result. + * @return void + */ + private function cache_validation( array $result ): void { + set_transient( self::TRANSIENT_LICENSE_CHECK, $result, self::CACHE_TTL ); + } + + /** + * Get cached validation result. + * + * @return array|null + */ + private function get_cached_validation(): ?array { + $cached = get_transient( self::TRANSIENT_LICENSE_CHECK ); + return false === $cached ? null : $cached; + } + + /** + * AJAX handler: Validate license. + * + * @return void + */ + public function ajax_validate_license(): void { + check_ajax_referer( 'fedistream_license_action', 'nonce' ); + + if ( ! current_user_can( 'manage_fedistream_settings' ) ) { + wp_send_json_error( array( + 'message' => __( 'You do not have permission to perform this action.', 'wp-fedistream' ), + ) ); + } + + $result = $this->validate(); + + if ( $result['success'] ) { + wp_send_json_success( $result ); + } else { + wp_send_json_error( $result ); + } + } + + /** + * AJAX handler: Activate license. + * + * @return void + */ + public function ajax_activate_license(): void { + check_ajax_referer( 'fedistream_license_action', 'nonce' ); + + if ( ! current_user_can( 'manage_fedistream_settings' ) ) { + wp_send_json_error( array( + 'message' => __( 'You do not have permission to perform this action.', 'wp-fedistream' ), + ) ); + } + + $result = $this->activate(); + + if ( $result['success'] ) { + wp_send_json_success( $result ); + } else { + wp_send_json_error( $result ); + } + } + + /** + * AJAX handler: Deactivate license. + * + * @return void + */ + public function ajax_deactivate_license(): void { + check_ajax_referer( 'fedistream_license_action', 'nonce' ); + + if ( ! current_user_can( 'manage_fedistream_settings' ) ) { + wp_send_json_error( array( + 'message' => __( 'You do not have permission to perform this action.', 'wp-fedistream' ), + ) ); + } + + $this->deactivate(); + + wp_send_json_success( array( + 'success' => true, + 'message' => __( 'License deactivated.', 'wp-fedistream' ), + ) ); + } + + /** + * AJAX handler: Check license status. + * + * @return void + */ + public function ajax_check_status(): void { + check_ajax_referer( 'fedistream_license_action', 'nonce' ); + + if ( ! current_user_can( 'manage_fedistream_settings' ) ) { + wp_send_json_error( array( + 'message' => __( 'You do not have permission to perform this action.', 'wp-fedistream' ), + ) ); + } + + $force_refresh = isset( $_POST['force'] ) && 'true' === $_POST['force']; + $result = $this->get_status( $force_refresh ); + + if ( $result['success'] ) { + wp_send_json_success( $result ); + } else { + wp_send_json_error( $result ); + } + } +} diff --git a/includes/Plugin.php b/includes/Plugin.php index df8476f..5e0a9dc 100644 --- a/includes/Plugin.php +++ b/includes/Plugin.php @@ -27,6 +27,7 @@ use WP_FediStream\Taxonomies\License; use WP_FediStream\User\Library as UserLibrary; use WP_FediStream\User\LibraryPage; use WP_FediStream\User\Notifications; +use WP_FediStream\License\Manager as LicenseManager; // Prevent direct file access. if ( ! defined( 'ABSPATH' ) ) { @@ -155,10 +156,13 @@ final class Plugin { new ListColumns(); } - // Initialize frontend components. - if ( ! is_admin() ) { + // Initialize frontend components (only if licensed). + if ( ! is_admin() && LicenseManager::is_license_valid() ) { new TemplateLoader(); new Shortcodes(); + } elseif ( ! is_admin() ) { + // Register shortcodes that show license message. + new Shortcodes( true ); // Unlicensed mode. } // Initialize widgets (always needed for admin widget management). @@ -167,8 +171,8 @@ final class Plugin { // Initialize AJAX handlers. new Ajax(); - // Initialize ActivityPub integration. - if ( get_option( 'wp_fedistream_enable_activitypub', 1 ) ) { + // Initialize ActivityPub integration (only if licensed and enabled). + if ( get_option( 'wp_fedistream_enable_activitypub', 1 ) && LicenseManager::is_license_valid() ) { new ActivityPubIntegration(); new ActivityPubRestApi(); } @@ -184,6 +188,9 @@ final class Plugin { new UserLibrary(); new LibraryPage(); new Notifications(); + + // Initialize license manager. + LicenseManager::get_instance(); } /** @@ -409,86 +416,334 @@ final class Plugin { return; } - // Save settings. - if ( isset( $_POST['fedistream_settings_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['fedistream_settings_nonce'] ), 'fedistream_save_settings' ) ) { - update_option( 'wp_fedistream_enable_activitypub', isset( $_POST['enable_activitypub'] ) ? 1 : 0 ); - update_option( 'wp_fedistream_enable_woocommerce', isset( $_POST['enable_woocommerce'] ) ? 1 : 0 ); - update_option( 'wp_fedistream_max_upload_size', absint( $_POST['max_upload_size'] ?? 50 ) ); - update_option( 'wp_fedistream_default_license', sanitize_text_field( wp_unslash( $_POST['default_license'] ?? 'all-rights-reserved' ) ) ); + // Get current tab. + $current_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'license'; - echo '

' . esc_html__( 'Settings saved.', 'wp-fedistream' ) . '

'; - } + // Handle form submissions. + $this->handle_settings_save( $current_tab ); // Get current settings. $enable_activitypub = get_option( 'wp_fedistream_enable_activitypub', 1 ); $enable_woocommerce = get_option( 'wp_fedistream_enable_woocommerce', 0 ); $max_upload_size = get_option( 'wp_fedistream_max_upload_size', 50 ); $default_license = get_option( 'wp_fedistream_default_license', 'all-rights-reserved' ); + + // License settings. + $license_key = LicenseManager::get_license_key(); + $license_server_url = LicenseManager::get_server_url(); + $license_status = LicenseManager::get_cached_status(); + $license_data = LicenseManager::get_cached_data(); + $last_check = LicenseManager::get_last_check(); + + $tabs = array( + 'license' => __( 'License', 'wp-fedistream' ), + 'settings' => __( 'Default Settings', 'wp-fedistream' ), + 'integrations' => __( 'Integrations', 'wp-fedistream' ), + ); ?>

-
- + - - - - - - - - - - - - - - - - - -
- -

-
- - is_woocommerce_active() ) : ?> -

- -

- -
- - - MB -

-
- - - -

-
- - -
+
+ render_license_tab( $license_key, $license_server_url, $license_status, $license_data, $last_check ); + break; + case 'settings': + $this->render_settings_tab( $max_upload_size, $default_license ); + break; + case 'integrations': + $this->render_integrations_tab( $enable_activitypub, $enable_woocommerce ); + break; + } + ?> +
isset( $_POST['license_key'] ) ? sanitize_text_field( wp_unslash( $_POST['license_key'] ) ) : '', + 'server_url' => isset( $_POST['license_server_url'] ) ? esc_url_raw( wp_unslash( $_POST['license_server_url'] ) ) : '', + 'server_secret' => isset( $_POST['license_server_secret'] ) ? sanitize_text_field( wp_unslash( $_POST['license_server_secret'] ) ) : '', + ) ); + echo '

' . esc_html__( 'License settings saved.', 'wp-fedistream' ) . '

'; + break; + + case 'settings': + update_option( 'wp_fedistream_max_upload_size', absint( $_POST['max_upload_size'] ?? 50 ) ); + update_option( 'wp_fedistream_default_license', sanitize_text_field( wp_unslash( $_POST['default_license'] ?? 'all-rights-reserved' ) ) ); + echo '

' . esc_html__( 'Settings saved.', 'wp-fedistream' ) . '

'; + break; + + case 'integrations': + update_option( 'wp_fedistream_enable_activitypub', isset( $_POST['enable_activitypub'] ) ? 1 : 0 ); + update_option( 'wp_fedistream_enable_woocommerce', isset( $_POST['enable_woocommerce'] ) ? 1 : 0 ); + echo '

' . esc_html__( 'Integration settings saved.', 'wp-fedistream' ) . '

'; + break; + } + } + + /** + * Render the License tab. + * + * @param string $license_key License key. + * @param string $server_url Server URL. + * @param string $status License status. + * @param array $license_data License data. + * @param int $last_check Last check timestamp. + * @return void + */ + private function render_license_tab( string $license_key, string $server_url, string $status, array $license_data, int $last_check ): void { + $status_classes = array( + 'valid' => 'notice-success', + 'invalid' => 'notice-error', + 'expired' => 'notice-warning', + 'revoked' => 'notice-error', + 'inactive' => 'notice-warning', + 'unchecked' => 'notice-info', + 'unconfigured' => 'notice-info', + ); + + $status_messages = array( + 'valid' => __( 'License is active and valid.', 'wp-fedistream' ), + 'invalid' => __( 'License is invalid.', 'wp-fedistream' ), + 'expired' => __( 'License has expired.', 'wp-fedistream' ), + 'revoked' => __( 'License has been revoked.', 'wp-fedistream' ), + 'inactive' => __( 'License is inactive. Please activate it.', 'wp-fedistream' ), + 'unchecked' => __( 'License has not been validated yet.', 'wp-fedistream' ), + 'unconfigured' => __( 'License server is not configured.', 'wp-fedistream' ), + ); + + $status_icons = array( + 'valid' => 'dashicons-yes-alt', + 'invalid' => 'dashicons-dismiss', + 'expired' => 'dashicons-warning', + 'revoked' => 'dashicons-dismiss', + 'inactive' => 'dashicons-marker', + 'unchecked' => 'dashicons-info-outline', + 'unconfigured' => 'dashicons-admin-generic', + ); + + $status_class = $status_classes[ $status ] ?? 'notice-info'; + $status_message = $status_messages[ $status ] ?? __( 'Unknown status.', 'wp-fedistream' ); + $status_icon = $status_icons[ $status ] ?? 'dashicons-info-outline'; + ?> +
+ +
+ + +
+ + + + +
+ + + 0 ) : ?> +
+ + + + +
+
+ +
+ + + + + + + + + + + + + + + +
+ + + +

+
+ + + +

+
+ + + +

+
+ +

+ + + + +

+
+ + + + + +
+ + + + + + + + + + + +
+ + + MB +

+
+ + + +

+
+ + +
+ +
+ + + + + + + + + + + +
+ +

+ is_activitypub_active() ) : ?> +

+ + +

+ +
+ + is_woocommerce_active() ) : ?> +

+ + +

+ +

+ +
+ + +
+ mQvAv%4#?0=_UNXDu@y_fnhJanueY(4t z>Z*2K=CVey{E!G)5GP8A@(_@fIKTtK5GiqpCK1vIDG((_$_pqKiWD9YQv7B`iFnBG zf9h0s^~^4$G^c-6=YGEPec$=c{P?}seKFwqEa?NJpI;jUUxjbnzz@&XfgpG{+=jQp z7vVeLUqJqXuk&*od=0)I{s8_u{29CnUjNRj{w?r!zCQ?m4IYN-?+K`OeV_jVd^_KN z2Cs)-hPS}K^55Tvn%Z~Zb?~1cLk0f=`3ru?&%N*`@T2f%CZYL01XcfW_%65rwXRiY zpoJ_w_{zh8$R=KCj5`*tIps{UQ@9(WjPULlmc zOV7{4hxqi|M-!&#{Pe+J$Mdr075k3faq5A!AsD5vyk>+z6-UXk6YX3ac z{`?`l8-5KQf4c;55Rq3VAdmTzMn5RnAu=v@6j!;ikV zAVtB8Q0sabYM;IWHNS5{>GgM@>c0Uc-#4M^-_EA1zJZ$meNg#FJm)=6LYf3;q3T=D z6iQCp{`+^K?Ba9qA^0coG5CF7egnp#{@(+oSGPjV|D#a){TP%yJ`GiG4a&X;zI@&D z3sCm`Dnzuw-$RB7UWaP;Q>cA>6Kb5dp!DE6lv{dtKa~DH3f2A+l$>IycAtZi$4j0s zL$*Hn7SuT3g|gQl!we*70tGPk}8c`Sqae>WfhG{vLc3z78dicc5I_ zhdZIlAA!=dqwoxzhuW_{fal;2lziXG<~{=NfLg~TsQx0T`Y%Au<5j5j{S+?1>k+c{ za|vpk5!8ALsPUik-!H(o@m)V|ZG1>KuJM_xP}isoyD9{m z@R)!9I2`)-*z>pH10?z5&-%PiLrap+(mv|BK*~tcmx#1PdWKX#*Ybkdx<|UB=OU?e zZSxk@Vb0x=fNT>iMk-!8&}F^hpvX8f=gjNWpxkh&IB)nln+yCb_LL zqGEfwTr;PW!uGSUh|(mO?{>|6yjBjYx2%Zr!o8lenSHwvJL_(g?X=8H=(@;FnwhmQ>E>;UhEZb9+N3mv-72cl^ZnUX!+rVnVEbFR zk;$%BtY3Y^=6uv26uCKXbDM40ZZPjxO0e!~}+gT*9Vi>+}w;#H!@8p_P(b=jpf zWsO6db*veeov__#rC_Ov zhTdQpxo$HEbF*e`Vlumtu4_)s61z2uvb~u}T2xKk{FqbMY};beFv^V^2z5bET%{`% zPGv<&)uL^d-P)=Sq%+ZU$5ADesm7X*Z$6&7%RKwRznj+k*19i)ZH1o34v3cGrJD+|tsN!Z6ODz{L7c^BY6C$7b3c#m>6 z+%gxO!I_olvZb%BXjl$SkI9&v9A}nc*^SbPVV&BmYd!+Efrj>*0&umX=<(98jTn`>_%CX`BLa6+KJT30n$U~tld1ZfL9H*P? zi$G>Oc(RPp_IX@En&g3ZCO9~}@CshZ)cQE~ZY!3vqv83TL&C2Qvb5|EOv8(|1MhZL zoc8hMy?6am`@NMxm^IG>vk`?;u6plM?hICtV9XTLI1N@=r53Q^9s4LQ`y8bhofHC( zo}d#>7iB{Yfkcy_pzV6WKbo{RZTpo4shke6;KC*a9Y0&*3UO_fM{}K4=R~c$zJ)(Y z_P6jV?yJ=b?>&WcV9uB7WGgguHywsiLiMO%;lwCr7$(yBXG@NOd~Ezhwr#>bRSk!= z&1m3G4CfXnHa5xhKGEywDy9)!s18e=wTWOLGx2OG^4@Sm?(=Mh8Sgul7%W*kN zKSLc zwN?r2<`iPtao(Ki+NY17I&k*%*~Q69XIa_t%J^HdkvSKn9~{LP+7W~Naj?bF3#%tu zhbQ$klb+35i$n%p9M+sUycQJ)mSduZxOD=($r&7X#b&=FI;9=#_qcOEsf_Z~Sw zAaU6ymrb}X_hwOyV1DB1T1|a+N4Ob8$>p-QyTj=gEbZ=~&@pjeGuPFdlm(X}+qGFg zT(deb?cVRHw)h?!Pvx9&Lvj9Fb9#UipNyH(tI;JQuNrW}iPxI5+B;Gr*Jk6%MMaB6 zJBV;Q0}Og2&DQK7jB&t?>5m5t+=XRH7ZwR?>b|m=Rf?9liMn|hl+bM2C@0v}>~qq% zuf$v~+rf0JJ#tDOFoZg8&1bp8tkc4*yJ%3mwC6^{Rg?HX>2kq|-G+`ot$YqPP$t^3 z=}Lxu)U~FxKFq4`HDPJ9fJ;qN6;6~1%SMrtrm{4gU+c;>CKs4s@_OY9&f?TuE2rUp zxk5?6W~DR8q5>Ui=w&{<oS}*@z<|Ba&}aWAPV~{_aj(M1AyT#Z?*DsK^WMA;@!5 zYMh$1bOkzxY&0+qY4>k?Jx*qhok1nb%5uB`<()yiyOZarSC#MM;_5==OpN=GH!^p} zaCw_0;iTCl#LTji?iJX(0xZRZYkeDsQ`uGhB<&1L!bFNHIKXZvUAmSU$SI&-@pQi` zoyy@pUzoY+$!}vHMEWjr!BoiQ@`C{JL-06zDHdFTYnh zq2qogt=qpJE*Oa}(<5Tz+CPZVP$tgdkhFinD*cVRb<(1w!z98q&sf|WCl8kFB~W=h z!x)=;+*TuRuU}~tRql4u++DCjJYse0YMn&u(dp{qrFR+{NOaQ*G8BN6l^jdsJwbJ^?l?PYC4qO0iMbqB{d zfb1IjJw67e9R0rf<7#-75v zqh&mDu<~|zFak6F6@}awzY@W;F4m4trx@M1&Z`}DX4AYWN$%_3l~i}8iDCtdQ*L+a zYucTzS}xubJ2cg~R1MZRDyEh{eUsw2*nl#$D65A0JJGEJ$eVnttgdswG!fsOc^zzPqS9 zz2eXe!9SX0Ame)8FaFZOFC=SrJ=8Kd(fvK}Ovv=zSy9PhpuiDrIdtNq>1EyIPT{wP%JHz4>;%(_#$V>kj%ZvL~E^dFGEqZ{+i z@Nr-CW5xgke^%}K5PH2|y2^PHcoSN`cpW!Z^ME?uM2**Rz1~WcOF~7vw($Fm7 RG1>v4RN$j92fvBI{{b)w^Zoz; literal 0 HcmV?d00001 diff --git a/languages/wp-fedistream-de_CH.po b/languages/wp-fedistream-de_CH.po new file mode 100644 index 0000000..63dc67a --- /dev/null +++ b/languages/wp-fedistream-de_CH.po @@ -0,0 +1,2287 @@ +# German translations for WP FediStream package +# German translation for WP FediStream. +# Copyright (C) 2026 THE WP FediStream'S COPYRIGHT HOLDER +# This file is distributed under the same license as the WP FediStream package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: WP FediStream 0.3.0\n" +"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/magdev/wp-fedistream/" +"issues\n" +"POT-Creation-Date: 2026-01-29 11:53+0100\n" +"PO-Revision-Date: 2026-01-29 11:53+0100\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: de_CH\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: includes/Admin/ListColumns.php:66 includes/Admin/ListColumns.php:148 +#: includes/WooCommerce/DigitalDelivery.php:391 +msgid "Type" +msgstr "Typ" + +#: includes/Admin/ListColumns.php:67 includes/Frontend/TemplateLoader.php:503 +#: includes/User/LibraryPage.php:111 includes/Plugin.php:297 +#: includes/Plugin.php:298 includes/Plugin.php:365 +msgid "Albums" +msgstr "Alben" + +#: includes/Admin/ListColumns.php:68 includes/Admin/ListColumns.php:149 +#: includes/Admin/ListColumns.php:361 includes/Frontend/TemplateLoader.php:506 +#: includes/User/LibraryPage.php:110 includes/Plugin.php:306 +#: includes/Plugin.php:307 includes/Plugin.php:371 +msgid "Tracks" +msgstr "Titel" + +#: includes/Admin/ListColumns.php:74 includes/Admin/ListColumns.php:155 +#: includes/Admin/ListColumns.php:256 includes/Admin/ListColumns.php:368 +msgid "Date" +msgstr "Datum" + +#: includes/Admin/ListColumns.php:100 includes/Admin/ListColumns.php:105 +msgid "Solo" +msgstr "Solo" + +#: includes/Admin/ListColumns.php:101 includes/PostTypes/Artist.php:147 +#: includes/Frontend/TemplateLoader.php:242 includes/User/LibraryPage.php:249 +msgid "Band" +msgstr "Band" + +#: includes/Admin/ListColumns.php:102 includes/PostTypes/Artist.php:148 +#: includes/Frontend/TemplateLoader.php:243 +msgid "Duo" +msgstr "Duo" + +#: includes/Admin/ListColumns.php:103 includes/PostTypes/Artist.php:149 +#: includes/Frontend/TemplateLoader.php:244 +msgid "Collective" +msgstr "Kollektiv" + +#: includes/Admin/ListColumns.php:147 includes/PostTypes/Album.php:108 +#: includes/User/LibraryPage.php:249 +msgid "Artist" +msgstr "Künstler" + +#: includes/Admin/ListColumns.php:150 includes/PostTypes/Album.php:157 +msgid "Release Date" +msgstr "Erscheinungsdatum" + +#: includes/Admin/ListColumns.php:186 includes/Admin/ListColumns.php:298 +msgid "No artist" +msgstr "Kein Künstler" + +#: includes/Admin/ListColumns.php:193 includes/Admin/ListColumns.php:200 +#: includes/Admin/ListColumns.php:249 includes/PostTypes/Album.php:146 +#: includes/PostTypes/Track.php:125 includes/Frontend/TemplateLoader.php:287 +#: includes/Frontend/Widgets/RecentReleasesWidget.php:124 +msgid "Album" +msgstr "Album" + +#: includes/Admin/ListColumns.php:194 includes/PostTypes/Album.php:147 +#: includes/Frontend/TemplateLoader.php:288 +#: includes/Frontend/Widgets/RecentReleasesWidget.php:125 +msgid "EP" +msgstr "EP" + +#: includes/Admin/ListColumns.php:195 includes/Admin/ListColumns.php:310 +#: includes/PostTypes/Album.php:148 includes/Frontend/TemplateLoader.php:289 +#: includes/Frontend/Widgets/RecentReleasesWidget.php:126 +msgid "Single" +msgstr "Single" + +#: includes/Admin/ListColumns.php:196 includes/PostTypes/Album.php:149 +#: includes/Frontend/TemplateLoader.php:290 +#: includes/Frontend/Widgets/RecentReleasesWidget.php:127 +msgid "Compilation" +msgstr "Compilation" + +#: includes/Admin/ListColumns.php:197 +msgid "Live" +msgstr "" + +#: includes/Admin/ListColumns.php:198 +msgid "Remix" +msgstr "" + +#: includes/Admin/ListColumns.php:248 includes/PostTypes/Track.php:134 +#: includes/Frontend/TemplateLoader.php:500 +#: includes/Frontend/Shortcodes.php:414 includes/User/LibraryPage.php:99 +#: includes/Plugin.php:288 includes/Plugin.php:289 includes/Plugin.php:359 +msgid "Artists" +msgstr "Künstler" + +#: includes/Admin/ListColumns.php:250 includes/Admin/ListColumns.php:362 +msgid "Duration" +msgstr "Dauer" + +#: includes/Admin/ListColumns.php:251 +msgid "Plays" +msgstr "" + +#: includes/Admin/ListColumns.php:363 includes/PostTypes/Playlist.php:280 +msgid "Visibility" +msgstr "" + +#: includes/Admin/ListColumns.php:416 includes/Admin/ListColumns.php:426 +#: includes/PostTypes/Playlist.php:282 +msgid "Public" +msgstr "" + +#: includes/Admin/ListColumns.php:417 +msgid "Unlisted" +msgstr "" + +#: includes/Admin/ListColumns.php:418 includes/PostTypes/Playlist.php:284 +msgid "Private" +msgstr "" + +#: includes/PostTypes/Artist.php:43 +msgctxt "Post type general name" +msgid "Artists" +msgstr "Künstler" + +#: includes/PostTypes/Artist.php:44 +msgctxt "Post type singular name" +msgid "Artist" +msgstr "Künstler" + +#: includes/PostTypes/Artist.php:45 +msgctxt "Admin Menu text" +msgid "Artists" +msgstr "Künstler" + +#: includes/PostTypes/Artist.php:46 +msgctxt "Add New on Toolbar" +msgid "Artist" +msgstr "Künstler" + +#: includes/PostTypes/Artist.php:47 includes/PostTypes/Album.php:47 +#: includes/PostTypes/Track.php:55 includes/PostTypes/Playlist.php:47 +msgid "Add New" +msgstr "" + +#: includes/PostTypes/Artist.php:48 +msgid "Add New Artist" +msgstr "" + +#: includes/PostTypes/Artist.php:49 +msgid "New Artist" +msgstr "" + +#: includes/PostTypes/Artist.php:50 +msgid "Edit Artist" +msgstr "" + +#: includes/PostTypes/Artist.php:51 +msgid "View Artist" +msgstr "" + +#: includes/PostTypes/Artist.php:52 +msgid "All Artists" +msgstr "" + +#: includes/PostTypes/Artist.php:53 +msgid "Search Artists" +msgstr "" + +#: includes/PostTypes/Artist.php:54 +msgid "Parent Artists:" +msgstr "" + +#: includes/PostTypes/Artist.php:55 +msgid "No artists found." +msgstr "" + +#: includes/PostTypes/Artist.php:56 +msgid "No artists found in Trash." +msgstr "" + +#: includes/PostTypes/Artist.php:57 +msgctxt "Overrides the \"Featured Image\" phrase" +msgid "Artist Photo" +msgstr "" + +#: includes/PostTypes/Artist.php:58 +msgctxt "Overrides the \"Set featured image\" phrase" +msgid "Set artist photo" +msgstr "" + +#: includes/PostTypes/Artist.php:59 +msgctxt "Overrides the \"Remove featured image\" phrase" +msgid "Remove artist photo" +msgstr "" + +#: includes/PostTypes/Artist.php:60 +msgctxt "Overrides the \"Use as featured image\" phrase" +msgid "Use as artist photo" +msgstr "" + +#: includes/PostTypes/Artist.php:61 +msgctxt "The post type archive label" +msgid "Artist archives" +msgstr "" + +#: includes/PostTypes/Artist.php:62 +msgctxt "Overrides the \"Insert into post\" phrase" +msgid "Insert into artist" +msgstr "" + +#: includes/PostTypes/Artist.php:63 +msgctxt "Overrides the \"Uploaded to this post\" phrase" +msgid "Uploaded to this artist" +msgstr "" + +#: includes/PostTypes/Artist.php:64 +msgctxt "Screen reader text" +msgid "Filter artists list" +msgstr "" + +#: includes/PostTypes/Artist.php:65 +msgctxt "Screen reader text" +msgid "Artists list navigation" +msgstr "" + +#: includes/PostTypes/Artist.php:66 +msgctxt "Screen reader text" +msgid "Artists list" +msgstr "" + +#: includes/PostTypes/Artist.php:99 +msgid "Artist Information" +msgstr "" + +#: includes/PostTypes/Artist.php:108 +msgid "Social Links" +msgstr "" + +#: includes/PostTypes/Artist.php:117 +msgid "Band Members" +msgstr "" + +#: includes/PostTypes/Artist.php:142 +msgid "Artist Type" +msgstr "" + +#: includes/PostTypes/Artist.php:146 includes/Frontend/TemplateLoader.php:241 +msgid "Solo Artist" +msgstr "" + +#: includes/PostTypes/Artist.php:155 +msgid "Formed Date" +msgstr "" + +#: includes/PostTypes/Artist.php:159 +msgid "When the artist/band was formed or started their career." +msgstr "" + +#: includes/PostTypes/Artist.php:164 includes/ActivityPub/ArtistActor.php:273 +msgid "Location" +msgstr "" + +#: includes/PostTypes/Artist.php:168 +msgid "City, Country or region where the artist is based." +msgstr "" + +#: includes/PostTypes/Artist.php:173 includes/ActivityPub/ArtistActor.php:263 +msgid "Website" +msgstr "" + +#: includes/PostTypes/Artist.php:177 +msgid "Official website URL." +msgstr "" + +#: includes/PostTypes/Artist.php:197 +msgid "Mastodon" +msgstr "" + +#: includes/PostTypes/Artist.php:198 +msgid "Bandcamp" +msgstr "" + +#: includes/PostTypes/Artist.php:199 +msgid "SoundCloud" +msgstr "" + +#: includes/PostTypes/Artist.php:200 +msgid "YouTube" +msgstr "" + +#: includes/PostTypes/Artist.php:201 +msgid "Instagram" +msgstr "" + +#: includes/PostTypes/Artist.php:202 +msgid "Twitter/X" +msgstr "" + +#: includes/PostTypes/Artist.php:203 +msgid "Facebook" +msgstr "" + +#: includes/PostTypes/Artist.php:204 +msgid "TikTok" +msgstr "" + +#: includes/PostTypes/Artist.php:205 +msgid "Other" +msgstr "" + +#: includes/PostTypes/Artist.php:238 +msgid "Add band/group members (comma-separated names)." +msgstr "" + +#: includes/PostTypes/Artist.php:240 +msgid "One member per line." +msgstr "" + +#: includes/PostTypes/Album.php:43 +msgctxt "Post type general name" +msgid "Albums" +msgstr "Alben" + +#: includes/PostTypes/Album.php:44 +msgctxt "Post type singular name" +msgid "Album" +msgstr "Album" + +#: includes/PostTypes/Album.php:45 +msgctxt "Admin Menu text" +msgid "Albums" +msgstr "Alben" + +#: includes/PostTypes/Album.php:46 +msgctxt "Add New on Toolbar" +msgid "Album" +msgstr "Album" + +#: includes/PostTypes/Album.php:48 +msgid "Add New Album" +msgstr "" + +#: includes/PostTypes/Album.php:49 +msgid "New Album" +msgstr "" + +#: includes/PostTypes/Album.php:50 +msgid "Edit Album" +msgstr "" + +#: includes/PostTypes/Album.php:51 +msgid "View Album" +msgstr "" + +#: includes/PostTypes/Album.php:52 +msgid "All Albums" +msgstr "" + +#: includes/PostTypes/Album.php:53 +msgid "Search Albums" +msgstr "" + +#: includes/PostTypes/Album.php:54 +msgid "Parent Albums:" +msgstr "" + +#: includes/PostTypes/Album.php:55 +msgid "No albums found." +msgstr "" + +#: includes/PostTypes/Album.php:56 +msgid "No albums found in Trash." +msgstr "" + +#: includes/PostTypes/Album.php:57 +msgctxt "Overrides the \"Featured Image\" phrase" +msgid "Album Artwork" +msgstr "" + +#: includes/PostTypes/Album.php:58 +msgctxt "Overrides the \"Set featured image\" phrase" +msgid "Set album artwork" +msgstr "" + +#: includes/PostTypes/Album.php:59 +msgctxt "Overrides the \"Remove featured image\" phrase" +msgid "Remove album artwork" +msgstr "" + +#: includes/PostTypes/Album.php:60 +msgctxt "Overrides the \"Use as featured image\" phrase" +msgid "Use as album artwork" +msgstr "" + +#: includes/PostTypes/Album.php:61 +msgctxt "The post type archive label" +msgid "Album archives" +msgstr "" + +#: includes/PostTypes/Album.php:62 +msgctxt "Overrides the \"Insert into post\" phrase" +msgid "Insert into album" +msgstr "" + +#: includes/PostTypes/Album.php:63 +msgctxt "Overrides the \"Uploaded to this post\" phrase" +msgid "Uploaded to this album" +msgstr "" + +#: includes/PostTypes/Album.php:64 +msgctxt "Screen reader text" +msgid "Filter albums list" +msgstr "" + +#: includes/PostTypes/Album.php:65 +msgctxt "Screen reader text" +msgid "Albums list navigation" +msgstr "" + +#: includes/PostTypes/Album.php:66 +msgctxt "Screen reader text" +msgid "Albums list" +msgstr "" + +#: includes/PostTypes/Album.php:99 +msgid "Album Information" +msgstr "" + +#: includes/PostTypes/Album.php:117 +msgid "Album Codes" +msgstr "" + +#: includes/PostTypes/Album.php:142 +msgid "Release Type" +msgstr "" + +#: includes/PostTypes/Album.php:150 includes/Frontend/TemplateLoader.php:291 +msgid "Live Album" +msgstr "" + +#: includes/PostTypes/Album.php:151 includes/Frontend/TemplateLoader.php:292 +msgid "Remix Album" +msgstr "" + +#: includes/PostTypes/Album.php:165 +msgid "Total Tracks" +msgstr "" + +#: includes/PostTypes/Album.php:169 +msgid "Auto-calculated when tracks are added." +msgstr "" + +#: includes/PostTypes/Album.php:174 +msgid "Total Duration" +msgstr "" + +#: includes/PostTypes/Album.php:178 +msgid "seconds (auto-calculated)" +msgstr "" + +#: includes/PostTypes/Album.php:205 +msgid "Primary Artist" +msgstr "" + +#: includes/PostTypes/Album.php:208 +msgid "— Select Artist —" +msgstr "" + +#: includes/PostTypes/Album.php:220 includes/PostTypes/Track.php:479 +#, php-format +msgid "No artists found. %s" +msgstr "" + +#: includes/PostTypes/Album.php:221 includes/PostTypes/Track.php:480 +msgid "Add an artist first." +msgstr "" + +#: includes/PostTypes/Album.php:240 +msgid "UPC/EAN" +msgstr "" + +#: includes/PostTypes/Album.php:241 +msgid "12-13 digit UPC/EAN code" +msgstr "" + +#: includes/PostTypes/Album.php:244 +msgid "Catalog Number" +msgstr "" + +#: includes/PostTypes/Track.php:51 +msgctxt "Post type general name" +msgid "Tracks" +msgstr "Titel" + +#: includes/PostTypes/Track.php:52 +msgctxt "Post type singular name" +msgid "Track" +msgstr "" + +#: includes/PostTypes/Track.php:53 +msgctxt "Admin Menu text" +msgid "Tracks" +msgstr "Titel" + +#: includes/PostTypes/Track.php:54 +msgctxt "Add New on Toolbar" +msgid "Track" +msgstr "" + +#: includes/PostTypes/Track.php:56 +msgid "Add New Track" +msgstr "" + +#: includes/PostTypes/Track.php:57 +msgid "New Track" +msgstr "" + +#: includes/PostTypes/Track.php:58 +msgid "Edit Track" +msgstr "" + +#: includes/PostTypes/Track.php:59 +msgid "View Track" +msgstr "" + +#: includes/PostTypes/Track.php:60 +msgid "All Tracks" +msgstr "" + +#: includes/PostTypes/Track.php:61 +msgid "Search Tracks" +msgstr "" + +#: includes/PostTypes/Track.php:62 +msgid "Parent Tracks:" +msgstr "" + +#: includes/PostTypes/Track.php:63 +msgid "No tracks found." +msgstr "" + +#: includes/PostTypes/Track.php:64 +msgid "No tracks found in Trash." +msgstr "" + +#: includes/PostTypes/Track.php:65 +msgctxt "Overrides the \"Featured Image\" phrase" +msgid "Track Artwork" +msgstr "" + +#: includes/PostTypes/Track.php:66 +msgctxt "Overrides the \"Set featured image\" phrase" +msgid "Set track artwork" +msgstr "" + +#: includes/PostTypes/Track.php:67 +msgctxt "Overrides the \"Remove featured image\" phrase" +msgid "Remove track artwork" +msgstr "" + +#: includes/PostTypes/Track.php:68 +msgctxt "Overrides the \"Use as featured image\" phrase" +msgid "Use as track artwork" +msgstr "" + +#: includes/PostTypes/Track.php:69 +msgctxt "The post type archive label" +msgid "Track archives" +msgstr "" + +#: includes/PostTypes/Track.php:70 +msgctxt "Overrides the \"Insert into post\" phrase" +msgid "Insert into track" +msgstr "" + +#: includes/PostTypes/Track.php:71 +msgctxt "Overrides the \"Uploaded to this post\" phrase" +msgid "Uploaded to this track" +msgstr "" + +#: includes/PostTypes/Track.php:72 +msgctxt "Screen reader text" +msgid "Filter tracks list" +msgstr "" + +#: includes/PostTypes/Track.php:73 +msgctxt "Screen reader text" +msgid "Tracks list navigation" +msgstr "" + +#: includes/PostTypes/Track.php:74 +msgctxt "Screen reader text" +msgid "Tracks list" +msgstr "" + +#: includes/PostTypes/Track.php:107 includes/PostTypes/Track.php:168 +msgid "Audio File" +msgstr "" + +#: includes/PostTypes/Track.php:116 +msgid "Track Information" +msgstr "" + +#: includes/PostTypes/Track.php:143 +msgid "Track Codes" +msgstr "" + +#: includes/PostTypes/Track.php:185 includes/PostTypes/Track.php:241 +msgid "Select Audio File" +msgstr "" + +#: includes/PostTypes/Track.php:186 includes/PostTypes/Playlist.php:184 +#: includes/PostTypes/Playlist.php:252 +msgid "Remove" +msgstr "" + +#: includes/PostTypes/Track.php:188 +msgid "Supported formats: MP3, WAV, FLAC, OGG" +msgstr "" + +#: includes/PostTypes/Track.php:194 +msgid "Audio Format" +msgstr "" + +#: includes/PostTypes/Track.php:198 +msgid "— Auto-detect —" +msgstr "" + +#: includes/PostTypes/Track.php:208 +msgid "Duration (seconds)" +msgstr "" + +#: includes/PostTypes/Track.php:217 +#, php-format +msgid "(%s)" +msgstr "" + +#: includes/PostTypes/Track.php:223 +msgid "Auto-detected from audio file if available." +msgstr "" + +#: includes/PostTypes/Track.php:242 +msgid "Use this file" +msgstr "" + +#: includes/PostTypes/Track.php:305 +msgid "— Select Key —" +msgstr "" + +#: includes/PostTypes/Track.php:335 +msgid "Track Number" +msgstr "" + +#: includes/PostTypes/Track.php:343 +msgid "Disc Number" +msgstr "" + +#: includes/PostTypes/Track.php:351 +msgid "BPM" +msgstr "" + +#: includes/PostTypes/Track.php:355 +msgid "Beats per minute (tempo)." +msgstr "" + +#: includes/PostTypes/Track.php:360 +msgid "Musical Key" +msgstr "" + +#: includes/PostTypes/Track.php:372 +msgid "Explicit Content" +msgstr "" + +#: includes/PostTypes/Track.php:377 +msgid "This track contains explicit content" +msgstr "" + +#: includes/PostTypes/Track.php:383 +msgid "Preview Settings" +msgstr "" + +#: includes/PostTypes/Track.php:387 +msgid "Start at:" +msgstr "" + +#: includes/PostTypes/Track.php:389 includes/PostTypes/Track.php:395 +msgid "seconds" +msgstr "" + +#: includes/PostTypes/Track.php:393 +msgid "Duration:" +msgstr "" + +#: includes/PostTypes/Track.php:397 +msgid "Preview clip for non-authenticated users or before purchase." +msgstr "" + +#: includes/PostTypes/Track.php:425 +msgid "— No Album (Single) —" +msgstr "" + +#: includes/PostTypes/Track.php:465 +msgid "Select all artists featured on this track." +msgstr "" + +#: includes/PostTypes/Track.php:498 +msgid "ISRC" +msgstr "" + +#: includes/PostTypes/Track.php:499 +msgid "ISRC format: CC-XXX-YY-NNNNN" +msgstr "" + +#: includes/PostTypes/Track.php:500 +msgid "International Standard Recording Code" +msgstr "" + +#: includes/PostTypes/Playlist.php:43 +msgctxt "Post type general name" +msgid "Playlists" +msgstr "Wiedergabelisten" + +#: includes/PostTypes/Playlist.php:44 +msgctxt "Post type singular name" +msgid "Playlist" +msgstr "Wiedergabeliste" + +#: includes/PostTypes/Playlist.php:45 +msgctxt "Admin Menu text" +msgid "Playlists" +msgstr "Wiedergabelisten" + +#: includes/PostTypes/Playlist.php:46 +msgctxt "Add New on Toolbar" +msgid "Playlist" +msgstr "Wiedergabeliste" + +#: includes/PostTypes/Playlist.php:48 +msgid "Add New Playlist" +msgstr "" + +#: includes/PostTypes/Playlist.php:49 +msgid "New Playlist" +msgstr "" + +#: includes/PostTypes/Playlist.php:50 +msgid "Edit Playlist" +msgstr "" + +#: includes/PostTypes/Playlist.php:51 +msgid "View Playlist" +msgstr "" + +#: includes/PostTypes/Playlist.php:52 +msgid "All Playlists" +msgstr "" + +#: includes/PostTypes/Playlist.php:53 +msgid "Search Playlists" +msgstr "" + +#: includes/PostTypes/Playlist.php:54 +msgid "Parent Playlists:" +msgstr "" + +#: includes/PostTypes/Playlist.php:55 +msgid "No playlists found." +msgstr "" + +#: includes/PostTypes/Playlist.php:56 +msgid "No playlists found in Trash." +msgstr "" + +#: includes/PostTypes/Playlist.php:57 +msgctxt "Overrides the \"Featured Image\" phrase" +msgid "Playlist Cover" +msgstr "" + +#: includes/PostTypes/Playlist.php:58 +msgctxt "Overrides the \"Set featured image\" phrase" +msgid "Set playlist cover" +msgstr "" + +#: includes/PostTypes/Playlist.php:59 +msgctxt "Overrides the \"Remove featured image\" phrase" +msgid "Remove playlist cover" +msgstr "" + +#: includes/PostTypes/Playlist.php:60 +msgctxt "Overrides the \"Use as featured image\" phrase" +msgid "Use as playlist cover" +msgstr "" + +#: includes/PostTypes/Playlist.php:61 +msgctxt "The post type archive label" +msgid "Playlist archives" +msgstr "" + +#: includes/PostTypes/Playlist.php:62 +msgctxt "Overrides the \"Insert into post\" phrase" +msgid "Insert into playlist" +msgstr "" + +#: includes/PostTypes/Playlist.php:63 +msgctxt "Overrides the \"Uploaded to this post\" phrase" +msgid "Uploaded to this playlist" +msgstr "" + +#: includes/PostTypes/Playlist.php:64 +msgctxt "Screen reader text" +msgid "Filter playlists list" +msgstr "" + +#: includes/PostTypes/Playlist.php:65 +msgctxt "Screen reader text" +msgid "Playlists list navigation" +msgstr "" + +#: includes/PostTypes/Playlist.php:66 +msgctxt "Screen reader text" +msgid "Playlists list" +msgstr "" + +#: includes/PostTypes/Playlist.php:99 +msgid "Playlist Tracks" +msgstr "" + +#: includes/PostTypes/Playlist.php:108 +msgid "Playlist Settings" +msgstr "" + +#: includes/PostTypes/Playlist.php:117 +msgid "Playlist Stats" +msgstr "" + +#: includes/PostTypes/Playlist.php:160 +msgid "Current Tracks" +msgstr "" + +#: includes/PostTypes/Playlist.php:192 +msgid "Add Tracks" +msgstr "" + +#: includes/PostTypes/Playlist.php:195 +msgid "— Select a track to add —" +msgstr "" + +#: includes/PostTypes/Playlist.php:211 +msgid "Add to Playlist" +msgstr "" + +#: includes/PostTypes/Playlist.php:283 +msgid "Unlisted (link only)" +msgstr "" + +#: includes/PostTypes/Playlist.php:290 +msgid "Collaborative" +msgstr "" + +#: includes/PostTypes/Playlist.php:293 +msgid "Allow others to add tracks." +msgstr "" + +#: includes/PostTypes/Playlist.php:298 +msgid "Federated" +msgstr "" + +#: includes/PostTypes/Playlist.php:301 +msgid "Allow tracks from other FediStream instances." +msgstr "" + +#: includes/PostTypes/Playlist.php:317 +msgid "Tracks:" +msgstr "" + +#: includes/PostTypes/Playlist.php:321 +msgid "Total Duration:" +msgstr "" + +#: includes/PostTypes/Playlist.php:330 +msgid "Stats are automatically updated when saved." +msgstr "" + +#: includes/ActivityPub/ArtistActor.php:300 +msgid "Active Since" +msgstr "" + +#: includes/ActivityPub/AlbumTransformer.php:111 +#, php-format +msgid "By %s" +msgstr "" + +#: includes/ActivityPub/AlbumTransformer.php:115 +#, php-format +msgid "- Released %s" +msgstr "" + +#: includes/ActivityPub/AlbumTransformer.php:119 +#, php-format +msgid "- %d track" +msgid_plural "- %d tracks" +msgstr[0] "" +msgstr[1] "" + +#: includes/ActivityPub/RestApi.php:438 +msgid "Published to ActivityPub" +msgstr "" + +#: includes/ActivityPub/RestApi.php:446 +msgid "Failed to publish" +msgstr "" + +#: includes/WooCommerce/AlbumProduct.php:371 +#: includes/WooCommerce/TrackProduct.php:394 +#, php-format +msgid "%1$s (%2$s)" +msgstr "" + +#: includes/WooCommerce/AlbumProduct.php:419 +#: includes/WooCommerce/TrackProduct.php:442 +msgid "Name Your Price" +msgstr "" + +#: includes/WooCommerce/AlbumProduct.php:431 +#: includes/WooCommerce/TrackProduct.php:454 +#, php-format +msgid "From %s" +msgstr "" + +#: includes/WooCommerce/AlbumProduct.php:435 +#: includes/WooCommerce/TrackProduct.php:458 +#: includes/WooCommerce/Integration.php:246 +msgid "Pay What You Want" +msgstr "" + +#: includes/WooCommerce/AlbumProduct.php:442 +#: includes/WooCommerce/TrackProduct.php:465 +#, php-format +msgid "(Suggested: %s)" +msgstr "" + +#: includes/WooCommerce/AlbumProduct.php:485 +#: includes/WooCommerce/TrackProduct.php:507 +#, php-format +msgid "Please enter at least %s" +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:52 +msgid "You must be logged in to download files." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:75 +#: includes/WooCommerce/StreamingAccess.php:239 +msgid "Invalid track." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:80 +msgid "You have not purchased this track." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:85 +#: includes/WooCommerce/StreamingAccess.php:244 includes/Frontend/Ajax.php:60 +#: includes/Frontend/Ajax.php:154 +msgid "Track not found." +msgstr "Titel nicht gefunden." + +#: includes/WooCommerce/DigitalDelivery.php:91 +#: includes/WooCommerce/StreamingAccess.php:250 includes/Frontend/Ajax.php:73 +msgid "No audio file available." +msgstr "Keine Audiodatei verfügbar." + +#: includes/WooCommerce/DigitalDelivery.php:96 +#: includes/WooCommerce/DigitalDelivery.php:285 +#: includes/WooCommerce/StreamingAccess.php:255 +msgid "File not found." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:120 +msgid "Invalid album." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:125 +msgid "You have not purchased this album." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:130 +msgid "Album not found." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:152 +msgid "No tracks found in this album." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:159 +msgid "Failed to create download package." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:350 +#: includes/WooCommerce/DigitalDelivery.php:354 +msgid "Your FediStream Downloads" +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:351 +msgid "Access your purchased music at:" +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:359 +#, php-format +msgid "Access your purchased music in your %s." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:360 +msgid "account downloads" +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:386 +msgid "FediStream Library" +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:390 +msgid "Title" +msgstr "Titel" + +#: includes/WooCommerce/DigitalDelivery.php:392 +msgid "Purchased" +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:393 +msgid "Download" +msgstr "" + +#: includes/WooCommerce/StreamingAccess.php:373 +msgid "You own this track." +msgstr "" + +#: includes/WooCommerce/StreamingAccess.php:378 +msgid "You own this album." +msgstr "" + +#: includes/WooCommerce/StreamingAccess.php:391 +msgid "Buy Track" +msgstr "" + +#: includes/WooCommerce/StreamingAccess.php:408 +#, php-format +msgid "Buy Full Album: %s" +msgstr "" + +#: includes/WooCommerce/Integration.php:115 +msgid "FediStream Album" +msgstr "" + +#: includes/WooCommerce/Integration.php:116 +msgid "FediStream Track" +msgstr "" + +#: includes/WooCommerce/Integration.php:148 +#: includes/WooCommerce/Integration.php:701 includes/Plugin.php:266 +#: includes/Plugin.php:267 +msgid "FediStream" +msgstr "FediStream" + +#: includes/WooCommerce/Integration.php:155 +msgid "Audio Formats" +msgstr "" + +#: includes/WooCommerce/Integration.php:213 +msgid "Linked Album" +msgstr "" + +#: includes/WooCommerce/Integration.php:215 +msgid "Select an album..." +msgstr "" + +#: includes/WooCommerce/Integration.php:222 +msgid "Select the FediStream album this product represents." +msgstr "" + +#: includes/WooCommerce/Integration.php:228 +msgid "Linked Track" +msgstr "" + +#: includes/WooCommerce/Integration.php:230 +msgid "Select a track..." +msgstr "" + +#: includes/WooCommerce/Integration.php:237 +msgid "Select the FediStream track this product represents." +msgstr "" + +#: includes/WooCommerce/Integration.php:243 +msgid "Pricing Type" +msgstr "" + +#: includes/WooCommerce/Integration.php:245 +msgid "Fixed Price" +msgstr "" + +#: includes/WooCommerce/Integration.php:247 +msgid "Name Your Price (Free+)" +msgstr "" + +#: includes/WooCommerce/Integration.php:257 +msgid "Minimum Price" +msgstr "" + +#: includes/WooCommerce/Integration.php:259 +msgid "Minimum price for Pay What You Want. Leave empty for no minimum." +msgstr "" + +#: includes/WooCommerce/Integration.php:269 +msgid "Suggested Price" +msgstr "" + +#: includes/WooCommerce/Integration.php:271 +msgid "Suggested price shown to customers." +msgstr "" + +#: includes/WooCommerce/Integration.php:285 +msgid "Include Streaming" +msgstr "" + +#: includes/WooCommerce/Integration.php:286 +msgid "Purchase unlocks full-quality streaming access." +msgstr "" + +#: includes/WooCommerce/Integration.php:297 +msgid "Available Formats" +msgstr "" + +#: includes/WooCommerce/Integration.php:319 +msgid "Select which audio formats customers can download after purchase." +msgstr "" + +#: includes/WooCommerce/Integration.php:446 +msgid "Preview" +msgstr "" + +#: includes/WooCommerce/Integration.php:448 +msgid "Play preview" +msgstr "" + +#: includes/WooCommerce/Integration.php:492 +msgid "Tracklist" +msgstr "" + +#: includes/Taxonomies/Genre.php:47 +msgctxt "taxonomy general name" +msgid "Genres" +msgstr "Genres" + +#: includes/Taxonomies/Genre.php:48 +msgctxt "taxonomy singular name" +msgid "Genre" +msgstr "Genre" + +#: includes/Taxonomies/Genre.php:49 +msgid "Search Genres" +msgstr "" + +#: includes/Taxonomies/Genre.php:50 +msgid "Popular Genres" +msgstr "" + +#: includes/Taxonomies/Genre.php:51 +msgid "All Genres" +msgstr "" + +#: includes/Taxonomies/Genre.php:52 +msgid "Parent Genre" +msgstr "" + +#: includes/Taxonomies/Genre.php:53 +msgid "Parent Genre:" +msgstr "" + +#: includes/Taxonomies/Genre.php:54 +msgid "Edit Genre" +msgstr "" + +#: includes/Taxonomies/Genre.php:55 +msgid "View Genre" +msgstr "" + +#: includes/Taxonomies/Genre.php:56 +msgid "Update Genre" +msgstr "" + +#: includes/Taxonomies/Genre.php:57 +msgid "Add New Genre" +msgstr "" + +#: includes/Taxonomies/Genre.php:58 +msgid "New Genre Name" +msgstr "" + +#: includes/Taxonomies/Genre.php:59 +msgid "Separate genres with commas" +msgstr "" + +#: includes/Taxonomies/Genre.php:60 +msgid "Add or remove genres" +msgstr "" + +#: includes/Taxonomies/Genre.php:61 +msgid "Choose from the most used genres" +msgstr "" + +#: includes/Taxonomies/Genre.php:62 +msgid "No genres found." +msgstr "" + +#: includes/Taxonomies/Genre.php:63 +msgid "No genres" +msgstr "" + +#: includes/Taxonomies/Genre.php:64 includes/Plugin.php:324 +#: includes/Plugin.php:325 +msgid "Genres" +msgstr "Genres" + +#: includes/Taxonomies/Genre.php:65 +msgid "Genres list navigation" +msgstr "" + +#: includes/Taxonomies/Genre.php:66 +msgid "Genres list" +msgstr "" + +#: includes/Taxonomies/Genre.php:67 +msgid "← Back to Genres" +msgstr "" + +#: includes/Taxonomies/Mood.php:46 +msgctxt "taxonomy general name" +msgid "Moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:47 +msgctxt "taxonomy singular name" +msgid "Mood" +msgstr "" + +#: includes/Taxonomies/Mood.php:48 +msgid "Search Moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:49 +msgid "Popular Moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:50 +msgid "All Moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:51 +msgid "Edit Mood" +msgstr "" + +#: includes/Taxonomies/Mood.php:52 +msgid "View Mood" +msgstr "" + +#: includes/Taxonomies/Mood.php:53 +msgid "Update Mood" +msgstr "" + +#: includes/Taxonomies/Mood.php:54 +msgid "Add New Mood" +msgstr "" + +#: includes/Taxonomies/Mood.php:55 +msgid "New Mood Name" +msgstr "" + +#: includes/Taxonomies/Mood.php:56 +msgid "Separate moods with commas" +msgstr "" + +#: includes/Taxonomies/Mood.php:57 +msgid "Add or remove moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:58 +msgid "Choose from the most used moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:59 +msgid "No moods found." +msgstr "" + +#: includes/Taxonomies/Mood.php:60 +msgid "No moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:61 +msgid "Moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:62 +msgid "Moods list navigation" +msgstr "" + +#: includes/Taxonomies/Mood.php:63 +msgid "Moods list" +msgstr "" + +#: includes/Taxonomies/Mood.php:64 +msgid "← Back to Moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:98 +msgid "Energetic" +msgstr "" + +#: includes/Taxonomies/Mood.php:99 +msgid "Calm" +msgstr "" + +#: includes/Taxonomies/Mood.php:100 +msgid "Uplifting" +msgstr "" + +#: includes/Taxonomies/Mood.php:101 +msgid "Melancholic" +msgstr "" + +#: includes/Taxonomies/Mood.php:102 +msgid "Aggressive" +msgstr "" + +#: includes/Taxonomies/Mood.php:103 +msgid "Romantic" +msgstr "" + +#: includes/Taxonomies/Mood.php:104 +msgid "Happy" +msgstr "" + +#: includes/Taxonomies/Mood.php:105 +msgid "Sad" +msgstr "" + +#: includes/Taxonomies/Mood.php:106 +msgid "Relaxing" +msgstr "" + +#: includes/Taxonomies/Mood.php:107 +msgid "Intense" +msgstr "" + +#: includes/Taxonomies/Mood.php:108 +msgid "Dreamy" +msgstr "" + +#: includes/Taxonomies/Mood.php:109 +msgid "Dark" +msgstr "" + +#: includes/Taxonomies/Mood.php:110 +msgid "Groovy" +msgstr "" + +#: includes/Taxonomies/Mood.php:111 +msgid "Epic" +msgstr "" + +#: includes/Taxonomies/Mood.php:112 +msgid "Peaceful" +msgstr "" + +#: includes/Taxonomies/Mood.php:113 +msgid "Motivational" +msgstr "" + +#: includes/Taxonomies/Mood.php:114 +msgid "Nostalgic" +msgstr "" + +#: includes/Taxonomies/Mood.php:115 +msgid "Playful" +msgstr "" + +#: includes/Taxonomies/Mood.php:116 +msgid "Sensual" +msgstr "" + +#: includes/Taxonomies/Mood.php:117 +msgid "Suspenseful" +msgstr "" + +#: includes/Taxonomies/License.php:46 +msgctxt "taxonomy general name" +msgid "Licenses" +msgstr "" + +#: includes/Taxonomies/License.php:47 +msgctxt "taxonomy singular name" +msgid "License" +msgstr "Lizenz" + +#: includes/Taxonomies/License.php:48 +msgid "Search Licenses" +msgstr "" + +#: includes/Taxonomies/License.php:49 +msgid "Popular Licenses" +msgstr "" + +#: includes/Taxonomies/License.php:50 +msgid "All Licenses" +msgstr "" + +#: includes/Taxonomies/License.php:51 +msgid "Parent License" +msgstr "" + +#: includes/Taxonomies/License.php:52 +msgid "Parent License:" +msgstr "" + +#: includes/Taxonomies/License.php:53 +msgid "Edit License" +msgstr "" + +#: includes/Taxonomies/License.php:54 +msgid "View License" +msgstr "" + +#: includes/Taxonomies/License.php:55 +msgid "Update License" +msgstr "" + +#: includes/Taxonomies/License.php:56 +msgid "Add New License" +msgstr "" + +#: includes/Taxonomies/License.php:57 +msgid "New License Name" +msgstr "" + +#: includes/Taxonomies/License.php:58 +msgid "Separate licenses with commas" +msgstr "" + +#: includes/Taxonomies/License.php:59 +msgid "Add or remove licenses" +msgstr "" + +#: includes/Taxonomies/License.php:60 +msgid "Choose from the most used licenses" +msgstr "" + +#: includes/Taxonomies/License.php:61 +msgid "No licenses found." +msgstr "" + +#: includes/Taxonomies/License.php:62 +msgid "No licenses" +msgstr "" + +#: includes/Taxonomies/License.php:63 +msgid "Licenses" +msgstr "" + +#: includes/Taxonomies/License.php:64 +msgid "Licenses list navigation" +msgstr "" + +#: includes/Taxonomies/License.php:65 +msgid "Licenses list" +msgstr "" + +#: includes/Taxonomies/License.php:66 +msgid "← Back to Licenses" +msgstr "" + +#: includes/Taxonomies/License.php:101 +msgid "Standard copyright. All rights reserved by the creator." +msgstr "" + +#: includes/Taxonomies/License.php:105 +msgid "Creative Commons licenses for sharing and reuse." +msgstr "" + +#: includes/Taxonomies/License.php:107 +msgid "Public Domain Dedication - No rights reserved" +msgstr "" + +#: includes/Taxonomies/License.php:108 +msgid "Attribution - Credit must be given" +msgstr "" + +#: includes/Taxonomies/License.php:109 +msgid "Attribution-ShareAlike - Credit and share under same terms" +msgstr "" + +#: includes/Taxonomies/License.php:110 +msgid "Attribution-NoDerivs - Credit, no modifications" +msgstr "" + +#: includes/Taxonomies/License.php:111 +msgid "Attribution-NonCommercial - Credit, non-commercial only" +msgstr "" + +#: includes/Taxonomies/License.php:112 +msgid "Attribution-NonCommercial-ShareAlike" +msgstr "" + +#: includes/Taxonomies/License.php:113 +msgid "Attribution-NonCommercial-NoDerivs" +msgstr "" + +#: includes/Taxonomies/License.php:117 +msgid "Works in the public domain with no copyright restrictions." +msgstr "" + +#: includes/Roles/Capabilities.php:224 +msgid "FediStream Artist" +msgstr "" + +#: includes/Roles/Capabilities.php:231 +msgid "FediStream Label" +msgstr "" + +#: includes/Frontend/TemplateLoader.php:486 +msgid "« Previous" +msgstr "" + +#: includes/Frontend/TemplateLoader.php:487 +msgid "Next »" +msgstr "" + +#: includes/Frontend/TemplateLoader.php:509 includes/User/LibraryPage.php:112 +#: includes/Plugin.php:315 includes/Plugin.php:316 includes/Plugin.php:377 +msgid "Playlists" +msgstr "Wiedergabelisten" + +#: includes/Frontend/template-wrapper.php:40 +msgid "Genre" +msgstr "Genre" + +#: includes/Frontend/template-wrapper.php:43 +msgid "Mood" +msgstr "" + +#: includes/Frontend/template-wrapper.php:61 +msgid "Template Error:" +msgstr "" + +#: includes/Frontend/Shortcodes.php:55 +msgid "This content requires a valid FediStream license." +msgstr "Dieser Inhalt erfordert eine gültige FediStream-Lizenz." + +#: includes/Frontend/Shortcodes.php:280 +msgid "Latest Releases" +msgstr "Neueste Veröffentlichungen" + +#: includes/Frontend/Shortcodes.php:347 +#: includes/Frontend/Widgets/PopularTracksWidget.php:45 +#: includes/Frontend/Widgets/PopularTracksWidget.php:100 +msgid "Popular Tracks" +msgstr "Beliebte Titel" + +#: includes/Frontend/Widgets/RecentReleasesWidget.php:29 +msgid "FediStream: Recent Releases" +msgstr "" + +#: includes/Frontend/Widgets/RecentReleasesWidget.php:31 +msgid "Display recent album releases." +msgstr "" + +#: includes/Frontend/Widgets/RecentReleasesWidget.php:45 +#: includes/Frontend/Widgets/RecentReleasesWidget.php:108 +msgid "Recent Releases" +msgstr "" + +#: includes/Frontend/Widgets/RecentReleasesWidget.php:113 +#: includes/Frontend/Widgets/PopularTracksWidget.php:104 +#: includes/Frontend/Widgets/FeaturedArtistWidget.php:125 +#: includes/Frontend/Widgets/NowPlayingWidget.php:83 +msgid "Title:" +msgstr "" + +#: includes/Frontend/Widgets/RecentReleasesWidget.php:117 +msgid "Number of releases:" +msgstr "" + +#: includes/Frontend/Widgets/RecentReleasesWidget.php:121 +msgid "Release type:" +msgstr "" + +#: includes/Frontend/Widgets/RecentReleasesWidget.php:123 +msgid "All types" +msgstr "" + +#: includes/Frontend/Widgets/PopularTracksWidget.php:29 +msgid "FediStream: Popular Tracks" +msgstr "" + +#: includes/Frontend/Widgets/PopularTracksWidget.php:31 +msgid "Display popular tracks by play count." +msgstr "" + +#: includes/Frontend/Widgets/PopularTracksWidget.php:108 +msgid "Number of tracks:" +msgstr "" + +#: includes/Frontend/Widgets/FeaturedArtistWidget.php:29 +msgid "FediStream: Featured Artist" +msgstr "" + +#: includes/Frontend/Widgets/FeaturedArtistWidget.php:31 +msgid "Display a featured artist." +msgstr "" + +#: includes/Frontend/Widgets/FeaturedArtistWidget.php:45 +#: includes/Frontend/Widgets/FeaturedArtistWidget.php:109 +msgid "Featured Artist" +msgstr "" + +#: includes/Frontend/Widgets/FeaturedArtistWidget.php:131 +msgid "Show random artist" +msgstr "" + +#: includes/Frontend/Widgets/FeaturedArtistWidget.php:135 +msgid "Or select specific artist:" +msgstr "" + +#: includes/Frontend/Widgets/FeaturedArtistWidget.php:137 +msgid "-- Select Artist --" +msgstr "" + +#: includes/Frontend/Widgets/NowPlayingWidget.php:28 +msgid "FediStream: Now Playing" +msgstr "" + +#: includes/Frontend/Widgets/NowPlayingWidget.php:30 +msgid "Display the currently playing track." +msgstr "" + +#: includes/Frontend/Widgets/NowPlayingWidget.php:44 +#: includes/Frontend/Widgets/NowPlayingWidget.php:79 +msgid "Now Playing" +msgstr "" + +#: includes/Frontend/Widgets/NowPlayingWidget.php:89 +msgid "Show player controls" +msgstr "" + +#: includes/Frontend/Widgets/NowPlayingWidget.php:93 +msgid "" +"This widget shows information about the currently playing track and updates " +"automatically via JavaScript." +msgstr "" + +#: includes/Frontend/Ajax.php:43 includes/Frontend/Ajax.php:137 +msgid "This feature requires a valid license." +msgstr "Diese Funktion erfordert eine gültige Lizenz." + +#: includes/Frontend/Ajax.php:48 includes/Frontend/Ajax.php:142 +msgid "Invalid nonce." +msgstr "Ungültiger Sicherheitstoken." + +#: includes/Frontend/Ajax.php:54 includes/Frontend/Ajax.php:148 +msgid "Invalid track ID." +msgstr "Ungültige Titel-ID." + +#: includes/Frontend/Ajax.php:65 +msgid "Track not available." +msgstr "Titel nicht verfügbar." + +#: includes/Frontend/Ajax.php:179 +msgid "Play recorded." +msgstr "Wiedergabe aufgezeichnet." + +#: includes/User/Library.php:49 includes/User/Library.php:94 +#: includes/User/Library.php:138 includes/User/Library.php:160 +#: includes/User/Library.php:181 includes/User/Library.php:202 +msgid "You must be logged in." +msgstr "" + +#: includes/User/Library.php:56 +msgid "Invalid request." +msgstr "" + +#: includes/User/Library.php:76 +msgid "Added to your library." +msgstr "" + +#: includes/User/Library.php:77 +msgid "Removed from your library." +msgstr "" + +#: includes/User/Library.php:81 +msgid "Failed to update library." +msgstr "" + +#: includes/User/Library.php:100 +msgid "Invalid artist." +msgstr "" + +#: includes/User/Library.php:120 +msgid "You are now following this artist." +msgstr "" + +#: includes/User/Library.php:121 +msgid "You unfollowed this artist." +msgstr "" + +#: includes/User/Library.php:125 +msgid "Failed to update follow status." +msgstr "" + +#: includes/User/Library.php:209 includes/User/LibraryPage.php:58 +msgid "History cleared." +msgstr "" + +#: includes/User/Library.php:211 +msgid "Failed to clear history." +msgstr "" + +#: includes/User/Library.php:707 includes/User/LibraryPage.php:216 +msgid "Remove from library" +msgstr "" + +#: includes/User/Library.php:707 +msgid "Add to library" +msgstr "" + +#: includes/User/Library.php:736 +msgid "Following" +msgstr "" + +#: includes/User/Library.php:736 +msgid "Follow" +msgstr "" + +#: includes/User/LibraryPage.php:53 +msgid "Loading..." +msgstr "" + +#: includes/User/LibraryPage.php:54 +msgid "No favorites yet." +msgstr "" + +#: includes/User/LibraryPage.php:55 +msgid "Not following any artists yet." +msgstr "" + +#: includes/User/LibraryPage.php:56 +msgid "No listening history." +msgstr "" + +#: includes/User/LibraryPage.php:57 +msgid "Are you sure you want to clear your listening history?" +msgstr "" + +#: includes/User/LibraryPage.php:59 +msgid "An error occurred. Please try again." +msgstr "" + +#: includes/User/LibraryPage.php:95 +msgid "Favorites" +msgstr "" + +#: includes/User/LibraryPage.php:103 +msgid "History" +msgstr "" + +#: includes/User/LibraryPage.php:109 +msgid "All" +msgstr "" + +#: includes/User/LibraryPage.php:134 +msgid "Clear History" +msgstr "" + +#: includes/User/LibraryPage.php:161 +msgid "Please log in to view your library." +msgstr "" + +#: includes/User/LibraryPage.php:163 +msgid "Log In" +msgstr "" + +#: includes/User/LibraryPage.php:208 +#, php-format +msgid "%d track" +msgid_plural "%d tracks" +msgstr[0] "" +msgstr[1] "" + +#: includes/User/LibraryPage.php:253 includes/User/LibraryPage.php:255 +msgid "Unfollow" +msgstr "" + +#: includes/User/LibraryPage.php:296 +#, php-format +msgid "Played %s" +msgstr "" + +#: includes/User/LibraryPage.php:297 includes/Plugin.php:581 +msgid "ago" +msgstr "her" + +#: includes/User/Notifications.php:84 +msgid "No notifications" +msgstr "" + +#: includes/User/Notifications.php:85 +msgid "Mark all as read" +msgstr "" + +#: includes/User/Notifications.php:86 +msgid "View all notifications" +msgstr "" + +#: includes/User/Notifications.php:87 +msgid "Just now" +msgstr "" + +#: includes/User/Notifications.php:88 +msgid "An error occurred." +msgstr "" + +#: includes/User/Notifications.php:309 includes/User/Notifications.php:337 +#: includes/User/Notifications.php:369 includes/User/Notifications.php:391 +msgid "Not logged in." +msgstr "" + +#: includes/User/Notifications.php:343 includes/User/Notifications.php:397 +msgid "Invalid notification." +msgstr "" + +#: includes/User/Notifications.php:356 +msgid "Failed to update notification." +msgstr "" + +#: includes/User/Notifications.php:378 +msgid "Failed to update notifications." +msgstr "" + +#: includes/User/Notifications.php:410 +msgid "Failed to delete notification." +msgstr "" + +#: includes/User/Notifications.php:445 +#, php-format +msgid "New release from %s" +msgstr "" + +#: includes/User/Notifications.php:450 +#, php-format +msgid "%1$s released a new album: %2$s" +msgstr "" + +#: includes/User/Notifications.php:509 +#, php-format +msgid "New track from %s" +msgstr "" + +#: includes/User/Notifications.php:514 +#, php-format +msgid "%1$s released a new track: %2$s" +msgstr "" + +#: includes/User/Notifications.php:555 +msgid "New follower" +msgstr "" + +#: includes/User/Notifications.php:558 +#, php-format +msgid "%s started following you" +msgstr "" + +#: includes/User/Notifications.php:586 includes/User/Notifications.php:626 +msgid "Someone" +msgstr "" + +#: includes/User/Notifications.php:591 +msgid "New like from Fediverse" +msgstr "" + +#: includes/User/Notifications.php:594 +#, php-format +msgid "%1$s liked your %2$s" +msgstr "" + +#: includes/User/Notifications.php:631 +msgid "New boost from Fediverse" +msgstr "" + +#: includes/User/Notifications.php:634 +#, php-format +msgid "%1$s boosted your %2$s" +msgstr "" + +#: includes/User/Notifications.php:678 +#, php-format +msgid "[%1$s] %2$s" +msgstr "" + +#: includes/User/Notifications.php:720 +msgid "View Details" +msgstr "" + +#: includes/User/Notifications.php:726 +#, php-format +msgid "This email was sent by %s." +msgstr "" + +#: includes/Plugin.php:221 includes/Plugin.php:333 includes/Plugin.php:334 +msgid "Settings" +msgstr "Einstellungen" + +#: includes/Plugin.php:227 includes/Plugin.php:278 includes/Plugin.php:279 +msgid "Dashboard" +msgstr "Dashboard" + +#: includes/Plugin.php:354 +msgid "FediStream Dashboard" +msgstr "FediStream Dashboard" + +#: includes/Plugin.php:361 +msgid "Manage Artists" +msgstr "Künstler verwalten" + +#: includes/Plugin.php:367 +msgid "Manage Albums" +msgstr "Alben verwalten" + +#: includes/Plugin.php:373 +msgid "Manage Tracks" +msgstr "Titel verwalten" + +#: includes/Plugin.php:379 +msgid "Manage Playlists" +msgstr "Wiedergabelisten verwalten" + +#: includes/Plugin.php:384 +msgid "Quick Actions" +msgstr "Schnellaktionen" + +#: includes/Plugin.php:386 +msgid "Add Artist" +msgstr "Künstler hinzufügen" + +#: includes/Plugin.php:387 +msgid "Add Album" +msgstr "Album hinzufügen" + +#: includes/Plugin.php:388 +msgid "Add Track" +msgstr "Titel hinzufügen" + +#: includes/Plugin.php:389 +msgid "Add Playlist" +msgstr "Wiedergabeliste hinzufügen" + +#: includes/Plugin.php:394 +msgid "Getting Started" +msgstr "Erste Schritte" + +#: includes/Plugin.php:396 +msgid "Add your artists or bands." +msgstr "Fügen Sie Ihre Künstler oder Bands hinzu." + +#: includes/Plugin.php:397 +msgid "Create albums and assign them to artists." +msgstr "Erstellen Sie Alben und weisen Sie sie Künstlern zu." + +#: includes/Plugin.php:398 +msgid "Upload tracks and add them to albums." +msgstr "Laden Sie Titel hoch und fügen Sie sie zu Alben hinzu." + +#: includes/Plugin.php:399 +msgid "Create playlists to curate your music." +msgstr "Erstellen Sie Wiedergabelisten, um Ihre Musik zu kuratieren." + +#: includes/Plugin.php:400 +msgid "Share your music via ActivityPub to the Fediverse!" +msgstr "Teilen Sie Ihre Musik über ActivityPub im Fediverse!" + +#: includes/Plugin.php:439 +msgid "License" +msgstr "Lizenz" + +#: includes/Plugin.php:440 +msgid "Default Settings" +msgstr "Standardeinstellungen" + +#: includes/Plugin.php:441 +msgid "Integrations" +msgstr "Integrationen" + +#: includes/Plugin.php:445 +msgid "FediStream Settings" +msgstr "FediStream Einstellungen" + +#: includes/Plugin.php:493 +msgid "License settings saved." +msgstr "Lizenzeinstellungen gespeichert." + +#: includes/Plugin.php:499 +msgid "Settings saved." +msgstr "Einstellungen gespeichert." + +#: includes/Plugin.php:505 +msgid "Integration settings saved." +msgstr "Integrationseinstellungen gespeichert." + +#: includes/Plugin.php:532 +msgid "License is active and valid." +msgstr "Lizenz ist aktiv und gültig." + +#: includes/Plugin.php:533 +msgid "License is invalid." +msgstr "Lizenz ist ungültig." + +#: includes/Plugin.php:534 +msgid "License has expired." +msgstr "Lizenz ist abgelaufen." + +#: includes/Plugin.php:535 +msgid "License has been revoked." +msgstr "Lizenz wurde widerrufen." + +#: includes/Plugin.php:536 +msgid "License is inactive. Please activate it." +msgstr "Lizenz ist inaktiv. Bitte aktivieren Sie sie." + +#: includes/Plugin.php:537 +msgid "License has not been validated yet." +msgstr "Lizenz wurde noch nicht validiert." + +#: includes/Plugin.php:538 +msgid "License server is not configured." +msgstr "Lizenzserver ist nicht konfiguriert." + +#: includes/Plugin.php:552 +msgid "Unknown status." +msgstr "Unbekannter Status." + +#: includes/Plugin.php:565 +#, php-format +msgid "Expires: %s" +msgstr "" + +#: includes/Plugin.php:572 +msgid "Lifetime license" +msgstr "Lebenslange Lizenz" + +#: includes/Plugin.php:580 +#, php-format +msgid "Last checked: %s" +msgstr "" + +#: includes/Plugin.php:595 +msgid "License Server URL" +msgstr "Lizenzserver URL" + +#: includes/Plugin.php:601 +msgid "The URL of your license server." +msgstr "Die URL Ihres Lizenzservers." + +#: includes/Plugin.php:606 +msgid "License Key" +msgstr "Lizenzschlüssel" + +#: includes/Plugin.php:612 +msgid "Your license key from your purchase." +msgstr "Ihr Lizenzschlüssel von Ihrem Kauf." + +#: includes/Plugin.php:617 +msgid "Server Secret" +msgstr "Server-Geheimnis" + +#: includes/Plugin.php:622 +msgid "" +"64-character verification secret from your license account. Leave empty to " +"keep existing." +msgstr "" + +#: includes/Plugin.php:628 +msgid "Save License Settings" +msgstr "Lizenzeinstellungen speichern" + +#: includes/Plugin.php:631 +msgid "Validate License" +msgstr "Lizenz validieren" + +#: includes/Plugin.php:635 +msgid "Activate License" +msgstr "Lizenz aktivieren" + +#: includes/Plugin.php:664 +msgid "Max Upload Size" +msgstr "Maximale Upload-Grösse" + +#: includes/Plugin.php:668 +msgid "Maximum file size for audio uploads." +msgstr "Maximale Dateigrösse für Audio-Uploads." + +#: includes/Plugin.php:673 +msgid "Default License" +msgstr "Standardlizenz" + +#: includes/Plugin.php:677 +msgid "All Rights Reserved" +msgstr "Alle Rechte vorbehalten" + +#: includes/Plugin.php:684 +msgid "Default license for new uploads." +msgstr "Standardlizenz für neue Uploads." + +#: includes/Plugin.php:708 +msgid "ActivityPub Integration" +msgstr "ActivityPub-Integration" + +#: includes/Plugin.php:712 +msgid "Enable ActivityPub features" +msgstr "ActivityPub-Funktionen aktivieren" + +#: includes/Plugin.php:714 +msgid "Publish releases to the Fediverse and allow followers." +msgstr "Veröffentlichungen im Fediverse publizieren und Follower erlauben." + +#: includes/Plugin.php:718 +msgid "The ActivityPub plugin is recommended for full Fediverse integration." +msgstr "Das ActivityPub-Plugin wird für die vollständige Fediverse-Integration empfohlen." + +#: includes/Plugin.php:724 +msgid "WooCommerce Integration" +msgstr "WooCommerce-Integration" + +#: includes/Plugin.php:728 +msgid "Enable WooCommerce features" +msgstr "WooCommerce-Funktionen aktivieren" + +#: includes/Plugin.php:733 +msgid "WooCommerce is not installed or active." +msgstr "WooCommerce ist nicht installiert oder aktiv." + +#: includes/Plugin.php:736 +msgid "Sell albums and tracks through WooCommerce." +msgstr "Alben und Titel über WooCommerce verkaufen." + +#: includes/License/Manager.php:144 includes/License/Manager.php:244 +#: includes/License/Manager.php:325 +msgid "License server configuration is incomplete." +msgstr "Lizenzserver-Konfiguration ist unvollständig." + +#: includes/License/Manager.php:152 includes/License/Manager.php:252 +msgid "No license key provided." +msgstr "Kein Lizenzschlüssel angegeben." + +#: includes/License/Manager.php:170 +msgid "License validated successfully." +msgstr "Lizenz erfolgreich validiert." + +#: includes/License/Manager.php:182 includes/License/Manager.php:278 +msgid "License key not found. Please check your license key." +msgstr "Lizenzschlüssel nicht gefunden. Bitte überprüfen Sie Ihren Lizenzschlüssel." + +#: includes/License/Manager.php:188 includes/License/Manager.php:283 +msgid "Your license has expired. Please renew to continue." +msgstr "Ihre Lizenz ist abgelaufen. Bitte erneuern Sie sie, um fortzufahren." + +#: includes/License/Manager.php:194 +msgid "Your license has been revoked." +msgstr "Ihre Lizenz wurde widerrufen." + +#: includes/License/Manager.php:200 +msgid "License is inactive. Please activate it first." +msgstr "" + +#: includes/License/Manager.php:206 +msgid "This license is not activated for this domain." +msgstr "Diese Lizenz ist nicht für diese Domain aktiviert." + +#: includes/License/Manager.php:211 includes/License/Manager.php:288 +#: includes/License/Manager.php:395 +msgid "License verification failed. Please check your server secret." +msgstr "Lizenzverifizierung fehlgeschlagen. Bitte überprüfen Sie Ihr Server-Geheimnis." + +#: includes/License/Manager.php:216 +msgid "Too many requests. Please try again later." +msgstr "Zu viele Anfragen. Bitte versuchen Sie es später erneut." + +#: includes/License/Manager.php:223 +#, php-format +msgid "License validation failed: %s" +msgstr "" + +#: includes/License/Manager.php:230 +msgid "Unable to verify license. Please try again later." +msgstr "Lizenz konnte nicht verifiziert werden. Bitte versuchen Sie es später erneut." + +#: includes/License/Manager.php:273 +msgid "" +"Maximum number of activations reached. Please deactivate another site first." +msgstr "" + +#: includes/License/Manager.php:295 +#, php-format +msgid "License activation failed: %s" +msgstr "" + +#: includes/License/Manager.php:302 +msgid "Unable to activate license. Please try again later." +msgstr "Lizenz konnte nicht aktiviert werden. Bitte versuchen Sie es später erneut." + +#: includes/License/Manager.php:336 +msgid "No license key configured." +msgstr "Kein Lizenzschlüssel konfiguriert." + +#: includes/License/Manager.php:369 includes/License/Manager.php:379 +msgid "License is active." +msgstr "Lizenz ist aktiv." + +#: includes/License/Manager.php:370 includes/License/Manager.php:380 +msgid "License is not active." +msgstr "Lizenz ist nicht aktiv." + +#: includes/License/Manager.php:387 +msgid "License key not found." +msgstr "Lizenzschlüssel nicht gefunden." + +#: includes/License/Manager.php:403 +msgid "Unable to check license status." +msgstr "Lizenzstatus konnte nicht überprüft werden." + +#: includes/License/Manager.php:572 includes/License/Manager.php:595 +#: includes/License/Manager.php:618 includes/License/Manager.php:640 +msgid "You do not have permission to perform this action." +msgstr "Sie haben keine Berechtigung, diese Aktion auszuführen." + +#: includes/License/Manager.php:626 +msgid "License deactivated." +msgstr "Lizenz deaktiviert." + +#: wp-fedistream.php:112 +#, php-format +msgid "" +"WP FediStream requires PHP version %1$s or higher. You are running PHP %2$s." +msgstr "" + +#: wp-fedistream.php:127 +#, php-format +msgid "" +"WP FediStream requires WordPress version %1$s or higher. You are running " +"WordPress %2$s." +msgstr "" + +#: wp-fedistream.php:140 +msgid "" +"WP FediStream requires Composer dependencies to be installed. Please run " +"\"composer install\" in the plugin directory." +msgstr "" + +#: wp-fedistream.php:156 +#, php-format +msgid "WP FediStream requires PHP version %s or higher." +msgstr "" diff --git a/languages/wp-fedistream.pot b/languages/wp-fedistream.pot index 7b1b98c..e57925e 100644 --- a/languages/wp-fedistream.pot +++ b/languages/wp-fedistream.pot @@ -1,31 +1,2287 @@ -# Copyright (C) 2025 Marco Graetsch -# This file is distributed under the same license as the WP FediStream plugin. +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the WP FediStream package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy msgid "" msgstr "" -"Project-Id-Version: WP FediStream 0.0.1\n" -"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/magdev/wp-fedistream/issues\n" -"POT-Creation-Date: 2025-01-28T00:00:00+00:00\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2025-MO-DA HO:MI+ZONE\n" +"Project-Id-Version: WP FediStream 0.3.0\n" +"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/magdev/wp-fedistream/" +"issues\n" +"POT-Creation-Date: 2026-01-29 11:53+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" -#: wp-fedistream.php:93 -msgid "WP FediStream requires PHP version %1$s or higher. You are running PHP %2$s." +#: includes/Admin/ListColumns.php:66 includes/Admin/ListColumns.php:148 +#: includes/WooCommerce/DigitalDelivery.php:391 +msgid "Type" msgstr "" -#: wp-fedistream.php:105 -msgid "WP FediStream requires WordPress version %1$s or higher. You are running WordPress %2$s." +#: includes/Admin/ListColumns.php:67 includes/Frontend/TemplateLoader.php:503 +#: includes/User/LibraryPage.php:111 includes/Plugin.php:297 +#: includes/Plugin.php:298 includes/Plugin.php:365 +msgid "Albums" msgstr "" -#: wp-fedistream.php:114 -msgid "WP FediStream requires Composer dependencies to be installed. Please run \"composer install\" in the plugin directory." +#: includes/Admin/ListColumns.php:68 includes/Admin/ListColumns.php:149 +#: includes/Admin/ListColumns.php:361 includes/Frontend/TemplateLoader.php:506 +#: includes/User/LibraryPage.php:110 includes/Plugin.php:306 +#: includes/Plugin.php:307 includes/Plugin.php:371 +msgid "Tracks" +msgstr "" + +#: includes/Admin/ListColumns.php:74 includes/Admin/ListColumns.php:155 +#: includes/Admin/ListColumns.php:256 includes/Admin/ListColumns.php:368 +msgid "Date" +msgstr "" + +#: includes/Admin/ListColumns.php:100 includes/Admin/ListColumns.php:105 +msgid "Solo" +msgstr "" + +#: includes/Admin/ListColumns.php:101 includes/PostTypes/Artist.php:147 +#: includes/Frontend/TemplateLoader.php:242 includes/User/LibraryPage.php:249 +msgid "Band" +msgstr "" + +#: includes/Admin/ListColumns.php:102 includes/PostTypes/Artist.php:148 +#: includes/Frontend/TemplateLoader.php:243 +msgid "Duo" +msgstr "" + +#: includes/Admin/ListColumns.php:103 includes/PostTypes/Artist.php:149 +#: includes/Frontend/TemplateLoader.php:244 +msgid "Collective" +msgstr "" + +#: includes/Admin/ListColumns.php:147 includes/PostTypes/Album.php:108 +#: includes/User/LibraryPage.php:249 +msgid "Artist" +msgstr "" + +#: includes/Admin/ListColumns.php:150 includes/PostTypes/Album.php:157 +msgid "Release Date" +msgstr "" + +#: includes/Admin/ListColumns.php:186 includes/Admin/ListColumns.php:298 +msgid "No artist" +msgstr "" + +#: includes/Admin/ListColumns.php:193 includes/Admin/ListColumns.php:200 +#: includes/Admin/ListColumns.php:249 includes/PostTypes/Album.php:146 +#: includes/PostTypes/Track.php:125 includes/Frontend/TemplateLoader.php:287 +#: includes/Frontend/Widgets/RecentReleasesWidget.php:124 +msgid "Album" +msgstr "" + +#: includes/Admin/ListColumns.php:194 includes/PostTypes/Album.php:147 +#: includes/Frontend/TemplateLoader.php:288 +#: includes/Frontend/Widgets/RecentReleasesWidget.php:125 +msgid "EP" +msgstr "" + +#: includes/Admin/ListColumns.php:195 includes/Admin/ListColumns.php:310 +#: includes/PostTypes/Album.php:148 includes/Frontend/TemplateLoader.php:289 +#: includes/Frontend/Widgets/RecentReleasesWidget.php:126 +msgid "Single" +msgstr "" + +#: includes/Admin/ListColumns.php:196 includes/PostTypes/Album.php:149 +#: includes/Frontend/TemplateLoader.php:290 +#: includes/Frontend/Widgets/RecentReleasesWidget.php:127 +msgid "Compilation" +msgstr "" + +#: includes/Admin/ListColumns.php:197 +msgid "Live" +msgstr "" + +#: includes/Admin/ListColumns.php:198 +msgid "Remix" +msgstr "" + +#: includes/Admin/ListColumns.php:248 includes/PostTypes/Track.php:134 +#: includes/Frontend/TemplateLoader.php:500 +#: includes/Frontend/Shortcodes.php:414 includes/User/LibraryPage.php:99 +#: includes/Plugin.php:288 includes/Plugin.php:289 includes/Plugin.php:359 +msgid "Artists" +msgstr "" + +#: includes/Admin/ListColumns.php:250 includes/Admin/ListColumns.php:362 +msgid "Duration" +msgstr "" + +#: includes/Admin/ListColumns.php:251 +msgid "Plays" +msgstr "" + +#: includes/Admin/ListColumns.php:363 includes/PostTypes/Playlist.php:280 +msgid "Visibility" +msgstr "" + +#: includes/Admin/ListColumns.php:416 includes/Admin/ListColumns.php:426 +#: includes/PostTypes/Playlist.php:282 +msgid "Public" +msgstr "" + +#: includes/Admin/ListColumns.php:417 +msgid "Unlisted" +msgstr "" + +#: includes/Admin/ListColumns.php:418 includes/PostTypes/Playlist.php:284 +msgid "Private" +msgstr "" + +#: includes/PostTypes/Artist.php:43 +msgctxt "Post type general name" +msgid "Artists" +msgstr "" + +#: includes/PostTypes/Artist.php:44 +msgctxt "Post type singular name" +msgid "Artist" +msgstr "" + +#: includes/PostTypes/Artist.php:45 +msgctxt "Admin Menu text" +msgid "Artists" +msgstr "" + +#: includes/PostTypes/Artist.php:46 +msgctxt "Add New on Toolbar" +msgid "Artist" +msgstr "" + +#: includes/PostTypes/Artist.php:47 includes/PostTypes/Album.php:47 +#: includes/PostTypes/Track.php:55 includes/PostTypes/Playlist.php:47 +msgid "Add New" +msgstr "" + +#: includes/PostTypes/Artist.php:48 +msgid "Add New Artist" +msgstr "" + +#: includes/PostTypes/Artist.php:49 +msgid "New Artist" +msgstr "" + +#: includes/PostTypes/Artist.php:50 +msgid "Edit Artist" +msgstr "" + +#: includes/PostTypes/Artist.php:51 +msgid "View Artist" +msgstr "" + +#: includes/PostTypes/Artist.php:52 +msgid "All Artists" +msgstr "" + +#: includes/PostTypes/Artist.php:53 +msgid "Search Artists" +msgstr "" + +#: includes/PostTypes/Artist.php:54 +msgid "Parent Artists:" +msgstr "" + +#: includes/PostTypes/Artist.php:55 +msgid "No artists found." +msgstr "" + +#: includes/PostTypes/Artist.php:56 +msgid "No artists found in Trash." +msgstr "" + +#: includes/PostTypes/Artist.php:57 +msgctxt "Overrides the \"Featured Image\" phrase" +msgid "Artist Photo" +msgstr "" + +#: includes/PostTypes/Artist.php:58 +msgctxt "Overrides the \"Set featured image\" phrase" +msgid "Set artist photo" +msgstr "" + +#: includes/PostTypes/Artist.php:59 +msgctxt "Overrides the \"Remove featured image\" phrase" +msgid "Remove artist photo" +msgstr "" + +#: includes/PostTypes/Artist.php:60 +msgctxt "Overrides the \"Use as featured image\" phrase" +msgid "Use as artist photo" +msgstr "" + +#: includes/PostTypes/Artist.php:61 +msgctxt "The post type archive label" +msgid "Artist archives" +msgstr "" + +#: includes/PostTypes/Artist.php:62 +msgctxt "Overrides the \"Insert into post\" phrase" +msgid "Insert into artist" +msgstr "" + +#: includes/PostTypes/Artist.php:63 +msgctxt "Overrides the \"Uploaded to this post\" phrase" +msgid "Uploaded to this artist" +msgstr "" + +#: includes/PostTypes/Artist.php:64 +msgctxt "Screen reader text" +msgid "Filter artists list" +msgstr "" + +#: includes/PostTypes/Artist.php:65 +msgctxt "Screen reader text" +msgid "Artists list navigation" +msgstr "" + +#: includes/PostTypes/Artist.php:66 +msgctxt "Screen reader text" +msgid "Artists list" +msgstr "" + +#: includes/PostTypes/Artist.php:99 +msgid "Artist Information" +msgstr "" + +#: includes/PostTypes/Artist.php:108 +msgid "Social Links" +msgstr "" + +#: includes/PostTypes/Artist.php:117 +msgid "Band Members" +msgstr "" + +#: includes/PostTypes/Artist.php:142 +msgid "Artist Type" +msgstr "" + +#: includes/PostTypes/Artist.php:146 includes/Frontend/TemplateLoader.php:241 +msgid "Solo Artist" +msgstr "" + +#: includes/PostTypes/Artist.php:155 +msgid "Formed Date" +msgstr "" + +#: includes/PostTypes/Artist.php:159 +msgid "When the artist/band was formed or started their career." +msgstr "" + +#: includes/PostTypes/Artist.php:164 includes/ActivityPub/ArtistActor.php:273 +msgid "Location" +msgstr "" + +#: includes/PostTypes/Artist.php:168 +msgid "City, Country or region where the artist is based." +msgstr "" + +#: includes/PostTypes/Artist.php:173 includes/ActivityPub/ArtistActor.php:263 +msgid "Website" +msgstr "" + +#: includes/PostTypes/Artist.php:177 +msgid "Official website URL." +msgstr "" + +#: includes/PostTypes/Artist.php:197 +msgid "Mastodon" +msgstr "" + +#: includes/PostTypes/Artist.php:198 +msgid "Bandcamp" +msgstr "" + +#: includes/PostTypes/Artist.php:199 +msgid "SoundCloud" +msgstr "" + +#: includes/PostTypes/Artist.php:200 +msgid "YouTube" +msgstr "" + +#: includes/PostTypes/Artist.php:201 +msgid "Instagram" +msgstr "" + +#: includes/PostTypes/Artist.php:202 +msgid "Twitter/X" +msgstr "" + +#: includes/PostTypes/Artist.php:203 +msgid "Facebook" +msgstr "" + +#: includes/PostTypes/Artist.php:204 +msgid "TikTok" +msgstr "" + +#: includes/PostTypes/Artist.php:205 +msgid "Other" +msgstr "" + +#: includes/PostTypes/Artist.php:238 +msgid "Add band/group members (comma-separated names)." +msgstr "" + +#: includes/PostTypes/Artist.php:240 +msgid "One member per line." +msgstr "" + +#: includes/PostTypes/Album.php:43 +msgctxt "Post type general name" +msgid "Albums" +msgstr "" + +#: includes/PostTypes/Album.php:44 +msgctxt "Post type singular name" +msgid "Album" +msgstr "" + +#: includes/PostTypes/Album.php:45 +msgctxt "Admin Menu text" +msgid "Albums" +msgstr "" + +#: includes/PostTypes/Album.php:46 +msgctxt "Add New on Toolbar" +msgid "Album" +msgstr "" + +#: includes/PostTypes/Album.php:48 +msgid "Add New Album" +msgstr "" + +#: includes/PostTypes/Album.php:49 +msgid "New Album" +msgstr "" + +#: includes/PostTypes/Album.php:50 +msgid "Edit Album" +msgstr "" + +#: includes/PostTypes/Album.php:51 +msgid "View Album" +msgstr "" + +#: includes/PostTypes/Album.php:52 +msgid "All Albums" +msgstr "" + +#: includes/PostTypes/Album.php:53 +msgid "Search Albums" +msgstr "" + +#: includes/PostTypes/Album.php:54 +msgid "Parent Albums:" +msgstr "" + +#: includes/PostTypes/Album.php:55 +msgid "No albums found." +msgstr "" + +#: includes/PostTypes/Album.php:56 +msgid "No albums found in Trash." +msgstr "" + +#: includes/PostTypes/Album.php:57 +msgctxt "Overrides the \"Featured Image\" phrase" +msgid "Album Artwork" +msgstr "" + +#: includes/PostTypes/Album.php:58 +msgctxt "Overrides the \"Set featured image\" phrase" +msgid "Set album artwork" +msgstr "" + +#: includes/PostTypes/Album.php:59 +msgctxt "Overrides the \"Remove featured image\" phrase" +msgid "Remove album artwork" +msgstr "" + +#: includes/PostTypes/Album.php:60 +msgctxt "Overrides the \"Use as featured image\" phrase" +msgid "Use as album artwork" +msgstr "" + +#: includes/PostTypes/Album.php:61 +msgctxt "The post type archive label" +msgid "Album archives" +msgstr "" + +#: includes/PostTypes/Album.php:62 +msgctxt "Overrides the \"Insert into post\" phrase" +msgid "Insert into album" +msgstr "" + +#: includes/PostTypes/Album.php:63 +msgctxt "Overrides the \"Uploaded to this post\" phrase" +msgid "Uploaded to this album" +msgstr "" + +#: includes/PostTypes/Album.php:64 +msgctxt "Screen reader text" +msgid "Filter albums list" +msgstr "" + +#: includes/PostTypes/Album.php:65 +msgctxt "Screen reader text" +msgid "Albums list navigation" +msgstr "" + +#: includes/PostTypes/Album.php:66 +msgctxt "Screen reader text" +msgid "Albums list" +msgstr "" + +#: includes/PostTypes/Album.php:99 +msgid "Album Information" +msgstr "" + +#: includes/PostTypes/Album.php:117 +msgid "Album Codes" +msgstr "" + +#: includes/PostTypes/Album.php:142 +msgid "Release Type" +msgstr "" + +#: includes/PostTypes/Album.php:150 includes/Frontend/TemplateLoader.php:291 +msgid "Live Album" +msgstr "" + +#: includes/PostTypes/Album.php:151 includes/Frontend/TemplateLoader.php:292 +msgid "Remix Album" +msgstr "" + +#: includes/PostTypes/Album.php:165 +msgid "Total Tracks" +msgstr "" + +#: includes/PostTypes/Album.php:169 +msgid "Auto-calculated when tracks are added." +msgstr "" + +#: includes/PostTypes/Album.php:174 +msgid "Total Duration" +msgstr "" + +#: includes/PostTypes/Album.php:178 +msgid "seconds (auto-calculated)" +msgstr "" + +#: includes/PostTypes/Album.php:205 +msgid "Primary Artist" +msgstr "" + +#: includes/PostTypes/Album.php:208 +msgid "— Select Artist —" +msgstr "" + +#: includes/PostTypes/Album.php:220 includes/PostTypes/Track.php:479 +#, php-format +msgid "No artists found. %s" +msgstr "" + +#: includes/PostTypes/Album.php:221 includes/PostTypes/Track.php:480 +msgid "Add an artist first." +msgstr "" + +#: includes/PostTypes/Album.php:240 +msgid "UPC/EAN" +msgstr "" + +#: includes/PostTypes/Album.php:241 +msgid "12-13 digit UPC/EAN code" +msgstr "" + +#: includes/PostTypes/Album.php:244 +msgid "Catalog Number" +msgstr "" + +#: includes/PostTypes/Track.php:51 +msgctxt "Post type general name" +msgid "Tracks" +msgstr "" + +#: includes/PostTypes/Track.php:52 +msgctxt "Post type singular name" +msgid "Track" +msgstr "" + +#: includes/PostTypes/Track.php:53 +msgctxt "Admin Menu text" +msgid "Tracks" +msgstr "" + +#: includes/PostTypes/Track.php:54 +msgctxt "Add New on Toolbar" +msgid "Track" +msgstr "" + +#: includes/PostTypes/Track.php:56 +msgid "Add New Track" +msgstr "" + +#: includes/PostTypes/Track.php:57 +msgid "New Track" +msgstr "" + +#: includes/PostTypes/Track.php:58 +msgid "Edit Track" +msgstr "" + +#: includes/PostTypes/Track.php:59 +msgid "View Track" +msgstr "" + +#: includes/PostTypes/Track.php:60 +msgid "All Tracks" +msgstr "" + +#: includes/PostTypes/Track.php:61 +msgid "Search Tracks" +msgstr "" + +#: includes/PostTypes/Track.php:62 +msgid "Parent Tracks:" +msgstr "" + +#: includes/PostTypes/Track.php:63 +msgid "No tracks found." +msgstr "" + +#: includes/PostTypes/Track.php:64 +msgid "No tracks found in Trash." +msgstr "" + +#: includes/PostTypes/Track.php:65 +msgctxt "Overrides the \"Featured Image\" phrase" +msgid "Track Artwork" +msgstr "" + +#: includes/PostTypes/Track.php:66 +msgctxt "Overrides the \"Set featured image\" phrase" +msgid "Set track artwork" +msgstr "" + +#: includes/PostTypes/Track.php:67 +msgctxt "Overrides the \"Remove featured image\" phrase" +msgid "Remove track artwork" +msgstr "" + +#: includes/PostTypes/Track.php:68 +msgctxt "Overrides the \"Use as featured image\" phrase" +msgid "Use as track artwork" +msgstr "" + +#: includes/PostTypes/Track.php:69 +msgctxt "The post type archive label" +msgid "Track archives" +msgstr "" + +#: includes/PostTypes/Track.php:70 +msgctxt "Overrides the \"Insert into post\" phrase" +msgid "Insert into track" +msgstr "" + +#: includes/PostTypes/Track.php:71 +msgctxt "Overrides the \"Uploaded to this post\" phrase" +msgid "Uploaded to this track" +msgstr "" + +#: includes/PostTypes/Track.php:72 +msgctxt "Screen reader text" +msgid "Filter tracks list" +msgstr "" + +#: includes/PostTypes/Track.php:73 +msgctxt "Screen reader text" +msgid "Tracks list navigation" +msgstr "" + +#: includes/PostTypes/Track.php:74 +msgctxt "Screen reader text" +msgid "Tracks list" +msgstr "" + +#: includes/PostTypes/Track.php:107 includes/PostTypes/Track.php:168 +msgid "Audio File" +msgstr "" + +#: includes/PostTypes/Track.php:116 +msgid "Track Information" +msgstr "" + +#: includes/PostTypes/Track.php:143 +msgid "Track Codes" +msgstr "" + +#: includes/PostTypes/Track.php:185 includes/PostTypes/Track.php:241 +msgid "Select Audio File" +msgstr "" + +#: includes/PostTypes/Track.php:186 includes/PostTypes/Playlist.php:184 +#: includes/PostTypes/Playlist.php:252 +msgid "Remove" +msgstr "" + +#: includes/PostTypes/Track.php:188 +msgid "Supported formats: MP3, WAV, FLAC, OGG" +msgstr "" + +#: includes/PostTypes/Track.php:194 +msgid "Audio Format" +msgstr "" + +#: includes/PostTypes/Track.php:198 +msgid "— Auto-detect —" +msgstr "" + +#: includes/PostTypes/Track.php:208 +msgid "Duration (seconds)" +msgstr "" + +#: includes/PostTypes/Track.php:217 +#, php-format +msgid "(%s)" +msgstr "" + +#: includes/PostTypes/Track.php:223 +msgid "Auto-detected from audio file if available." +msgstr "" + +#: includes/PostTypes/Track.php:242 +msgid "Use this file" +msgstr "" + +#: includes/PostTypes/Track.php:305 +msgid "— Select Key —" +msgstr "" + +#: includes/PostTypes/Track.php:335 +msgid "Track Number" +msgstr "" + +#: includes/PostTypes/Track.php:343 +msgid "Disc Number" +msgstr "" + +#: includes/PostTypes/Track.php:351 +msgid "BPM" +msgstr "" + +#: includes/PostTypes/Track.php:355 +msgid "Beats per minute (tempo)." +msgstr "" + +#: includes/PostTypes/Track.php:360 +msgid "Musical Key" +msgstr "" + +#: includes/PostTypes/Track.php:372 +msgid "Explicit Content" +msgstr "" + +#: includes/PostTypes/Track.php:377 +msgid "This track contains explicit content" +msgstr "" + +#: includes/PostTypes/Track.php:383 +msgid "Preview Settings" +msgstr "" + +#: includes/PostTypes/Track.php:387 +msgid "Start at:" +msgstr "" + +#: includes/PostTypes/Track.php:389 includes/PostTypes/Track.php:395 +msgid "seconds" +msgstr "" + +#: includes/PostTypes/Track.php:393 +msgid "Duration:" +msgstr "" + +#: includes/PostTypes/Track.php:397 +msgid "Preview clip for non-authenticated users or before purchase." +msgstr "" + +#: includes/PostTypes/Track.php:425 +msgid "— No Album (Single) —" +msgstr "" + +#: includes/PostTypes/Track.php:465 +msgid "Select all artists featured on this track." +msgstr "" + +#: includes/PostTypes/Track.php:498 +msgid "ISRC" +msgstr "" + +#: includes/PostTypes/Track.php:499 +msgid "ISRC format: CC-XXX-YY-NNNNN" +msgstr "" + +#: includes/PostTypes/Track.php:500 +msgid "International Standard Recording Code" +msgstr "" + +#: includes/PostTypes/Playlist.php:43 +msgctxt "Post type general name" +msgid "Playlists" +msgstr "" + +#: includes/PostTypes/Playlist.php:44 +msgctxt "Post type singular name" +msgid "Playlist" +msgstr "" + +#: includes/PostTypes/Playlist.php:45 +msgctxt "Admin Menu text" +msgid "Playlists" +msgstr "" + +#: includes/PostTypes/Playlist.php:46 +msgctxt "Add New on Toolbar" +msgid "Playlist" +msgstr "" + +#: includes/PostTypes/Playlist.php:48 +msgid "Add New Playlist" +msgstr "" + +#: includes/PostTypes/Playlist.php:49 +msgid "New Playlist" +msgstr "" + +#: includes/PostTypes/Playlist.php:50 +msgid "Edit Playlist" +msgstr "" + +#: includes/PostTypes/Playlist.php:51 +msgid "View Playlist" +msgstr "" + +#: includes/PostTypes/Playlist.php:52 +msgid "All Playlists" +msgstr "" + +#: includes/PostTypes/Playlist.php:53 +msgid "Search Playlists" +msgstr "" + +#: includes/PostTypes/Playlist.php:54 +msgid "Parent Playlists:" +msgstr "" + +#: includes/PostTypes/Playlist.php:55 +msgid "No playlists found." +msgstr "" + +#: includes/PostTypes/Playlist.php:56 +msgid "No playlists found in Trash." +msgstr "" + +#: includes/PostTypes/Playlist.php:57 +msgctxt "Overrides the \"Featured Image\" phrase" +msgid "Playlist Cover" +msgstr "" + +#: includes/PostTypes/Playlist.php:58 +msgctxt "Overrides the \"Set featured image\" phrase" +msgid "Set playlist cover" +msgstr "" + +#: includes/PostTypes/Playlist.php:59 +msgctxt "Overrides the \"Remove featured image\" phrase" +msgid "Remove playlist cover" +msgstr "" + +#: includes/PostTypes/Playlist.php:60 +msgctxt "Overrides the \"Use as featured image\" phrase" +msgid "Use as playlist cover" +msgstr "" + +#: includes/PostTypes/Playlist.php:61 +msgctxt "The post type archive label" +msgid "Playlist archives" +msgstr "" + +#: includes/PostTypes/Playlist.php:62 +msgctxt "Overrides the \"Insert into post\" phrase" +msgid "Insert into playlist" +msgstr "" + +#: includes/PostTypes/Playlist.php:63 +msgctxt "Overrides the \"Uploaded to this post\" phrase" +msgid "Uploaded to this playlist" +msgstr "" + +#: includes/PostTypes/Playlist.php:64 +msgctxt "Screen reader text" +msgid "Filter playlists list" +msgstr "" + +#: includes/PostTypes/Playlist.php:65 +msgctxt "Screen reader text" +msgid "Playlists list navigation" +msgstr "" + +#: includes/PostTypes/Playlist.php:66 +msgctxt "Screen reader text" +msgid "Playlists list" +msgstr "" + +#: includes/PostTypes/Playlist.php:99 +msgid "Playlist Tracks" +msgstr "" + +#: includes/PostTypes/Playlist.php:108 +msgid "Playlist Settings" +msgstr "" + +#: includes/PostTypes/Playlist.php:117 +msgid "Playlist Stats" +msgstr "" + +#: includes/PostTypes/Playlist.php:160 +msgid "Current Tracks" +msgstr "" + +#: includes/PostTypes/Playlist.php:192 +msgid "Add Tracks" +msgstr "" + +#: includes/PostTypes/Playlist.php:195 +msgid "— Select a track to add —" +msgstr "" + +#: includes/PostTypes/Playlist.php:211 +msgid "Add to Playlist" +msgstr "" + +#: includes/PostTypes/Playlist.php:283 +msgid "Unlisted (link only)" +msgstr "" + +#: includes/PostTypes/Playlist.php:290 +msgid "Collaborative" +msgstr "" + +#: includes/PostTypes/Playlist.php:293 +msgid "Allow others to add tracks." +msgstr "" + +#: includes/PostTypes/Playlist.php:298 +msgid "Federated" +msgstr "" + +#: includes/PostTypes/Playlist.php:301 +msgid "Allow tracks from other FediStream instances." +msgstr "" + +#: includes/PostTypes/Playlist.php:317 +msgid "Tracks:" +msgstr "" + +#: includes/PostTypes/Playlist.php:321 +msgid "Total Duration:" +msgstr "" + +#: includes/PostTypes/Playlist.php:330 +msgid "Stats are automatically updated when saved." +msgstr "" + +#: includes/ActivityPub/ArtistActor.php:300 +msgid "Active Since" +msgstr "" + +#: includes/ActivityPub/AlbumTransformer.php:111 +#, php-format +msgid "By %s" +msgstr "" + +#: includes/ActivityPub/AlbumTransformer.php:115 +#, php-format +msgid "- Released %s" +msgstr "" + +#: includes/ActivityPub/AlbumTransformer.php:119 +#, php-format +msgid "- %d track" +msgid_plural "- %d tracks" +msgstr[0] "" +msgstr[1] "" + +#: includes/ActivityPub/RestApi.php:438 +msgid "Published to ActivityPub" +msgstr "" + +#: includes/ActivityPub/RestApi.php:446 +msgid "Failed to publish" +msgstr "" + +#: includes/WooCommerce/AlbumProduct.php:371 +#: includes/WooCommerce/TrackProduct.php:394 +#, php-format +msgid "%1$s (%2$s)" +msgstr "" + +#: includes/WooCommerce/AlbumProduct.php:419 +#: includes/WooCommerce/TrackProduct.php:442 +msgid "Name Your Price" +msgstr "" + +#: includes/WooCommerce/AlbumProduct.php:431 +#: includes/WooCommerce/TrackProduct.php:454 +#, php-format +msgid "From %s" +msgstr "" + +#: includes/WooCommerce/AlbumProduct.php:435 +#: includes/WooCommerce/TrackProduct.php:458 +#: includes/WooCommerce/Integration.php:246 +msgid "Pay What You Want" +msgstr "" + +#: includes/WooCommerce/AlbumProduct.php:442 +#: includes/WooCommerce/TrackProduct.php:465 +#, php-format +msgid "(Suggested: %s)" +msgstr "" + +#: includes/WooCommerce/AlbumProduct.php:485 +#: includes/WooCommerce/TrackProduct.php:507 +#, php-format +msgid "Please enter at least %s" +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:52 +msgid "You must be logged in to download files." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:75 +#: includes/WooCommerce/StreamingAccess.php:239 +msgid "Invalid track." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:80 +msgid "You have not purchased this track." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:85 +#: includes/WooCommerce/StreamingAccess.php:244 includes/Frontend/Ajax.php:60 +#: includes/Frontend/Ajax.php:154 +msgid "Track not found." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:91 +#: includes/WooCommerce/StreamingAccess.php:250 includes/Frontend/Ajax.php:73 +msgid "No audio file available." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:96 +#: includes/WooCommerce/DigitalDelivery.php:285 +#: includes/WooCommerce/StreamingAccess.php:255 +msgid "File not found." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:120 +msgid "Invalid album." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:125 +msgid "You have not purchased this album." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:130 +msgid "Album not found." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:152 +msgid "No tracks found in this album." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:159 +msgid "Failed to create download package." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:350 +#: includes/WooCommerce/DigitalDelivery.php:354 +msgid "Your FediStream Downloads" +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:351 +msgid "Access your purchased music at:" +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:359 +#, php-format +msgid "Access your purchased music in your %s." +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:360 +msgid "account downloads" +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:386 +msgid "FediStream Library" +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:390 +msgid "Title" +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:392 +msgid "Purchased" +msgstr "" + +#: includes/WooCommerce/DigitalDelivery.php:393 +msgid "Download" +msgstr "" + +#: includes/WooCommerce/StreamingAccess.php:373 +msgid "You own this track." +msgstr "" + +#: includes/WooCommerce/StreamingAccess.php:378 +msgid "You own this album." +msgstr "" + +#: includes/WooCommerce/StreamingAccess.php:391 +msgid "Buy Track" +msgstr "" + +#: includes/WooCommerce/StreamingAccess.php:408 +#, php-format +msgid "Buy Full Album: %s" +msgstr "" + +#: includes/WooCommerce/Integration.php:115 +msgid "FediStream Album" +msgstr "" + +#: includes/WooCommerce/Integration.php:116 +msgid "FediStream Track" +msgstr "" + +#: includes/WooCommerce/Integration.php:148 +#: includes/WooCommerce/Integration.php:701 includes/Plugin.php:266 +#: includes/Plugin.php:267 +msgid "FediStream" +msgstr "" + +#: includes/WooCommerce/Integration.php:155 +msgid "Audio Formats" +msgstr "" + +#: includes/WooCommerce/Integration.php:213 +msgid "Linked Album" +msgstr "" + +#: includes/WooCommerce/Integration.php:215 +msgid "Select an album..." +msgstr "" + +#: includes/WooCommerce/Integration.php:222 +msgid "Select the FediStream album this product represents." +msgstr "" + +#: includes/WooCommerce/Integration.php:228 +msgid "Linked Track" +msgstr "" + +#: includes/WooCommerce/Integration.php:230 +msgid "Select a track..." +msgstr "" + +#: includes/WooCommerce/Integration.php:237 +msgid "Select the FediStream track this product represents." +msgstr "" + +#: includes/WooCommerce/Integration.php:243 +msgid "Pricing Type" +msgstr "" + +#: includes/WooCommerce/Integration.php:245 +msgid "Fixed Price" +msgstr "" + +#: includes/WooCommerce/Integration.php:247 +msgid "Name Your Price (Free+)" +msgstr "" + +#: includes/WooCommerce/Integration.php:257 +msgid "Minimum Price" +msgstr "" + +#: includes/WooCommerce/Integration.php:259 +msgid "Minimum price for Pay What You Want. Leave empty for no minimum." +msgstr "" + +#: includes/WooCommerce/Integration.php:269 +msgid "Suggested Price" +msgstr "" + +#: includes/WooCommerce/Integration.php:271 +msgid "Suggested price shown to customers." +msgstr "" + +#: includes/WooCommerce/Integration.php:285 +msgid "Include Streaming" +msgstr "" + +#: includes/WooCommerce/Integration.php:286 +msgid "Purchase unlocks full-quality streaming access." +msgstr "" + +#: includes/WooCommerce/Integration.php:297 +msgid "Available Formats" +msgstr "" + +#: includes/WooCommerce/Integration.php:319 +msgid "Select which audio formats customers can download after purchase." +msgstr "" + +#: includes/WooCommerce/Integration.php:446 +msgid "Preview" +msgstr "" + +#: includes/WooCommerce/Integration.php:448 +msgid "Play preview" +msgstr "" + +#: includes/WooCommerce/Integration.php:492 +msgid "Tracklist" +msgstr "" + +#: includes/Taxonomies/Genre.php:47 +msgctxt "taxonomy general name" +msgid "Genres" +msgstr "" + +#: includes/Taxonomies/Genre.php:48 +msgctxt "taxonomy singular name" +msgid "Genre" +msgstr "" + +#: includes/Taxonomies/Genre.php:49 +msgid "Search Genres" +msgstr "" + +#: includes/Taxonomies/Genre.php:50 +msgid "Popular Genres" +msgstr "" + +#: includes/Taxonomies/Genre.php:51 +msgid "All Genres" +msgstr "" + +#: includes/Taxonomies/Genre.php:52 +msgid "Parent Genre" +msgstr "" + +#: includes/Taxonomies/Genre.php:53 +msgid "Parent Genre:" +msgstr "" + +#: includes/Taxonomies/Genre.php:54 +msgid "Edit Genre" +msgstr "" + +#: includes/Taxonomies/Genre.php:55 +msgid "View Genre" +msgstr "" + +#: includes/Taxonomies/Genre.php:56 +msgid "Update Genre" +msgstr "" + +#: includes/Taxonomies/Genre.php:57 +msgid "Add New Genre" +msgstr "" + +#: includes/Taxonomies/Genre.php:58 +msgid "New Genre Name" +msgstr "" + +#: includes/Taxonomies/Genre.php:59 +msgid "Separate genres with commas" +msgstr "" + +#: includes/Taxonomies/Genre.php:60 +msgid "Add or remove genres" +msgstr "" + +#: includes/Taxonomies/Genre.php:61 +msgid "Choose from the most used genres" +msgstr "" + +#: includes/Taxonomies/Genre.php:62 +msgid "No genres found." +msgstr "" + +#: includes/Taxonomies/Genre.php:63 +msgid "No genres" +msgstr "" + +#: includes/Taxonomies/Genre.php:64 includes/Plugin.php:324 +#: includes/Plugin.php:325 +msgid "Genres" +msgstr "" + +#: includes/Taxonomies/Genre.php:65 +msgid "Genres list navigation" +msgstr "" + +#: includes/Taxonomies/Genre.php:66 +msgid "Genres list" +msgstr "" + +#: includes/Taxonomies/Genre.php:67 +msgid "← Back to Genres" +msgstr "" + +#: includes/Taxonomies/Mood.php:46 +msgctxt "taxonomy general name" +msgid "Moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:47 +msgctxt "taxonomy singular name" +msgid "Mood" +msgstr "" + +#: includes/Taxonomies/Mood.php:48 +msgid "Search Moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:49 +msgid "Popular Moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:50 +msgid "All Moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:51 +msgid "Edit Mood" +msgstr "" + +#: includes/Taxonomies/Mood.php:52 +msgid "View Mood" +msgstr "" + +#: includes/Taxonomies/Mood.php:53 +msgid "Update Mood" +msgstr "" + +#: includes/Taxonomies/Mood.php:54 +msgid "Add New Mood" +msgstr "" + +#: includes/Taxonomies/Mood.php:55 +msgid "New Mood Name" +msgstr "" + +#: includes/Taxonomies/Mood.php:56 +msgid "Separate moods with commas" +msgstr "" + +#: includes/Taxonomies/Mood.php:57 +msgid "Add or remove moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:58 +msgid "Choose from the most used moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:59 +msgid "No moods found." +msgstr "" + +#: includes/Taxonomies/Mood.php:60 +msgid "No moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:61 +msgid "Moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:62 +msgid "Moods list navigation" +msgstr "" + +#: includes/Taxonomies/Mood.php:63 +msgid "Moods list" +msgstr "" + +#: includes/Taxonomies/Mood.php:64 +msgid "← Back to Moods" +msgstr "" + +#: includes/Taxonomies/Mood.php:98 +msgid "Energetic" +msgstr "" + +#: includes/Taxonomies/Mood.php:99 +msgid "Calm" +msgstr "" + +#: includes/Taxonomies/Mood.php:100 +msgid "Uplifting" +msgstr "" + +#: includes/Taxonomies/Mood.php:101 +msgid "Melancholic" +msgstr "" + +#: includes/Taxonomies/Mood.php:102 +msgid "Aggressive" +msgstr "" + +#: includes/Taxonomies/Mood.php:103 +msgid "Romantic" +msgstr "" + +#: includes/Taxonomies/Mood.php:104 +msgid "Happy" +msgstr "" + +#: includes/Taxonomies/Mood.php:105 +msgid "Sad" +msgstr "" + +#: includes/Taxonomies/Mood.php:106 +msgid "Relaxing" +msgstr "" + +#: includes/Taxonomies/Mood.php:107 +msgid "Intense" +msgstr "" + +#: includes/Taxonomies/Mood.php:108 +msgid "Dreamy" +msgstr "" + +#: includes/Taxonomies/Mood.php:109 +msgid "Dark" +msgstr "" + +#: includes/Taxonomies/Mood.php:110 +msgid "Groovy" +msgstr "" + +#: includes/Taxonomies/Mood.php:111 +msgid "Epic" +msgstr "" + +#: includes/Taxonomies/Mood.php:112 +msgid "Peaceful" +msgstr "" + +#: includes/Taxonomies/Mood.php:113 +msgid "Motivational" +msgstr "" + +#: includes/Taxonomies/Mood.php:114 +msgid "Nostalgic" +msgstr "" + +#: includes/Taxonomies/Mood.php:115 +msgid "Playful" +msgstr "" + +#: includes/Taxonomies/Mood.php:116 +msgid "Sensual" +msgstr "" + +#: includes/Taxonomies/Mood.php:117 +msgid "Suspenseful" +msgstr "" + +#: includes/Taxonomies/License.php:46 +msgctxt "taxonomy general name" +msgid "Licenses" +msgstr "" + +#: includes/Taxonomies/License.php:47 +msgctxt "taxonomy singular name" +msgid "License" +msgstr "" + +#: includes/Taxonomies/License.php:48 +msgid "Search Licenses" +msgstr "" + +#: includes/Taxonomies/License.php:49 +msgid "Popular Licenses" +msgstr "" + +#: includes/Taxonomies/License.php:50 +msgid "All Licenses" +msgstr "" + +#: includes/Taxonomies/License.php:51 +msgid "Parent License" +msgstr "" + +#: includes/Taxonomies/License.php:52 +msgid "Parent License:" +msgstr "" + +#: includes/Taxonomies/License.php:53 +msgid "Edit License" +msgstr "" + +#: includes/Taxonomies/License.php:54 +msgid "View License" +msgstr "" + +#: includes/Taxonomies/License.php:55 +msgid "Update License" +msgstr "" + +#: includes/Taxonomies/License.php:56 +msgid "Add New License" +msgstr "" + +#: includes/Taxonomies/License.php:57 +msgid "New License Name" +msgstr "" + +#: includes/Taxonomies/License.php:58 +msgid "Separate licenses with commas" +msgstr "" + +#: includes/Taxonomies/License.php:59 +msgid "Add or remove licenses" +msgstr "" + +#: includes/Taxonomies/License.php:60 +msgid "Choose from the most used licenses" +msgstr "" + +#: includes/Taxonomies/License.php:61 +msgid "No licenses found." +msgstr "" + +#: includes/Taxonomies/License.php:62 +msgid "No licenses" +msgstr "" + +#: includes/Taxonomies/License.php:63 +msgid "Licenses" +msgstr "" + +#: includes/Taxonomies/License.php:64 +msgid "Licenses list navigation" +msgstr "" + +#: includes/Taxonomies/License.php:65 +msgid "Licenses list" +msgstr "" + +#: includes/Taxonomies/License.php:66 +msgid "← Back to Licenses" +msgstr "" + +#: includes/Taxonomies/License.php:101 +msgid "Standard copyright. All rights reserved by the creator." +msgstr "" + +#: includes/Taxonomies/License.php:105 +msgid "Creative Commons licenses for sharing and reuse." +msgstr "" + +#: includes/Taxonomies/License.php:107 +msgid "Public Domain Dedication - No rights reserved" +msgstr "" + +#: includes/Taxonomies/License.php:108 +msgid "Attribution - Credit must be given" +msgstr "" + +#: includes/Taxonomies/License.php:109 +msgid "Attribution-ShareAlike - Credit and share under same terms" +msgstr "" + +#: includes/Taxonomies/License.php:110 +msgid "Attribution-NoDerivs - Credit, no modifications" +msgstr "" + +#: includes/Taxonomies/License.php:111 +msgid "Attribution-NonCommercial - Credit, non-commercial only" +msgstr "" + +#: includes/Taxonomies/License.php:112 +msgid "Attribution-NonCommercial-ShareAlike" +msgstr "" + +#: includes/Taxonomies/License.php:113 +msgid "Attribution-NonCommercial-NoDerivs" +msgstr "" + +#: includes/Taxonomies/License.php:117 +msgid "Works in the public domain with no copyright restrictions." +msgstr "" + +#: includes/Roles/Capabilities.php:224 +msgid "FediStream Artist" +msgstr "" + +#: includes/Roles/Capabilities.php:231 +msgid "FediStream Label" +msgstr "" + +#: includes/Frontend/TemplateLoader.php:486 +msgid "« Previous" +msgstr "" + +#: includes/Frontend/TemplateLoader.php:487 +msgid "Next »" +msgstr "" + +#: includes/Frontend/TemplateLoader.php:509 includes/User/LibraryPage.php:112 +#: includes/Plugin.php:315 includes/Plugin.php:316 includes/Plugin.php:377 +msgid "Playlists" +msgstr "" + +#: includes/Frontend/template-wrapper.php:40 +msgid "Genre" +msgstr "" + +#: includes/Frontend/template-wrapper.php:43 +msgid "Mood" +msgstr "" + +#: includes/Frontend/template-wrapper.php:61 +msgid "Template Error:" +msgstr "" + +#: includes/Frontend/Shortcodes.php:55 +msgid "This content requires a valid FediStream license." +msgstr "" + +#: includes/Frontend/Shortcodes.php:280 +msgid "Latest Releases" +msgstr "" + +#: includes/Frontend/Shortcodes.php:347 +#: includes/Frontend/Widgets/PopularTracksWidget.php:45 +#: includes/Frontend/Widgets/PopularTracksWidget.php:100 +msgid "Popular Tracks" +msgstr "" + +#: includes/Frontend/Widgets/RecentReleasesWidget.php:29 +msgid "FediStream: Recent Releases" +msgstr "" + +#: includes/Frontend/Widgets/RecentReleasesWidget.php:31 +msgid "Display recent album releases." +msgstr "" + +#: includes/Frontend/Widgets/RecentReleasesWidget.php:45 +#: includes/Frontend/Widgets/RecentReleasesWidget.php:108 +msgid "Recent Releases" +msgstr "" + +#: includes/Frontend/Widgets/RecentReleasesWidget.php:113 +#: includes/Frontend/Widgets/PopularTracksWidget.php:104 +#: includes/Frontend/Widgets/FeaturedArtistWidget.php:125 +#: includes/Frontend/Widgets/NowPlayingWidget.php:83 +msgid "Title:" +msgstr "" + +#: includes/Frontend/Widgets/RecentReleasesWidget.php:117 +msgid "Number of releases:" +msgstr "" + +#: includes/Frontend/Widgets/RecentReleasesWidget.php:121 +msgid "Release type:" +msgstr "" + +#: includes/Frontend/Widgets/RecentReleasesWidget.php:123 +msgid "All types" +msgstr "" + +#: includes/Frontend/Widgets/PopularTracksWidget.php:29 +msgid "FediStream: Popular Tracks" +msgstr "" + +#: includes/Frontend/Widgets/PopularTracksWidget.php:31 +msgid "Display popular tracks by play count." +msgstr "" + +#: includes/Frontend/Widgets/PopularTracksWidget.php:108 +msgid "Number of tracks:" +msgstr "" + +#: includes/Frontend/Widgets/FeaturedArtistWidget.php:29 +msgid "FediStream: Featured Artist" +msgstr "" + +#: includes/Frontend/Widgets/FeaturedArtistWidget.php:31 +msgid "Display a featured artist." +msgstr "" + +#: includes/Frontend/Widgets/FeaturedArtistWidget.php:45 +#: includes/Frontend/Widgets/FeaturedArtistWidget.php:109 +msgid "Featured Artist" +msgstr "" + +#: includes/Frontend/Widgets/FeaturedArtistWidget.php:131 +msgid "Show random artist" +msgstr "" + +#: includes/Frontend/Widgets/FeaturedArtistWidget.php:135 +msgid "Or select specific artist:" +msgstr "" + +#: includes/Frontend/Widgets/FeaturedArtistWidget.php:137 +msgid "-- Select Artist --" +msgstr "" + +#: includes/Frontend/Widgets/NowPlayingWidget.php:28 +msgid "FediStream: Now Playing" +msgstr "" + +#: includes/Frontend/Widgets/NowPlayingWidget.php:30 +msgid "Display the currently playing track." +msgstr "" + +#: includes/Frontend/Widgets/NowPlayingWidget.php:44 +#: includes/Frontend/Widgets/NowPlayingWidget.php:79 +msgid "Now Playing" +msgstr "" + +#: includes/Frontend/Widgets/NowPlayingWidget.php:89 +msgid "Show player controls" +msgstr "" + +#: includes/Frontend/Widgets/NowPlayingWidget.php:93 +msgid "" +"This widget shows information about the currently playing track and updates " +"automatically via JavaScript." +msgstr "" + +#: includes/Frontend/Ajax.php:43 includes/Frontend/Ajax.php:137 +msgid "This feature requires a valid license." +msgstr "" + +#: includes/Frontend/Ajax.php:48 includes/Frontend/Ajax.php:142 +msgid "Invalid nonce." +msgstr "" + +#: includes/Frontend/Ajax.php:54 includes/Frontend/Ajax.php:148 +msgid "Invalid track ID." +msgstr "" + +#: includes/Frontend/Ajax.php:65 +msgid "Track not available." +msgstr "" + +#: includes/Frontend/Ajax.php:179 +msgid "Play recorded." +msgstr "" + +#: includes/User/Library.php:49 includes/User/Library.php:94 +#: includes/User/Library.php:138 includes/User/Library.php:160 +#: includes/User/Library.php:181 includes/User/Library.php:202 +msgid "You must be logged in." +msgstr "" + +#: includes/User/Library.php:56 +msgid "Invalid request." +msgstr "" + +#: includes/User/Library.php:76 +msgid "Added to your library." +msgstr "" + +#: includes/User/Library.php:77 +msgid "Removed from your library." +msgstr "" + +#: includes/User/Library.php:81 +msgid "Failed to update library." +msgstr "" + +#: includes/User/Library.php:100 +msgid "Invalid artist." +msgstr "" + +#: includes/User/Library.php:120 +msgid "You are now following this artist." +msgstr "" + +#: includes/User/Library.php:121 +msgid "You unfollowed this artist." +msgstr "" + +#: includes/User/Library.php:125 +msgid "Failed to update follow status." +msgstr "" + +#: includes/User/Library.php:209 includes/User/LibraryPage.php:58 +msgid "History cleared." +msgstr "" + +#: includes/User/Library.php:211 +msgid "Failed to clear history." +msgstr "" + +#: includes/User/Library.php:707 includes/User/LibraryPage.php:216 +msgid "Remove from library" +msgstr "" + +#: includes/User/Library.php:707 +msgid "Add to library" +msgstr "" + +#: includes/User/Library.php:736 +msgid "Following" +msgstr "" + +#: includes/User/Library.php:736 +msgid "Follow" +msgstr "" + +#: includes/User/LibraryPage.php:53 +msgid "Loading..." +msgstr "" + +#: includes/User/LibraryPage.php:54 +msgid "No favorites yet." +msgstr "" + +#: includes/User/LibraryPage.php:55 +msgid "Not following any artists yet." +msgstr "" + +#: includes/User/LibraryPage.php:56 +msgid "No listening history." +msgstr "" + +#: includes/User/LibraryPage.php:57 +msgid "Are you sure you want to clear your listening history?" +msgstr "" + +#: includes/User/LibraryPage.php:59 +msgid "An error occurred. Please try again." +msgstr "" + +#: includes/User/LibraryPage.php:95 +msgid "Favorites" +msgstr "" + +#: includes/User/LibraryPage.php:103 +msgid "History" +msgstr "" + +#: includes/User/LibraryPage.php:109 +msgid "All" +msgstr "" + +#: includes/User/LibraryPage.php:134 +msgid "Clear History" +msgstr "" + +#: includes/User/LibraryPage.php:161 +msgid "Please log in to view your library." +msgstr "" + +#: includes/User/LibraryPage.php:163 +msgid "Log In" +msgstr "" + +#: includes/User/LibraryPage.php:208 +#, php-format +msgid "%d track" +msgid_plural "%d tracks" +msgstr[0] "" +msgstr[1] "" + +#: includes/User/LibraryPage.php:253 includes/User/LibraryPage.php:255 +msgid "Unfollow" +msgstr "" + +#: includes/User/LibraryPage.php:296 +#, php-format +msgid "Played %s" +msgstr "" + +#: includes/User/LibraryPage.php:297 includes/Plugin.php:581 +msgid "ago" +msgstr "" + +#: includes/User/Notifications.php:84 +msgid "No notifications" +msgstr "" + +#: includes/User/Notifications.php:85 +msgid "Mark all as read" +msgstr "" + +#: includes/User/Notifications.php:86 +msgid "View all notifications" +msgstr "" + +#: includes/User/Notifications.php:87 +msgid "Just now" +msgstr "" + +#: includes/User/Notifications.php:88 +msgid "An error occurred." +msgstr "" + +#: includes/User/Notifications.php:309 includes/User/Notifications.php:337 +#: includes/User/Notifications.php:369 includes/User/Notifications.php:391 +msgid "Not logged in." +msgstr "" + +#: includes/User/Notifications.php:343 includes/User/Notifications.php:397 +msgid "Invalid notification." +msgstr "" + +#: includes/User/Notifications.php:356 +msgid "Failed to update notification." +msgstr "" + +#: includes/User/Notifications.php:378 +msgid "Failed to update notifications." +msgstr "" + +#: includes/User/Notifications.php:410 +msgid "Failed to delete notification." +msgstr "" + +#: includes/User/Notifications.php:445 +#, php-format +msgid "New release from %s" +msgstr "" + +#: includes/User/Notifications.php:450 +#, php-format +msgid "%1$s released a new album: %2$s" +msgstr "" + +#: includes/User/Notifications.php:509 +#, php-format +msgid "New track from %s" +msgstr "" + +#: includes/User/Notifications.php:514 +#, php-format +msgid "%1$s released a new track: %2$s" +msgstr "" + +#: includes/User/Notifications.php:555 +msgid "New follower" +msgstr "" + +#: includes/User/Notifications.php:558 +#, php-format +msgid "%s started following you" +msgstr "" + +#: includes/User/Notifications.php:586 includes/User/Notifications.php:626 +msgid "Someone" +msgstr "" + +#: includes/User/Notifications.php:591 +msgid "New like from Fediverse" +msgstr "" + +#: includes/User/Notifications.php:594 +#, php-format +msgid "%1$s liked your %2$s" +msgstr "" + +#: includes/User/Notifications.php:631 +msgid "New boost from Fediverse" +msgstr "" + +#: includes/User/Notifications.php:634 +#, php-format +msgid "%1$s boosted your %2$s" +msgstr "" + +#: includes/User/Notifications.php:678 +#, php-format +msgid "[%1$s] %2$s" +msgstr "" + +#: includes/User/Notifications.php:720 +msgid "View Details" +msgstr "" + +#: includes/User/Notifications.php:726 +#, php-format +msgid "This email was sent by %s." +msgstr "" + +#: includes/Plugin.php:221 includes/Plugin.php:333 includes/Plugin.php:334 +msgid "Settings" +msgstr "" + +#: includes/Plugin.php:227 includes/Plugin.php:278 includes/Plugin.php:279 +msgid "Dashboard" +msgstr "" + +#: includes/Plugin.php:354 +msgid "FediStream Dashboard" +msgstr "" + +#: includes/Plugin.php:361 +msgid "Manage Artists" +msgstr "" + +#: includes/Plugin.php:367 +msgid "Manage Albums" +msgstr "" + +#: includes/Plugin.php:373 +msgid "Manage Tracks" +msgstr "" + +#: includes/Plugin.php:379 +msgid "Manage Playlists" +msgstr "" + +#: includes/Plugin.php:384 +msgid "Quick Actions" +msgstr "" + +#: includes/Plugin.php:386 +msgid "Add Artist" +msgstr "" + +#: includes/Plugin.php:387 +msgid "Add Album" +msgstr "" + +#: includes/Plugin.php:388 +msgid "Add Track" +msgstr "" + +#: includes/Plugin.php:389 +msgid "Add Playlist" +msgstr "" + +#: includes/Plugin.php:394 +msgid "Getting Started" +msgstr "" + +#: includes/Plugin.php:396 +msgid "Add your artists or bands." +msgstr "" + +#: includes/Plugin.php:397 +msgid "Create albums and assign them to artists." +msgstr "" + +#: includes/Plugin.php:398 +msgid "Upload tracks and add them to albums." +msgstr "" + +#: includes/Plugin.php:399 +msgid "Create playlists to curate your music." +msgstr "" + +#: includes/Plugin.php:400 +msgid "Share your music via ActivityPub to the Fediverse!" +msgstr "" + +#: includes/Plugin.php:439 +msgid "License" +msgstr "" + +#: includes/Plugin.php:440 +msgid "Default Settings" +msgstr "" + +#: includes/Plugin.php:441 +msgid "Integrations" +msgstr "" + +#: includes/Plugin.php:445 +msgid "FediStream Settings" +msgstr "" + +#: includes/Plugin.php:493 +msgid "License settings saved." +msgstr "" + +#: includes/Plugin.php:499 +msgid "Settings saved." +msgstr "" + +#: includes/Plugin.php:505 +msgid "Integration settings saved." +msgstr "" + +#: includes/Plugin.php:532 +msgid "License is active and valid." +msgstr "" + +#: includes/Plugin.php:533 +msgid "License is invalid." +msgstr "" + +#: includes/Plugin.php:534 +msgid "License has expired." +msgstr "" + +#: includes/Plugin.php:535 +msgid "License has been revoked." +msgstr "" + +#: includes/Plugin.php:536 +msgid "License is inactive. Please activate it." +msgstr "" + +#: includes/Plugin.php:537 +msgid "License has not been validated yet." +msgstr "" + +#: includes/Plugin.php:538 +msgid "License server is not configured." +msgstr "" + +#: includes/Plugin.php:552 +msgid "Unknown status." +msgstr "" + +#: includes/Plugin.php:565 +#, php-format +msgid "Expires: %s" +msgstr "" + +#: includes/Plugin.php:572 +msgid "Lifetime license" +msgstr "" + +#: includes/Plugin.php:580 +#, php-format +msgid "Last checked: %s" +msgstr "" + +#: includes/Plugin.php:595 +msgid "License Server URL" +msgstr "" + +#: includes/Plugin.php:601 +msgid "The URL of your license server." +msgstr "" + +#: includes/Plugin.php:606 +msgid "License Key" +msgstr "" + +#: includes/Plugin.php:612 +msgid "Your license key from your purchase." +msgstr "" + +#: includes/Plugin.php:617 +msgid "Server Secret" +msgstr "" + +#: includes/Plugin.php:622 +msgid "" +"64-character verification secret from your license account. Leave empty to " +"keep existing." +msgstr "" + +#: includes/Plugin.php:628 +msgid "Save License Settings" +msgstr "" + +#: includes/Plugin.php:631 +msgid "Validate License" +msgstr "" + +#: includes/Plugin.php:635 +msgid "Activate License" +msgstr "" + +#: includes/Plugin.php:664 +msgid "Max Upload Size" +msgstr "" + +#: includes/Plugin.php:668 +msgid "Maximum file size for audio uploads." +msgstr "" + +#: includes/Plugin.php:673 +msgid "Default License" +msgstr "" + +#: includes/Plugin.php:677 +msgid "All Rights Reserved" +msgstr "" + +#: includes/Plugin.php:684 +msgid "Default license for new uploads." +msgstr "" + +#: includes/Plugin.php:708 +msgid "ActivityPub Integration" +msgstr "" + +#: includes/Plugin.php:712 +msgid "Enable ActivityPub features" +msgstr "" + +#: includes/Plugin.php:714 +msgid "Publish releases to the Fediverse and allow followers." +msgstr "" + +#: includes/Plugin.php:718 +msgid "The ActivityPub plugin is recommended for full Fediverse integration." +msgstr "" + +#: includes/Plugin.php:724 +msgid "WooCommerce Integration" +msgstr "" + +#: includes/Plugin.php:728 +msgid "Enable WooCommerce features" +msgstr "" + +#: includes/Plugin.php:733 +msgid "WooCommerce is not installed or active." +msgstr "" + +#: includes/Plugin.php:736 +msgid "Sell albums and tracks through WooCommerce." +msgstr "" + +#: includes/License/Manager.php:144 includes/License/Manager.php:244 +#: includes/License/Manager.php:325 +msgid "License server configuration is incomplete." +msgstr "" + +#: includes/License/Manager.php:152 includes/License/Manager.php:252 +msgid "No license key provided." +msgstr "" + +#: includes/License/Manager.php:170 +msgid "License validated successfully." +msgstr "" + +#: includes/License/Manager.php:182 includes/License/Manager.php:278 +msgid "License key not found. Please check your license key." +msgstr "" + +#: includes/License/Manager.php:188 includes/License/Manager.php:283 +msgid "Your license has expired. Please renew to continue." +msgstr "" + +#: includes/License/Manager.php:194 +msgid "Your license has been revoked." +msgstr "" + +#: includes/License/Manager.php:200 +msgid "License is inactive. Please activate it first." +msgstr "" + +#: includes/License/Manager.php:206 +msgid "This license is not activated for this domain." +msgstr "" + +#: includes/License/Manager.php:211 includes/License/Manager.php:288 +#: includes/License/Manager.php:395 +msgid "License verification failed. Please check your server secret." +msgstr "" + +#: includes/License/Manager.php:216 +msgid "Too many requests. Please try again later." +msgstr "" + +#: includes/License/Manager.php:223 +#, php-format +msgid "License validation failed: %s" +msgstr "" + +#: includes/License/Manager.php:230 +msgid "Unable to verify license. Please try again later." +msgstr "" + +#: includes/License/Manager.php:273 +msgid "" +"Maximum number of activations reached. Please deactivate another site first." +msgstr "" + +#: includes/License/Manager.php:295 +#, php-format +msgid "License activation failed: %s" +msgstr "" + +#: includes/License/Manager.php:302 +msgid "Unable to activate license. Please try again later." +msgstr "" + +#: includes/License/Manager.php:336 +msgid "No license key configured." +msgstr "" + +#: includes/License/Manager.php:369 includes/License/Manager.php:379 +msgid "License is active." +msgstr "" + +#: includes/License/Manager.php:370 includes/License/Manager.php:380 +msgid "License is not active." +msgstr "" + +#: includes/License/Manager.php:387 +msgid "License key not found." +msgstr "" + +#: includes/License/Manager.php:403 +msgid "Unable to check license status." +msgstr "" + +#: includes/License/Manager.php:572 includes/License/Manager.php:595 +#: includes/License/Manager.php:618 includes/License/Manager.php:640 +msgid "You do not have permission to perform this action." +msgstr "" + +#: includes/License/Manager.php:626 +msgid "License deactivated." +msgstr "" + +#: wp-fedistream.php:112 +#, php-format +msgid "" +"WP FediStream requires PHP version %1$s or higher. You are running PHP %2$s." msgstr "" #: wp-fedistream.php:127 +#, php-format +msgid "" +"WP FediStream requires WordPress version %1$s or higher. You are running " +"WordPress %2$s." +msgstr "" + +#: wp-fedistream.php:140 +msgid "" +"WP FediStream requires Composer dependencies to be installed. Please run " +"\"composer install\" in the plugin directory." +msgstr "" + +#: wp-fedistream.php:156 +#, php-format msgid "WP FediStream requires PHP version %s or higher." msgstr "" diff --git a/wp-fedistream.php b/wp-fedistream.php index 0936497..bac8ed1 100644 --- a/wp-fedistream.php +++ b/wp-fedistream.php @@ -3,7 +3,7 @@ * Plugin Name: WP FediStream * Plugin URI: https://src.bundespruefstelle.ch/magdev/wp-fedistream * Description: Stream music over ActivityPub - Build your own music streaming platform for Musicians and Labels. - * Version: 0.2.0 + * Version: 0.3.0 * Requires at least: 6.4 * Requires PHP: 8.3 * Author: Marco Graetsch @@ -26,7 +26,7 @@ if ( ! defined( 'ABSPATH' ) ) { * * @var string */ -define( 'WP_FEDISTREAM_VERSION', '0.2.0' ); +define( 'WP_FEDISTREAM_VERSION', '0.3.0' ); /** * Plugin file path.