diff --git a/steam-gift-manager/Dockerfile b/steam-gift-manager/Dockerfile index 681e017..ee654d4 100644 --- a/steam-gift-manager/Dockerfile +++ b/steam-gift-manager/Dockerfile @@ -2,7 +2,7 @@ FROM python:3.10-slim SHELL ["/bin/bash", "-c"] -RUN apt-get update && apt-get install -y --no-install-recommends wget && mkdir -p /app/static && wget -O /app/static/logo.png "https://git.nocci.it/nocci/GiftGamesDB/raw/branch/main/steam-gift-manager/static/logo.png" && wget -O /app/static/logo_small.png "https://git.nocci.it/nocci/GiftGamesDB/raw/branch/main/steam-gift-manager/static/logo_small.png" && wget -O /app/static/forgejo.svg "https://git.nocci.it/nocci/GiftGamesDB/raw/branch/main/steam-gift-manager/static/forgejo.svg" && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -y --no-install-recommends wget && mkdir -p /app/static && wget -O /app/static/logo.webp "https://drop.nocadmin.net/logo.webp" && wget -O /app/static/logo_small.webp "https://drop.nocadmin.net/logo_small.webp" && wget -O /app/static/forgejo.webp "https://drop.nocadmin.net/forgejo.webp" && wget -O /app/static/gog_logo.webp "https://drop.nocadmin.net/gog_logo.webp" && wget -O /app/static/logo_small_maskable.webp "https://drop.nocadmin.net/logo_small_maskable.webp" && rm -rf /var/lib/apt/lists/* RUN mkdir -p /app/data && chown -R 1000:1000 /app/data diff --git a/steam-gift-manager/app.py b/steam-gift-manager/app.py index a32caca..64cf1a7 100644 --- a/steam-gift-manager/app.py +++ b/steam-gift-manager/app.py @@ -1,16 +1,15 @@ import os -import logging import warnings from sqlalchemy.exc import LegacyAPIWarning warnings.simplefilter("ignore", category=LegacyAPIWarning) from flask import Flask, render_template, request, redirect, url_for, flash, make_response, session, abort, send_file, jsonify from flask_sqlalchemy import SQLAlchemy from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user -from flask_babel import Babel, _ from werkzeug.security import generate_password_hash, check_password_hash from datetime import datetime, timedelta from flask_wtf import CSRFProtect from flask import abort +from flask import request, redirect import io import warnings import re @@ -41,8 +40,39 @@ from reportlab.lib.utils import ImageReader from reportlab.lib.units import cm, inch, mm from io import BytesIO import reportlab.lib - +import logging +logging.basicConfig() app = Flask(__name__) + +# Load Languages +import os +import json + +TRANSLATION_DIR = os.path.join(os.path.dirname(__file__), 'translations') +SUPPORTED_LANGUAGES = ['de', 'en'] +TRANSLATIONS = {} + +for lang in SUPPORTED_LANGUAGES: + try: + with open(os.path.join(TRANSLATION_DIR, f'{lang}.json'), encoding='utf-8') as f: + TRANSLATIONS[lang] = json.load(f) + except Exception: + TRANSLATIONS[lang] = {} + +def translate(key, lang=None, **kwargs): + if not lang: + lang = session.get('lang', 'en') + value = TRANSLATIONS.get(lang, {}).get(key) + if value is None and lang != 'en': + value = TRANSLATIONS.get('en', {}).get(key, key) + else: + value = value or key + return value.format(**kwargs) if kwargs and isinstance(value, str) else value + +## DEBUG Translations +if app.debug: + print(f"Loaded translations for 'de': {TRANSLATIONS.get('de', {})}") + csrf = CSRFProtect(app) convention = { @@ -62,14 +92,16 @@ load_dotenv(override=True) # App-Configuration app.config.update( SECRET_KEY=os.getenv('SECRET_KEY'), - SQLALCHEMY_DATABASE_URI=('sqlite:////app/data/games.db'), + SQLALCHEMY_DATABASE_URI='sqlite:////app/data/games.db', SQLALCHEMY_TRACK_MODIFICATIONS=False, - BABEL_DEFAULT_LOCALE=os.getenv('BABEL_DEFAULT_LOCALE'), - BABEL_SUPPORTED_LOCALES=os.getenv('BABEL_SUPPORTED_LOCALES').split(','), - BABEL_TRANSLATION_DIRECTORIES=os.getenv('BABEL_TRANSLATION_DIRECTORIES'), - SESSION_COOKIE_SECURE=os.getenv('SESSION_COOKIE_SECURE') == 'True', - WTF_CSRF_ENABLED=os.getenv('CSRF_ENABLED') == 'True', - REGISTRATION_ENABLED=os.getenv('REGISTRATION_ENABLED', 'True').lower() == 'true' + SESSION_COOKIE_SECURE=os.getenv('SESSION_COOKIE_SECURE', 'False') == 'True', + SESSION_COOKIE_SAMESITE='Lax', + PERMANENT_SESSION_LIFETIME=timedelta(days=30), + SESSION_REFRESH_EACH_REQUEST=False, + WTF_CSRF_ENABLED=os.getenv('CSRF_ENABLED', 'True') == 'True', + REGISTRATION_ENABLED=os.getenv('REGISTRATION_ENABLED', 'True').lower() == 'true', + SEND_FILE_MAX_AGE_DEFAULT=int(os.getenv('SEND_FILE_MAX_AGE_DEFAULT', 0)), + TEMPLATES_AUTO_RELOAD=os.getenv('TEMPLATES_AUTO_RELOAD', 'True') == 'True' ) interval_hours = int(os.getenv('CHECK_EXPIRING_KEYS_INTERVAL_HOURS', 12)) @@ -79,24 +111,28 @@ db = SQLAlchemy(app, metadata=metadata) migrate = Migrate(app, db) login_manager = LoginManager(app) login_manager.login_view = 'login' -babel = Babel(app) # Logging app.logger.addHandler(logging.StreamHandler()) app.logger.setLevel(logging.INFO) -@babel.localeselector -def get_locale(): - if 'lang' in session and session['lang'] in app.config['BABEL_SUPPORTED_LOCALES']: - return session['lang'] - return request.accept_languages.best_match(app.config['BABEL_SUPPORTED_LOCALES']) + +@app.before_request +def enforce_https(): + if os.getenv('FORCE_HTTPS', 'False').lower() == 'true': + if request.headers.get('X-Forwarded-Proto', 'http') != 'https' and not request.is_secure: + url = request.url.replace('http://', 'https://', 1) + app.logger.info(f"Redirecting to HTTPS: {url}") + return redirect(url, code=301) + @app.context_processor def inject_template_vars(): - return dict( - get_locale=get_locale, - theme='dark' if request.cookies.get('dark_mode') == 'true' else 'light' - ) + def _(key, **kwargs): + lang = session.get('lang', 'en') + return translate(key, lang, **kwargs) + theme = request.cookies.get('theme', 'light') + return dict(_=_, theme=theme) # DB Models class User(db.Model, UserMixin): @@ -163,14 +199,15 @@ def index(): @app.route('/set-lang/') def set_lang(lang): - if lang in app.config['BABEL_SUPPORTED_LOCALES']: + if lang in SUPPORTED_LANGUAGES: session['lang'] = lang return redirect(request.referrer or url_for('index')) - + @app.route('/set-theme/') def set_theme(theme): resp = make_response('', 204) - resp.set_cookie('dark_mode', 'true' if theme == 'dark' else 'false', max_age=60*60*24*365) + # Von 'dark_mode' zu 'theme' ändern + resp.set_cookie('theme', theme, max_age=60*60*24*365) return resp @app.route('/login', methods=['GET', 'POST']) @@ -190,7 +227,7 @@ def login(): @app.route('/register', methods=['GET', 'POST']) def register(): if not app.config['REGISTRATION_ENABLED']: - flash(_('Registrierungen sind deaktiviert'), 'danger') + flash(_('No new registrations. They are deactivated!'), 'danger') return redirect(url_for('login')) if request.method == 'POST': @@ -224,16 +261,16 @@ def change_password(): confirm_password = request.form['confirm_password'] if not check_password_hash(current_user.password, current_password): - flash(_('Aktuelles Passwort ist falsch'), 'danger') + flash(_('Current passwort is wrong'), 'danger') return redirect(url_for('change_password')) if new_password != confirm_password: - flash(_('Neue Passwörter stimmen nicht überein'), 'danger') + flash(_('New Passwords are not matching'), 'danger') return redirect(url_for('change_password')) current_user.password = generate_password_hash(new_password) db.session.commit() - flash(_('Passwort erfolgreich geändert'), 'success') + flash(_('Password changed successfully'), 'success') return redirect(url_for('index')) return render_template('change_password.html') @@ -421,6 +458,12 @@ def export_pdf(): img = Image(img_data, width=3*cm, height=img_height) except Exception: img = Paragraph('', styles['Normal']) + elif game.url and 'gog.com' in game.url: + try: + img_path = os.path.join(app.root_path, 'static', 'gog_logo.webp') + img = Image(img_path, width=3*cm, height=img_height) + except Exception: + img = Paragraph('', styles['Normal']) data.append([ img or '', @@ -429,7 +472,7 @@ def export_pdf(): game.redeem_date.strftime('%d.%m.%y') if game.redeem_date else '' ]) - # Table format + # Table format (korrekte Einrückung) table = Table(data, colWidths=col_widths, repeatRows=1) table.setStyle(TableStyle([ ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'), @@ -445,13 +488,14 @@ def export_pdf(): doc.build(elements) buffer.seek(0) - return send_file( + return send_file( buffer, mimetype='application/pdf', as_attachment=True, download_name=f'game_export_{datetime.now().strftime("%Y%m%d")}.pdf' ) + @app.route('/import', methods=['GET', 'POST']) @login_required def import_games(): @@ -491,15 +535,15 @@ def import_games(): db.session.commit() - flash(_('%(new)d neue Spiele importiert, %(dup)d Duplikate übersprungen', new=new_games, dup=duplicates), 'success') + flash(_('%(new)d new games imported, %(dup)d skipped duplicates', new=new_games, dup=duplicates), 'success') except Exception as e: db.session.rollback() - flash(_('Importfehler: %(error)s', error=str(e)), 'danger') + flash(_('Import error: %(error)s', error=str(e)), 'danger') return redirect(url_for('index')) - flash(_('Bitte eine gültige CSV-Datei hochladen.'), 'danger') + flash(_('Please upload a valid CSV file.'), 'danger') return render_template('import.html') @@ -557,81 +601,29 @@ def redeem_page(token): redeem_token=redeem_token, platform_link='https://store.steampowered.com/account/registerkey?key=' if game.steam_appid else 'https://www.gog.com/redeem') -# Benachrichtigungsfunktionen -def send_pushover_notification(user, game): - """Sendet Pushover-Benachrichtigung für ablaufenden Key""" - if not app.config['PUSHOVER_APP_TOKEN'] or not app.config['PUSHOVER_USER_KEY']: - return False - - payload = { - "token": os.getenv('PUSHOVER_APP_TOKEN'), - "user": os.getenv('PUSHOVER_USER_KEY'), - "title": "Steam-Key läuft ab!", - "message": f"Dein Key für '{game.name}' läuft in weniger als 48 Stunden ab!", - "url": url_for('edit_game', game_id=game.id, _external=True), - "url_title": "Zum Spiel", - "priority": 1 - } - - try: - response = requests.post( - 'https://api.pushover.net/1/messages.json', - data=payload - ) - return response.status_code == 200 - except Exception as e: - app.logger.error(f"Pushover error: {str(e)}") +# Apprise Notifications +import apprise + +def send_apprise_notification(user, game): + apprise_urls = os.getenv('APPRISE_URLS', '').strip() + if not apprise_urls: + app.logger.error("No APPRISE_URLS configured") return False -def send_gotify_notification(user, game): - """Sendet Gotify-Benachrichtigung für ablaufenden Key""" - if not GOTIFY_URL or not GOTIFY_TOKEN: - return False - - payload = { - "title": "Steam-Key läuft ab!", - "message": f"Dein Key für '{game.name}' läuft in weniger als 48 Stunden ab!", - "priority": 5 - } - - try: - response = requests.post( - f"{GOTIFY_URL}/message?token={GOTIFY_TOKEN}", - json=payload - ) - return response.status_code == 200 - except Exception as e: - app.logger.error(f"Gotify error: {str(e)}") - return False + apobj = apprise.Apprise() + for url in apprise_urls.replace(',', '\n').splitlines(): + if url.strip(): + apobj.add(url.strip()) -def send_matrix_notification(user, game): - """Sendet Matrix-Benachrichtigung für ablaufenden Key""" - if not MATRIX_HOMESERVER or not MATRIX_ACCESS_TOKEN or not MATRIX_ROOM_ID: - return False - - try: - from matrix_client.client import MatrixClient - - client = MatrixClient(MATRIX_HOMESERVER, token=MATRIX_ACCESS_TOKEN) - room = client.join_room(MATRIX_ROOM_ID) - - message = f"🎮 Dein Key für '{game.name}' läuft in weniger als 48 Stunden ab!" - room.send_text(message) - - return True - except Exception as e: - app.logger.error(f"Matrix error: {str(e)}") - return False + edit_url = url_for('edit_game', game_id=game.id, _external=True) + result = apobj.notify( + title="Steam-Key läuft ab!", + body=f"Dein Key für '{game.name}' läuft in weniger als 48 Stunden ab!\n\nLink: {edit_url}", + ) + return result def send_notification(user, game): - """Sendet Benachrichtigung über den bevorzugten Dienst des Benutzers""" - if user.notification_service == 'pushover': - return send_pushover_notification(user, game) - elif user.notification_service == 'gotify': - return send_gotify_notification(user, game) - elif user.notification_service == 'matrix': - return send_matrix_notification(user, game) - return False + return send_apprise_notification(user, game) def check_expiring_keys(): with app.app_context(): diff --git a/steam-gift-manager/babel.cfg b/steam-gift-manager/babel.cfg deleted file mode 100644 index f0234b3..0000000 --- a/steam-gift-manager/babel.cfg +++ /dev/null @@ -1,3 +0,0 @@ -[python: **.py] -[jinja2: **/templates/**.html] -extensions=jinja2.ext.autoescape,jinja2.ext.with_ diff --git a/steam-gift-manager/docker-compose.yml b/steam-gift-manager/docker-compose.yml index d4ad381..0840c1d 100644 --- a/steam-gift-manager/docker-compose.yml +++ b/steam-gift-manager/docker-compose.yml @@ -8,7 +8,8 @@ services: - TZ= volumes: - ../data:/app/data - - ../translations:/app/translations + - ./translations:/app/translations:rw - ../.env:/app/.env - user: "1000:1000" + user: "0:" restart: unless-stopped + diff --git a/steam-gift-manager/requirements.txt b/steam-gift-manager/requirements.txt index b909030..01baa3b 100644 --- a/steam-gift-manager/requirements.txt +++ b/steam-gift-manager/requirements.txt @@ -5,13 +5,12 @@ flask-migrate werkzeug python-dotenv flask-sqlalchemy -flask-babel jinja2<3.1.0 itsdangerous sqlalchemy apscheduler -matrix-client reportlab requests pillow gunicorn +apprise diff --git a/steam-gift-manager/static/forgejo.svg b/steam-gift-manager/static/forgejo.svg deleted file mode 100644 index 804b05e..0000000 --- a/steam-gift-manager/static/forgejo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/steam-gift-manager/static/forgejo.webp b/steam-gift-manager/static/forgejo.webp deleted file mode 100644 index 34d45aa..0000000 Binary files a/steam-gift-manager/static/forgejo.webp and /dev/null differ diff --git a/steam-gift-manager/static/gog_logo.png b/steam-gift-manager/static/gog_logo.png deleted file mode 100644 index f05c336..0000000 Binary files a/steam-gift-manager/static/gog_logo.png and /dev/null differ diff --git a/steam-gift-manager/static/gog_logo.webp b/steam-gift-manager/static/gog_logo.webp deleted file mode 100644 index ce9a8a9..0000000 Binary files a/steam-gift-manager/static/gog_logo.webp and /dev/null differ diff --git a/steam-gift-manager/static/logo.png b/steam-gift-manager/static/logo.png deleted file mode 100644 index 1e09159..0000000 Binary files a/steam-gift-manager/static/logo.png and /dev/null differ diff --git a/steam-gift-manager/static/logo.webp b/steam-gift-manager/static/logo.webp deleted file mode 100644 index 7196e01..0000000 Binary files a/steam-gift-manager/static/logo.webp and /dev/null differ diff --git a/steam-gift-manager/static/logo_small.png b/steam-gift-manager/static/logo_small.png deleted file mode 100644 index 5db0156..0000000 Binary files a/steam-gift-manager/static/logo_small.png and /dev/null differ diff --git a/steam-gift-manager/static/logo_small.webp b/steam-gift-manager/static/logo_small.webp deleted file mode 100644 index 424e4bb..0000000 Binary files a/steam-gift-manager/static/logo_small.webp and /dev/null differ diff --git a/steam-gift-manager/static/logo_small_maskable.png b/steam-gift-manager/static/logo_small_maskable.png deleted file mode 100644 index b0947a1..0000000 Binary files a/steam-gift-manager/static/logo_small_maskable.png and /dev/null differ diff --git a/steam-gift-manager/static/logo_small_maskable.webp b/steam-gift-manager/static/logo_small_maskable.webp deleted file mode 100644 index 8ac87ad..0000000 Binary files a/steam-gift-manager/static/logo_small_maskable.webp and /dev/null differ diff --git a/steam-gift-manager/static/manifest.json b/steam-gift-manager/static/manifest.json new file mode 100644 index 0000000..56e7189 --- /dev/null +++ b/steam-gift-manager/static/manifest.json @@ -0,0 +1,34 @@ +{ + "id": "/", + "name": "Game Key Manager", + "short_name": "GameKeys", + "start_url": "/", + "display": "standalone", + "background_color": "#212529", + "theme_color": "#212529", + "description": "Manage Steam/GOG keys easily!", + "orientation": "any", + "launch_handler": { + "client_mode": "navigate-existing" + }, + "icons": [ + { + "src": "/static/logo_small.webp", + "sizes": "192x192", + "type": "image/webp", + "purpose": "any" + }, + { + "src": "/static/logo_small_maskable.webp", + "sizes": "192x192", + "type": "image/webp", + "purpose": "maskable" + }, + { + "src": "/static/logo.webp", + "sizes": "512x512", + "type": "image/webp", + "purpose": "any maskable" + } + ] +} diff --git a/steam-gift-manager/static/serviceworker.js b/steam-gift-manager/static/serviceworker.js new file mode 100644 index 0000000..4fc266b --- /dev/null +++ b/steam-gift-manager/static/serviceworker.js @@ -0,0 +1,32 @@ +const CACHE_NAME = 'game-key-manager-v2'; +const ASSETS = [ + '/', + '/static/style.css', + '/static/logo.webp', + '/static/logo_small.webp', + '/static/gog_logo.webp', + '/static/forgejo.webp' +]; + +self.addEventListener('install', (event) => { + event.waitUntil( + caches.open(CACHE_NAME) + .then(cache => cache.addAll(ASSETS)) + ); +}); + +self.addEventListener('fetch', (event) => { + event.respondWith( + caches.match(event.request) + .then(cachedResponse => cachedResponse || fetch(event.request)) + ); +}); + +self.addEventListener('activate', (event) => { + event.waitUntil( + caches.keys().then(keys => Promise.all( + keys.filter(key => key !== CACHE_NAME) + .map(key => caches.delete(key)) + )) + ); +}); diff --git a/steam-gift-manager/static/style.css b/steam-gift-manager/static/style.css index e8c608f..c056d1d 100644 --- a/steam-gift-manager/static/style.css +++ b/steam-gift-manager/static/style.css @@ -60,3 +60,76 @@ body { .table-pdf td, .table-pdf th { padding: 4px 8px; } + +.badge.bg-warning { + background-color: #ffcc00 !important; + color: #222 !important; +} +.badge.bg-success { + background-color: #198754 !important; + color: #fff !important; +} + + +.game-cover { + width: 368px; + height: 172px; + max-width: 100%; + max-height: 35vw; + object-fit: contain; + background: #222; + border-radius: 8px; + display: block; + margin: 0 auto; + transition: width 0.2s, height 0.2s; +} + +/* Responsive Cover Images */ +.game-cover { + width: 368px; + height: 172px; + object-fit: contain; + background: #222; + border-radius: 6px; +} + +@media (max-width: 1200px) { + .game-cover { + width: 260px; + height: 122px; + } +} + +@media (max-width: 992px) { + .game-cover { + width: 180px; + height: 84px; + } +} + +@media (max-width: 768px) { + .game-cover { + width: 120px; + height: 56px; + } +} + +@media (max-width: 576px) { + .game-cover { + width: 90px; + height: 42px; + } +} + +/* Accessibility Improvements */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} + diff --git a/steam-gift-manager/templates/add_game.html b/steam-gift-manager/templates/add_game.html index 081aeaa..65ad86c 100644 --- a/steam-gift-manager/templates/add_game.html +++ b/steam-gift-manager/templates/add_game.html @@ -2,40 +2,44 @@ {% block content %}

{{ _('Add New Game') }}

-
- + +
- - + +
- - + +
- -
- - + +
- - + + +
+
+ + +
+
+ +
- - -
-
- - + +
diff --git a/steam-gift-manager/templates/base.html b/steam-gift-manager/templates/base.html index ec5b8c4..1f112fa 100644 --- a/steam-gift-manager/templates/base.html +++ b/steam-gift-manager/templates/base.html @@ -1,51 +1,81 @@ - + + + + {{ _('Game Key Manager') }} - + + + + + {# LCP-Optimierung: Preload für das erste Cover-Bild, falls vorhanden #} + {% if games and games[0].steam_appid %} + + {% endif %} +
{% include "footer.html" %} diff --git a/steam-gift-manager/templates/change_password.html b/steam-gift-manager/templates/change_password.html index 7d6943c..ca3f406 100644 --- a/steam-gift-manager/templates/change_password.html +++ b/steam-gift-manager/templates/change_password.html @@ -1,22 +1,28 @@ {% extends "base.html" %} {% block content %} -
-

{{ _('Change Password') }}

-
+
+
+
+

{{ _('Change Password') }}

+
- - + +
- - + +
- - + +
- + {{ _('Cancel') }} + +
+
{% endblock %} + diff --git a/steam-gift-manager/templates/edit_game.html b/steam-gift-manager/templates/edit_game.html index 63e5384..81db0bd 100644 --- a/steam-gift-manager/templates/edit_game.html +++ b/steam-gift-manager/templates/edit_game.html @@ -1,66 +1,67 @@ {% extends "base.html" %} {% block content %}
-

{{ _('Edit Game') }}

-
- -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- {% if redeem_url and active_redeem %} -
- - - - {{ _('Expires at') }}: {{ active_redeem.expires.strftime('%d.%m.%Y %H:%M') }} - -
- {% endif %} -
-
- - {{ _('Cancel') }} -
+

{{ _('Edit Game') }}

+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ {% if redeem_url and active_redeem %} +
+ + + + {{ _('Expires at') }}: {{ active_redeem.expires.strftime('%d.%m.%Y %H:%M') }} +
- + {% endif %} +
+
+ + {{ _('Cancel') }} +
+
+
{% endblock %} diff --git a/steam-gift-manager/templates/footer.html b/steam-gift-manager/templates/footer.html index 4f0d5fa..fdf3d9f 100644 --- a/steam-gift-manager/templates/footer.html +++ b/steam-gift-manager/templates/footer.html @@ -5,7 +5,7 @@
diff --git a/steam-gift-manager/templates/import.html b/steam-gift-manager/templates/import.html index 9abcc22..79dc283 100644 --- a/steam-gift-manager/templates/import.html +++ b/steam-gift-manager/templates/import.html @@ -5,11 +5,11 @@
- +
- - {{ _('Abbrechen') }} + + {{ _('Cancel') }}
{% endblock %} diff --git a/steam-gift-manager/templates/index.html b/steam-gift-manager/templates/index.html index ff6b87b..f9398a1 100644 --- a/steam-gift-manager/templates/index.html +++ b/steam-gift-manager/templates/index.html @@ -31,7 +31,19 @@ {% if game.steam_appid %} Steam Header + alt="Steam Header" + class="game-cover" + {% if loop.first %}fetchpriority="high"{% endif %} + width="368" + height="172" + loading="lazy"> + {% elif game.url and 'gog.com' in game.url %} + GOG Logo {% endif %} {{ game.name }} diff --git a/steam-gift-manager/templates/login.html b/steam-gift-manager/templates/login.html index 0003326..0c0ccb7 100644 --- a/steam-gift-manager/templates/login.html +++ b/steam-gift-manager/templates/login.html @@ -1,29 +1,43 @@ {% extends "base.html" %} {% block content %} -
-
-
-
- Logo -

{{ _('Login') }}

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

{{ _('Login') }}

+
+ +
+ + +
+
+ + +
+ {% if error %} + + {% endif %} + +
+ +
{% endblock %} + diff --git a/steam-gift-manager/templates/register.html b/steam-gift-manager/templates/register.html index 40d6d62..b9b7ee0 100644 --- a/steam-gift-manager/templates/register.html +++ b/steam-gift-manager/templates/register.html @@ -1,24 +1,51 @@ {% extends "base.html" %} {% block content %} -
-
-
-
-

{{ _('Register') }}

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

{{ _('Register') }}

+
+ +
+ + +
+
+ + +
+
+ + +
+ {% if error %} + + {% endif %} + +
+ +
{% endblock %} + diff --git a/steam-gift-manager/translations/de.json b/steam-gift-manager/translations/de.json new file mode 100644 index 0000000..0f3b89d --- /dev/null +++ b/steam-gift-manager/translations/de.json @@ -0,0 +1,71 @@ +{ + "": "", + "Actions": "Aktionen", + "Active Redeem Link": "Aktiver Einlöse-Link", + "Add New Game": "Neues Spiel hinzufügen", + "Already have an account? Login!": "", + "Cancel": "Abbrechen", + "Change Password": "Passwort ändern", + "Change password form": "", + "Changes saved!": "Änderungen gespeichert!", + "Confirm New Password": "Neues Passwort bestätigen", + "Confirm Password": "", + "Cover": "Cover", + "Created": "Erstellt", + "Current Password": "Aktuelles Passwort", + "Current passwort is wrong": "Aktuelles Passwort ist falsch", + "Dark Mode": "Dunkler Modus", + "Edit Game": "Spiel bearbeiten", + "Error generating link": "Fehler beim Generieren des Links", + "Error: ": "Fehler: ", + "Expires at": "Ablaufdatum", + "Export CSV": "CSV exportieren", + "Game Key": "Spiele-Key", + "Game Key Manager": "Game-Key-Verwaltung", + "Game List (without Keys)": "Spieleliste (ohne Keys)", + "Game added successfully!": "Spiel erfolgreich hinzugefügt!", + "Generate redeem link": "Einlöse-Link generieren", + "Gifted": "Verschenkt", + "Import": "Importieren", + "Import CSV": "CSV importieren", + "Import Games": "Spiele importieren", + "Import error: %(error)s', error=str(e)), 'danger": "", + "Invalid credentials": "Ungültige Anmeldedaten", + "Key": "Key", + "Login": "Anmelden", + "Login form": "", + "Logout": "Abmelden", + "My Games": "Meine Spiele", + "Name": "Name", + "New Password": "Neues Passwort", + "New Passwords are not matching": "Neue Passwörter stimmen nicht überein", + "No account? Register here!": "", + "No games yet": "Der Kornspeicher ist leer, Sire!", + "No new registrations. They are deactivated!": "Keine neuen Registrierungen. Sie sind deaktiviert!", + "Not redeemed": "Nicht eingelöst", + "Notes": "Notizen", + "Password": "Passwort", + "Password changed successfully": "Passwort erfolgreich geändert", + "Please upload a valid CSV file.": "Bitte eine gültige CSV-Datei hochladen.", + "Really delete?": "Wirklich löschen?", + "Recipient": "Empfänger", + "Redeem by": "Einzulösen vor", + "Redeem link copied to clipboard!": "Einlöse-Link in die Zwischenablage kopiert!", + "Redeem now on": "Jetzt einlösen bei", + "Redeemed": "Eingelöst", + "Register": "Registrieren", + "Registration form": "", + "Save": "Speichern", + "Search": "Suche", + "Search games": "", + "Select CSV file": "CSV-Datei auswählen", + "Shop": "Shop", + "Shop URL": "Shop-URL", + "Status": "Status", + "Steam AppID (optional)": "Steam-AppID (optional)", + "Steam Key already exists!": "Steam-Key existiert bereits!", + "This page will expire in": "Diese Seite läuft ab in", + "Username": "Benutzername", + "Username already exists": "Benutzername existiert bereits", + "Your Key:": "Dein Key:" +} diff --git a/steam-gift-manager/translations/en.json b/steam-gift-manager/translations/en.json new file mode 100644 index 0000000..243f316 --- /dev/null +++ b/steam-gift-manager/translations/en.json @@ -0,0 +1,72 @@ +{ + "": "", + "Actions": "", + "Active Redeem Link": "", + "Add New Game": "", + "Already have an account? Login!": "", + "Cancel": "", + "Change Password": "", + "Change password form": "", + "Changes saved!": "", + "Confirm New Password": "", + "Confirm Password": "", + "Cover": "", + "Created": "", + "Current Password": "", + "Current passwort is wrong": "", + "Dark Mode": "", + "Edit Game": "", + "Error: ": "", + "Error generating link": "", + "Expires at": "", + "Export CSV": "", + "Game added successfully!": "", + "Game Key": "", + "Game Key Manager": "", + "Game List (without Keys)": "", + "Generate redeem link": "", + "Gifted": "", + "Import": "", + "Import CSV": "", + "Import error: %(error)s', error=str(e)), 'danger": "", + "Import Games": "", + "Invalid credentials": "", + "Key": "", + "Login": "", + "Login form": "", + "Logout": "", + "My Games": "", + "Name": "", + "%(new)d new games imported, %(dup)d skipped duplicates', new=new_games, dup=duplicates), 'success": "", + "New Password": "", + "New Passwords are not matching": "", + "No account? Register here!": "", + "No games yet": "", + "No new registrations. They are deactivated!": "", + "Notes": "", + "Not redeemed": "", + "Password": "", + "Password changed successfully": "", + "Please upload a valid CSV file.": "", + "Really delete?": "", + "Recipient": "", + "Redeem by": "", + "Redeemed": "", + "Redeem link copied to clipboard!": "", + "Redeem now on": "", + "Register": "", + "Registration form": "", + "Save": "", + "Search": "", + "Search games": "", + "Select CSV file": "", + "Shop": "", + "Shop URL": "", + "Status": "", + "Steam AppID (optional)": "", + "Steam Key already exists!": "", + "This page will expire in": "", + "Username": "", + "Username already exists": "", + "Your Key:": "" +} diff --git a/translate.sh b/translate.sh index 75e21e4..65b52bb 100755 --- a/translate.sh +++ b/translate.sh @@ -1,28 +1,41 @@ #!/bin/bash set -e -cd "$(dirname "$0")/steam-gift-manager" +APP_DIR="steam-gift-manager" +TRANSLATION_DIR="$APP_DIR/translations" +LANGS=("de" "en") -declare -A locales=( - ["de"]="de" - ["en"]="en" -) +# Prüfe jq +if ! command -v jq &>/dev/null; then + echo "❌ jq is required. Install with: sudo apt-get install jq" + exit 1 +fi -# create POT-file -docker-compose exec steam-manager pybabel extract -F babel.cfg -o translations/messages.pot . - -# Check for each language and initialize if necessary -for lang in "${!locales[@]}"; do - if [ ! -f "translations/${locales[$lang]}/LC_MESSAGES/messages.po" ]; then - docker-compose exec steam-manager pybabel init \ - -i translations/messages.pot \ - -d translations \ - -l "${locales[$lang]}" +# 1. Lege JSON-Dateien an, falls sie fehlen +for lang in "${LANGS[@]}"; do + file="$TRANSLATION_DIR/$lang.json" + if [ ! -f "$file" ]; then + echo "{}" > "$file" + echo "Created $file" fi done -# Update and compile translations -docker-compose exec steam-manager pybabel update -i translations/messages.pot -d translations -docker-compose exec steam-manager pybabel compile -d translations +# 2. Extrahiere alle zu übersetzenden Strings +STRINGS=$(grep -rhoP "_\(\s*['\"](.+?)['\"]\s*\)" \ + "$APP_DIR/templates" "$APP_DIR/app.py" | \ + sed -E "s/_\(\s*['\"](.+?)['\"]\s*\)/\1/" | sort | uniq) -echo "✅ Translations updated!" +# 3. Ergänze neue Keys in die JSON-Dateien +for lang in "${LANGS[@]}"; do + file="$TRANSLATION_DIR/$lang.json" + tmp="$file.tmp" + cp "$file" "$tmp" + while IFS= read -r key; do + if ! jq -e --arg k "$key" 'has($k)' "$tmp" >/dev/null; then + jq --arg k "$key" '. + {($k): ""}' "$tmp" > "$tmp.new" && mv "$tmp.new" "$tmp" + fi + done <<< "$STRINGS" + mv "$tmp" "$file" + echo "Updated $file" +done +echo "✅ JSON translation files updated. Please enter your translations!" diff --git a/translations/de/LC_MESSAGES/messages.mo b/translations/de/LC_MESSAGES/messages.mo deleted file mode 100644 index 7eaa6c9..0000000 Binary files a/translations/de/LC_MESSAGES/messages.mo and /dev/null differ diff --git a/translations/de/LC_MESSAGES/messages.po b/translations/de/LC_MESSAGES/messages.po deleted file mode 100644 index aa6b016..0000000 --- a/translations/de/LC_MESSAGES/messages.po +++ /dev/null @@ -1,274 +0,0 @@ -# German translations for PROJECT. -# Copyright (C) 2025 ORGANIZATION -# This file is distributed under the same license as the PROJECT project. -# FIRST AUTHOR , 2025. -# -msgid "" -msgstr "" -"Project-Id-Version: PROJECT VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2025-04-29 15:53+0000\n" -"PO-Revision-Date: 2025-04-29 15:42+0000\n" -"Last-Translator: FULL NAME \n" -"Language: de\n" -"Language-Team: de \n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.17.0\n" - -#: app.py:194 -msgid "Invalid credentials" -msgstr "Ungültige Anmeldedaten" - -#: app.py:200 -msgid "No new registrations. They are deactivated!" -msgstr "Keine neuen Registrierungen. Sie sind deaktiviert!" - -#: app.py:208 -msgid "Username already exists" -msgstr "Benutzername existiert bereits" - -#: app.py:234 -msgid "Current passwort is wrong" -msgstr "Aktuelles Passwort ist falsch" - -#: app.py:238 -msgid "New Passwords are not matching" -msgstr "Neue Passwörter stimmen nicht überein" - -#: app.py:243 -msgid "Password changed successfully" -msgstr "Passwort erfolgreich geändert" - -#: app.py:273 -msgid "Game added successfully!" -msgstr "Spiel erfolgreich hinzugefügt!" - -#: app.py:278 -msgid "Steam Key already exists!" -msgstr "Steam-Key existiert bereits!" - -#: app.py:281 app.py:325 -msgid "Error: " -msgstr "Fehler: " - -#: app.py:320 -msgid "Changes saved!" -msgstr "Änderungen gespeichert!" - -#: app.py:408 -msgid "Game List (without Keys)" -msgstr "Spieleliste (ohne Keys)" - -#: app.py:501 -#, python-format -msgid "%(new)d new games imported, %(dup)d skipped duplicates" -msgstr "%(new)d neue Spiele importiert, %(dup)d Duplikate übersprungen" - -#: app.py:505 -#, python-format -msgid "Import error: %(error)s" -msgstr "Importfehler: %(error)s" - -#: app.py:509 -msgid "Please upload a valid CSV file." -msgstr "Bitte eine gültige CSV-Datei hochladen." - -#: templates/add_game.html:4 templates/index.html:9 -msgid "Add New Game" -msgstr "Neues Spiel hinzufügen" - -#: templates/add_game.html:9 templates/edit_game.html:9 templates/index.html:19 -msgid "Name" -msgstr "Name" - -#: templates/add_game.html:13 templates/edit_game.html:13 -msgid "Game Key" -msgstr "Spiele-Key" - -#: templates/add_game.html:17 templates/edit_game.html:21 templates/index.html:21 -msgid "Status" -msgstr "Status" - -#: templates/add_game.html:19 templates/edit_game.html:23 templates/index.html:41 -msgid "Not redeemed" -msgstr "Nicht eingelöst" - -#: templates/add_game.html:20 templates/edit_game.html:24 templates/index.html:43 -msgid "Gifted" -msgstr "Verschenkt" - -#: templates/add_game.html:21 templates/edit_game.html:25 templates/index.html:45 -msgid "Redeemed" -msgstr "Eingelöst" - -#: templates/add_game.html:25 templates/edit_game.html:29 templates/index.html:23 -msgid "Redeem by" -msgstr "Einzulösen bis" - -#: templates/add_game.html:29 templates/edit_game.html:33 -msgid "Recipient" -msgstr "Empfänger" - -#: templates/add_game.html:33 templates/edit_game.html:37 -msgid "Shop URL" -msgstr "Shop-URL" - -#: templates/add_game.html:37 templates/edit_game.html:41 -msgid "Notes" -msgstr "Notizen" - -#: templates/add_game.html:41 templates/edit_game.html:60 -msgid "Save" -msgstr "Speichern" - -#: templates/add_game.html:42 templates/edit_game.html:61 templates/import.html:12 -msgid "Cancel" -msgstr "Abbrechen" - -#: templates/base.html:7 -msgid "Game Key Manager" -msgstr "Game-Key-Verwaltung" - -#: templates/base.html:23 -msgid "Search" -msgstr "Suche" - -#: templates/base.html:31 -msgid "Dark Mode" -msgstr "Dunkler Modus" - -#: templates/base.html:46 templates/login.html:16 templates/register.html:15 -msgid "Password" -msgstr "Passwort" - -#: templates/base.html:49 -msgid "Logout" -msgstr "Abmelden" - -#: templates/change_password.html:4 templates/change_password.html:19 -msgid "Change Password" -msgstr "Passwort ändern" - -#: templates/change_password.html:8 -msgid "Current Password" -msgstr "Aktuelles Passwort" - -#: templates/change_password.html:12 -msgid "New Password" -msgstr "Neues Passwort" - -#: templates/change_password.html:16 -msgid "Confirm New Password" -msgstr "Neues Passwort bestätigen" - -#: templates/edit_game.html:4 -msgid "Edit Game" -msgstr "Spiel bearbeiten" - -#: templates/edit_game.html:17 -msgid "Steam AppID (optional)" -msgstr "Steam-AppID (optional)" - -#: templates/edit_game.html:47 -msgid "Active Redeem Link" -msgstr "Aktiver Einlöse-Link" - -#: templates/edit_game.html:54 -msgid "Expires at" -msgstr "Ablaufdatum" - -#: templates/import.html:4 -msgid "Import Games" -msgstr "Spiele importieren" - -#: templates/import.html:8 -msgid "Select CSV file" -msgstr "CSV-Datei auswählen" - -#: templates/import.html:11 -msgid "Import" -msgstr "Importieren" - -#: templates/index.html:4 -msgid "My Games" -msgstr "Meine Spiele" - -#: templates/index.html:6 -msgid "Export CSV" -msgstr "CSV exportieren" - -#: templates/index.html:8 -msgid "Import CSV" -msgstr "CSV importieren" - -#: templates/index.html:18 -msgid "Cover" -msgstr "Cover" - -#: templates/index.html:20 -msgid "Key" -msgstr "Key" - -#: templates/index.html:22 -msgid "Created" -msgstr "Erstellt" - -#: templates/index.html:24 templates/index.html:56 -msgid "Shop" -msgstr "Shop" - -#: templates/index.html:25 -msgid "Actions" -msgstr "Aktionen" - -#: templates/index.html:63 -msgid "Generate redeem link" -msgstr "Einlöse-Link generieren" - -#: templates/index.html:70 -msgid "Really delete?" -msgstr "Wirklich löschen?" - -#: templates/index.html:96 -msgid "Redeem link copied to clipboard!" -msgstr "Einlöse-Link in die Zwischenablage kopiert!" - -#: templates/index.html:100 -msgid "Error generating link" -msgstr "Fehler beim Generieren des Links" - -#: templates/index.html:106 -msgid "No games yet" -msgstr "Der Kornspeicher ist leer, Sire!" - -#: templates/login.html:8 templates/login.html:19 -msgid "Login" -msgstr "Anmelden" - -#: templates/login.html:12 templates/register.html:11 -msgid "Username" -msgstr "Benutzername" - -#: templates/login.html:22 -msgid "No account yet? Register" -msgstr "Noch kein Konto? Jetzt registrieren" - -#: templates/redeem.html:16 -msgid "Your Key:" -msgstr "Dein Key:" - -#: templates/redeem.html:22 -msgid "Redeem now on" -msgstr "Jetzt einlösen bei" - -#: templates/redeem.html:26 -msgid "This page will expire in" -msgstr "Diese Seite läuft ab in" - -#: templates/register.html:7 templates/register.html:18 -msgid "Register" -msgstr "Registrieren" - diff --git a/translations/en/LC_MESSAGES/messages.mo b/translations/en/LC_MESSAGES/messages.mo deleted file mode 100644 index 2cb4216..0000000 Binary files a/translations/en/LC_MESSAGES/messages.mo and /dev/null differ diff --git a/translations/en/LC_MESSAGES/messages.po b/translations/en/LC_MESSAGES/messages.po deleted file mode 100644 index e7a3a4e..0000000 --- a/translations/en/LC_MESSAGES/messages.po +++ /dev/null @@ -1,280 +0,0 @@ -# English translations for PROJECT. -# Copyright (C) 2025 ORGANIZATION -# This file is distributed under the same license as the PROJECT project. -# FIRST AUTHOR , 2025. -# -msgid "" -msgstr "" -"Project-Id-Version: PROJECT VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2025-04-29 15:53+0000\n" -"PO-Revision-Date: 2025-04-29 15:42+0000\n" -"Last-Translator: FULL NAME \n" -"Language: en\n" -"Language-Team: en \n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.17.0\n" - -#: app.py:194 -msgid "Invalid credentials" -msgstr "" - -#: app.py:200 -msgid "No new registrations. They are deactivated!" -msgstr "" - -#: app.py:208 -msgid "Username already exists" -msgstr "" - -#: app.py:234 -msgid "Current passwort is wrong" -msgstr "" - -#: app.py:238 -msgid "New Passwords are not matching" -msgstr "" - -#: app.py:243 -msgid "Password changed successfully" -msgstr "" - -#: app.py:273 -msgid "Game added successfully!" -msgstr "" - -#: app.py:278 -msgid "Steam Key already exists!" -msgstr "" - -#: app.py:281 app.py:325 -msgid "Error: " -msgstr "" - -#: app.py:320 -msgid "Changes saved!" -msgstr "" - -#: app.py:408 -msgid "Game List (without Keys)" -msgstr "" - -#: app.py:501 -#, python-format -msgid "%(new)d new games imported, %(dup)d skipped duplicates" -msgstr "" - -#: app.py:505 -#, python-format -msgid "Import error: %(error)s" -msgstr "" - -#: app.py:509 -msgid "Please upload a valid CSV file." -msgstr "" - -#: templates/add_game.html:4 templates/index.html:9 -msgid "Add New Game" -msgstr "" - -#: templates/add_game.html:9 templates/edit_game.html:9 templates/index.html:19 -msgid "Name" -msgstr "" - -#: templates/add_game.html:13 templates/edit_game.html:13 -msgid "Game Key" -msgstr "" - -#: templates/add_game.html:17 templates/edit_game.html:21 -#: templates/index.html:21 -msgid "Status" -msgstr "" - -#: templates/add_game.html:19 templates/edit_game.html:23 -#: templates/index.html:41 -msgid "Not redeemed" -msgstr "" - -#: templates/add_game.html:20 templates/edit_game.html:24 -#: templates/index.html:43 -msgid "Gifted" -msgstr "" - -#: templates/add_game.html:21 templates/edit_game.html:25 -#: templates/index.html:45 -msgid "Redeemed" -msgstr "" - -#: templates/add_game.html:25 templates/edit_game.html:29 -#: templates/index.html:23 -msgid "Redeem by" -msgstr "" - -#: templates/add_game.html:29 templates/edit_game.html:33 -msgid "Recipient" -msgstr "" - -#: templates/add_game.html:33 templates/edit_game.html:37 -msgid "Shop URL" -msgstr "" - -#: templates/add_game.html:37 templates/edit_game.html:41 -msgid "Notes" -msgstr "" - -#: templates/add_game.html:41 templates/edit_game.html:60 -msgid "Save" -msgstr "" - -#: templates/add_game.html:42 templates/edit_game.html:61 -#: templates/import.html:12 -msgid "Cancel" -msgstr "" - -#: templates/base.html:7 -msgid "Game Key Manager" -msgstr "" - -#: templates/base.html:23 -msgid "Search" -msgstr "" - -#: templates/base.html:31 -msgid "Dark Mode" -msgstr "" - -#: templates/base.html:46 templates/login.html:16 templates/register.html:15 -msgid "Password" -msgstr "" - -#: templates/base.html:49 -msgid "Logout" -msgstr "" - -#: templates/change_password.html:4 templates/change_password.html:19 -msgid "Change Password" -msgstr "" - -#: templates/change_password.html:8 -msgid "Current Password" -msgstr "" - -#: templates/change_password.html:12 -msgid "New Password" -msgstr "" - -#: templates/change_password.html:16 -msgid "Confirm New Password" -msgstr "" - -#: templates/edit_game.html:4 -msgid "Edit Game" -msgstr "" - -#: templates/edit_game.html:17 -msgid "Steam AppID (optional)" -msgstr "" - -#: templates/edit_game.html:47 -msgid "Active Redeem Link" -msgstr "" - -#: templates/edit_game.html:54 -msgid "Expires at" -msgstr "" - -#: templates/import.html:4 -msgid "Import Games" -msgstr "" - -#: templates/import.html:8 -msgid "Select CSV file" -msgstr "" - -#: templates/import.html:11 -msgid "Import" -msgstr "" - -#: templates/index.html:4 -msgid "My Games" -msgstr "" - -#: templates/index.html:6 -msgid "Export CSV" -msgstr "" - -#: templates/index.html:8 -msgid "Import CSV" -msgstr "" - -#: templates/index.html:18 -msgid "Cover" -msgstr "" - -#: templates/index.html:20 -msgid "Key" -msgstr "" - -#: templates/index.html:22 -msgid "Created" -msgstr "" - -#: templates/index.html:24 templates/index.html:56 -msgid "Shop" -msgstr "" - -#: templates/index.html:25 -msgid "Actions" -msgstr "" - -#: templates/index.html:63 -msgid "Generate redeem link" -msgstr "" - -#: templates/index.html:70 -msgid "Really delete?" -msgstr "" - -#: templates/index.html:96 -msgid "Redeem link copied to clipboard!" -msgstr "" - -#: templates/index.html:100 -msgid "Error generating link" -msgstr "" - -#: templates/index.html:106 -msgid "No games yet" -msgstr "" - -#: templates/login.html:8 templates/login.html:19 -msgid "Login" -msgstr "" - -#: templates/login.html:12 templates/register.html:11 -msgid "Username" -msgstr "" - -#: templates/login.html:22 -msgid "No account yet? Register" -msgstr "" - -#: templates/redeem.html:16 -msgid "Your Key:" -msgstr "" - -#: templates/redeem.html:22 -msgid "Redeem now on" -msgstr "" - -#: templates/redeem.html:26 -msgid "This page will expire in" -msgstr "" - -#: templates/register.html:7 templates/register.html:18 -msgid "Register" -msgstr "" - diff --git a/translations/messages.pot b/translations/messages.pot deleted file mode 100644 index 6306a35..0000000 --- a/translations/messages.pot +++ /dev/null @@ -1,279 +0,0 @@ -# Translations template for PROJECT. -# Copyright (C) 2025 ORGANIZATION -# This file is distributed under the same license as the PROJECT project. -# FIRST AUTHOR , 2025. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PROJECT VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2025-04-29 15:53+0000\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.17.0\n" - -#: app.py:194 -msgid "Invalid credentials" -msgstr "" - -#: app.py:200 -msgid "No new registrations. They are deactivated!" -msgstr "" - -#: app.py:208 -msgid "Username already exists" -msgstr "" - -#: app.py:234 -msgid "Current passwort is wrong" -msgstr "" - -#: app.py:238 -msgid "New Passwords are not matching" -msgstr "" - -#: app.py:243 -msgid "Password changed successfully" -msgstr "" - -#: app.py:273 -msgid "Game added successfully!" -msgstr "" - -#: app.py:278 -msgid "Steam Key already exists!" -msgstr "" - -#: app.py:281 app.py:325 -msgid "Error: " -msgstr "" - -#: app.py:320 -msgid "Changes saved!" -msgstr "" - -#: app.py:408 -msgid "Game List (without Keys)" -msgstr "" - -#: app.py:501 -#, python-format -msgid "%(new)d new games imported, %(dup)d skipped duplicates" -msgstr "" - -#: app.py:505 -#, python-format -msgid "Import error: %(error)s" -msgstr "" - -#: app.py:509 -msgid "Please upload a valid CSV file." -msgstr "" - -#: templates/add_game.html:4 templates/index.html:9 -msgid "Add New Game" -msgstr "" - -#: templates/add_game.html:9 templates/edit_game.html:9 templates/index.html:19 -msgid "Name" -msgstr "" - -#: templates/add_game.html:13 templates/edit_game.html:13 -msgid "Game Key" -msgstr "" - -#: templates/add_game.html:17 templates/edit_game.html:21 -#: templates/index.html:21 -msgid "Status" -msgstr "" - -#: templates/add_game.html:19 templates/edit_game.html:23 -#: templates/index.html:41 -msgid "Not redeemed" -msgstr "" - -#: templates/add_game.html:20 templates/edit_game.html:24 -#: templates/index.html:43 -msgid "Gifted" -msgstr "" - -#: templates/add_game.html:21 templates/edit_game.html:25 -#: templates/index.html:45 -msgid "Redeemed" -msgstr "" - -#: templates/add_game.html:25 templates/edit_game.html:29 -#: templates/index.html:23 -msgid "Redeem by" -msgstr "" - -#: templates/add_game.html:29 templates/edit_game.html:33 -msgid "Recipient" -msgstr "" - -#: templates/add_game.html:33 templates/edit_game.html:37 -msgid "Shop URL" -msgstr "" - -#: templates/add_game.html:37 templates/edit_game.html:41 -msgid "Notes" -msgstr "" - -#: templates/add_game.html:41 templates/edit_game.html:60 -msgid "Save" -msgstr "" - -#: templates/add_game.html:42 templates/edit_game.html:61 -#: templates/import.html:12 -msgid "Cancel" -msgstr "" - -#: templates/base.html:7 -msgid "Game Key Manager" -msgstr "" - -#: templates/base.html:23 -msgid "Search" -msgstr "" - -#: templates/base.html:31 -msgid "Dark Mode" -msgstr "" - -#: templates/base.html:46 templates/login.html:16 templates/register.html:15 -msgid "Password" -msgstr "" - -#: templates/base.html:49 -msgid "Logout" -msgstr "" - -#: templates/change_password.html:4 templates/change_password.html:19 -msgid "Change Password" -msgstr "" - -#: templates/change_password.html:8 -msgid "Current Password" -msgstr "" - -#: templates/change_password.html:12 -msgid "New Password" -msgstr "" - -#: templates/change_password.html:16 -msgid "Confirm New Password" -msgstr "" - -#: templates/edit_game.html:4 -msgid "Edit Game" -msgstr "" - -#: templates/edit_game.html:17 -msgid "Steam AppID (optional)" -msgstr "" - -#: templates/edit_game.html:47 -msgid "Active Redeem Link" -msgstr "" - -#: templates/edit_game.html:54 -msgid "Expires at" -msgstr "" - -#: templates/import.html:4 -msgid "Import Games" -msgstr "" - -#: templates/import.html:8 -msgid "Select CSV file" -msgstr "" - -#: templates/import.html:11 -msgid "Import" -msgstr "" - -#: templates/index.html:4 -msgid "My Games" -msgstr "" - -#: templates/index.html:6 -msgid "Export CSV" -msgstr "" - -#: templates/index.html:8 -msgid "Import CSV" -msgstr "" - -#: templates/index.html:18 -msgid "Cover" -msgstr "" - -#: templates/index.html:20 -msgid "Key" -msgstr "" - -#: templates/index.html:22 -msgid "Created" -msgstr "" - -#: templates/index.html:24 templates/index.html:56 -msgid "Shop" -msgstr "" - -#: templates/index.html:25 -msgid "Actions" -msgstr "" - -#: templates/index.html:63 -msgid "Generate redeem link" -msgstr "" - -#: templates/index.html:70 -msgid "Really delete?" -msgstr "" - -#: templates/index.html:96 -msgid "Redeem link copied to clipboard!" -msgstr "" - -#: templates/index.html:100 -msgid "Error generating link" -msgstr "" - -#: templates/index.html:106 -msgid "No games yet" -msgstr "" - -#: templates/login.html:8 templates/login.html:19 -msgid "Login" -msgstr "" - -#: templates/login.html:12 templates/register.html:11 -msgid "Username" -msgstr "" - -#: templates/login.html:22 -msgid "No account yet? Register" -msgstr "" - -#: templates/redeem.html:16 -msgid "Your Key:" -msgstr "" - -#: templates/redeem.html:22 -msgid "Redeem now on" -msgstr "" - -#: templates/redeem.html:26 -msgid "This page will expire in" -msgstr "" - -#: templates/register.html:7 templates/register.html:18 -msgid "Register" -msgstr "" -