feat: make UI strings localisable via LOCALE environment variable

Agent-Logs-Url: https://github.com/wasi-master/13ft/sessions/3b6e6061-c4d2-4aa1-879b-8526ccd3b1db

Co-authored-by: wasi-master <63045920+wasi-master@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-04-02 12:01:51 +00:00
committed by GitHub
co-authored by wasi-master
parent ef12cd0184
commit ce8e8c1664
8 changed files with 165 additions and 16 deletions
+3
View File
@@ -0,0 +1,3 @@
__pycache__
*.pyc
*.pyo
+41 -1
View File
@@ -160,7 +160,47 @@ WantedBy=multi-user.target
</VirtualHost> </VirtualHost>
``` ```
## Screenshots ## Localisation
The UI strings can be localised by setting the `LOCALE` environment variable to a supported locale code before starting the server. Locale files live in `app/locales/<locale>.json`.
**Built-in locales**
| Code | Language |
|------|----------|
| `en` | English (default) |
| `de` | German |
| `fr` | French |
**Running with a different locale**
```sh
# Standard Python
LOCALE=de python portable.py
# Flask dev server
LOCALE=fr FLASK_APP=app/portable.py flask run
# Docker Compose – add to docker-compose.yaml
environment:
- LOCALE=de
```
**Adding a new locale**
Create `app/locales/<code>.json` with the following keys (any keys you omit fall back to English):
```json
{
"heading": "Enter Website Link",
"label": "Link of the website you want to remove paywall for:",
"submit": "Submit",
"toggle_dark_mode": "Toggle Dark Mode",
"invalid_url": "Invalid URL"
}
```
### Step 1 ### Step 1
+4 -4
View File
@@ -144,13 +144,13 @@
<body> <body>
<div class="dark-mode-toggle"> <div class="dark-mode-toggle">
<input type="checkbox" id="dark-mode-toggle"> <input type="checkbox" id="dark-mode-toggle">
<label for="dark-mode-toggle" title="Toggle Dark Mode"></label> <label for="dark-mode-toggle" title="{{ toggle_dark_mode }}"></label>
</div> </div>
<form action="/article" method="post"> <form action="/article" method="post">
<h1>Enter Website Link</h1> <h1>{{ heading }}</h1>
<label for="link">Link of the website you want to remove paywall for:</label> <label for="link">{{ label }}</label>
<input type="text" id="link" name="link" required autofocus> <input type="text" id="link" name="link" required autofocus>
<input type="submit" value="Submit"> <input type="submit" value="{{ submit }}">
</form> </form>
<script> <script>
+47 -3
View File
@@ -1,3 +1,7 @@
import json
import os
import re
import flask import flask
import requests import requests
from flask import request from flask import request
@@ -5,6 +9,43 @@ from bs4 import BeautifulSoup
from urllib.parse import urlparse, urljoin from urllib.parse import urlparse, urljoin
app = flask.Flask(__name__) app = flask.Flask(__name__)
_DEFAULT_STRINGS = {
"heading": "Enter Website Link",
"label": "Link of the website you want to remove paywall for:",
"submit": "Submit",
"toggle_dark_mode": "Toggle Dark Mode",
"invalid_url": "Invalid URL",
}
def load_strings():
"""Load UI strings from a locale JSON file selected by the LOCALE env var.
Falls back to built-in English strings when the locale file is missing or
cannot be parsed. Only alphanumeric characters, hyphens, and underscores
are accepted as locale names to prevent path traversal.
"""
locale = os.environ.get("LOCALE", "en")
if not re.match(r'^[a-zA-Z0-9_-]+$', locale):
locale = "en"
if locale == "en":
return dict(_DEFAULT_STRINGS)
locale_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "locales")
locale_file = os.path.join(locale_dir, f"{locale}.json")
try:
with open(locale_file, "r", encoding="utf-8") as f:
loaded = json.load(f)
return {**_DEFAULT_STRINGS, **loaded}
except (FileNotFoundError, json.JSONDecodeError, OSError):
return dict(_DEFAULT_STRINGS)
strings = load_strings()
googlebot_headers = { googlebot_headers = {
"User-Agent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.119 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" "User-Agent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.119 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
} }
@@ -48,7 +89,10 @@ def bypass_paywall(url):
@app.route("/") @app.route("/")
def main_page(): def main_page():
return flask.send_from_directory(".", "index.html") template_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "index.html")
with open(template_path, "r", encoding="utf-8") as f:
template = f.read()
return flask.render_template_string(template, **strings)
@app.route("/article", methods=["POST"]) @app.route("/article", methods=["POST"])
@@ -73,10 +117,10 @@ def get_article(path):
return bypass_paywall(actual_url) return bypass_paywall(actual_url)
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
return str(e), 400 return str(e), 400
except e: except Exception as e:
raise e raise e
else: else:
return "Invalid URL", 400 return strings["invalid_url"], 400
app.run(debug=False) app.run(debug=False)
+7
View File
@@ -0,0 +1,7 @@
{
"heading": "Website-Link eingeben",
"label": "Link der Website, von der Sie die Paywall entfernen möchten:",
"submit": "Absenden",
"toggle_dark_mode": "Dunkelmodus umschalten",
"invalid_url": "Ungültige URL"
}
+7
View File
@@ -0,0 +1,7 @@
{
"heading": "Enter Website Link",
"label": "Link of the website you want to remove paywall for:",
"submit": "Submit",
"toggle_dark_mode": "Toggle Dark Mode",
"invalid_url": "Invalid URL"
}
+7
View File
@@ -0,0 +1,7 @@
{
"heading": "Entrez le lien du site web",
"label": "Lien du site web dont vous souhaitez supprimer le paywall :",
"submit": "Soumettre",
"toggle_dark_mode": "Basculer en mode sombre",
"invalid_url": "URL invalide"
}
+49 -8
View File
@@ -1,3 +1,7 @@
import json
import os
import re
import flask import flask
import requests import requests
from flask import request from flask import request
@@ -5,6 +9,43 @@ from bs4 import BeautifulSoup
from urllib.parse import urlparse, urljoin from urllib.parse import urlparse, urljoin
app = flask.Flask(__name__) app = flask.Flask(__name__)
_DEFAULT_STRINGS = {
"heading": "Enter Website Link",
"label": "Link of the website you want to remove paywall for:",
"submit": "Submit",
"toggle_dark_mode": "Toggle Dark Mode",
"invalid_url": "Invalid URL",
}
def load_strings():
"""Load UI strings from a locale JSON file selected by the LOCALE env var.
Falls back to built-in English strings when the locale file is missing or
cannot be parsed. Only alphanumeric characters, hyphens, and underscores
are accepted as locale names to prevent path traversal.
"""
locale = os.environ.get("LOCALE", "en")
if not re.match(r'^[a-zA-Z0-9_-]+$', locale):
locale = "en"
if locale == "en":
return dict(_DEFAULT_STRINGS)
locale_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "locales")
locale_file = os.path.join(locale_dir, f"{locale}.json")
try:
with open(locale_file, "r", encoding="utf-8") as f:
loaded = json.load(f)
return {**_DEFAULT_STRINGS, **loaded}
except (FileNotFoundError, json.JSONDecodeError, OSError):
return dict(_DEFAULT_STRINGS)
strings = load_strings()
googlebot_headers = { googlebot_headers = {
"User-Agent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.119 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" "User-Agent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.119 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
} }
@@ -154,13 +195,13 @@ html = """
<body> <body>
<div class="dark-mode-toggle"> <div class="dark-mode-toggle">
<input type="checkbox" id="dark-mode-toggle"> <input type="checkbox" id="dark-mode-toggle">
<label for="dark-mode-toggle" title="Toggle Dark Mode"></label> <label for="dark-mode-toggle" title="{{ toggle_dark_mode }}"></label>
</div> </div>
<form action="/article" method="post"> <form action="/article" method="post">
<h1>Enter Website Link</h1> <h1>{{ heading }}</h1>
<label for="link">Link of the website you want to remove paywall for:</label> <label for="link">{{ label }}</label>
<input type="text" id="link" name="link" required autofocus> <input type="text" id="link" name="link" required autofocus>
<input type="submit" value="Submit"> <input type="submit" value="{{ submit }}">
</form> </form>
<script> <script>
@@ -226,7 +267,7 @@ def bypass_paywall(url):
@app.route("/") @app.route("/")
def main_page(): def main_page():
return html return flask.render_template_string(html, **strings)
@app.route("/article", methods=["POST"]) @app.route("/article", methods=["POST"])
@@ -236,7 +277,7 @@ def show_article():
return bypass_paywall(link) return bypass_paywall(link)
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
return str(e), 400 return str(e), 400
except e: except Exception as e:
raise e raise e
@@ -251,10 +292,10 @@ def get_article(path):
return bypass_paywall(actual_url) return bypass_paywall(actual_url)
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
return str(e), 400 return str(e), 400
except e: except Exception as e:
raise e raise e
else: else:
return "Invalid URL", 400 return strings["invalid_url"], 400
app.run(host="0.0.0.0", port=5000, debug=False) app.run(host="0.0.0.0", port=5000, debug=False)