Compare commits

...

2 Commits

Author SHA1 Message Date
dgtlmoon
9b4a18c320 Fixes for test 2026-01-15 11:51:09 +01:00
dgtlmoon
89fb57c2e0 zh_TW - zh_Hant_TW fixes and tests re #3737 2026-01-15 11:02:50 +01:00
6 changed files with 66 additions and 9 deletions

View File

@@ -9,6 +9,7 @@ import threading
import time
import timeago
from blinker import signal
from pathlib import Path
from changedetectionio.strtobool import strtobool
from threading import Event
@@ -84,6 +85,10 @@ app.config['NEW_VERSION_AVAILABLE'] = False
if os.getenv('FLASK_SERVER_NAME'):
app.config['SERVER_NAME'] = os.getenv('FLASK_SERVER_NAME')
# Babel/i18n configuration
app.config['BABEL_TRANSLATION_DIRECTORIES'] = str(Path(__file__).parent / 'translations')
app.config['BABEL_DEFAULT_LOCALE'] = 'en_GB'
#app.config["EXPLAIN_TEMPLATE_LOADING"] = True
@@ -395,13 +400,9 @@ def changedetection_app(config=None, datastore_o=None):
def get_locale():
# 1. Try to get locale from session (user explicitly selected)
if 'locale' in session:
locale = session['locale']
logger.trace(f"DEBUG: get_locale() returning from session: {locale}")
return locale
return session['locale']
# 2. Fall back to Accept-Language header
locale = request.accept_languages.best_match(language_codes)
logger.trace(f"DEBUG: get_locale() returning from Accept-Language: {locale}")
return locale
return request.accept_languages.best_match(language_codes)
# Initialize Babel with locale selector
babel = Babel(app, locale_selector=get_locale)
@@ -518,9 +519,20 @@ def changedetection_app(config=None, datastore_o=None):
@app.route('/set-language/<locale>')
def set_language(locale):
"""Set the user's preferred language in the session"""
if not request.cookies:
logger.error("Cannot set language without session cookie")
flash("Cannot set language without session cookie", 'error')
return redirect(url_for('watchlist.index'))
# Validate the locale against available languages
if locale in language_codes:
session['locale'] = locale
# CRITICAL: Flask-Babel caches the locale in the request context (ctx.babel_locale)
# We must refresh to clear this cache so the new locale takes effect immediately
# This is especially important for tests where multiple requests happen rapidly
from flask_babel import refresh
refresh()
else:
logger.error(f"Invalid locale {locale}, available: {language_codes}")

View File

@@ -29,7 +29,7 @@ def get_timeago_locale(flask_locale):
"""
locale_map = {
'zh': 'zh_CN', # Chinese Simplified
'zh_Hant_TW': 'zh_TW', # Flask-Babel normalizes zh_TW to zh_Hant_TW
'zh_TW': 'zh_Hant_TW', # Flask-Babel normalizes zh_TW to zh_Hant_TW
'pt': 'pt_PT', # Portuguese (Portugal)
'sv': 'sv_SE', # Swedish
'no': 'nb_NO', # Norwegian Bokmål
@@ -54,7 +54,7 @@ LANGUAGE_DATA = {
'it': {'flag': 'fi fi-it fis', 'name': 'Italiano'},
'ja': {'flag': 'fi fi-jp fis', 'name': '日本語'},
'zh': {'flag': 'fi fi-cn fis', 'name': '中文 (简体)'},
'zh_TW': {'flag': 'fi fi-tw fis', 'name': '繁體中文'},
'zh_Hant_TW': {'flag': 'fi fi-tw fis', 'name': '繁體中文'},
'ru': {'flag': 'fi fi-ru fis', 'name': 'Русский'},
'pl': {'flag': 'fi fi-pl fis', 'name': 'Polski'},
'nl': {'flag': 'fi fi-nl fis', 'name': 'Nederlands'},

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="{{ get_locale() }}" data-darkmode="{{ get_darkmode_state() }}">
<html lang="{{ get_locale()|replace('_', '-') }}" data-darkmode="{{ get_darkmode_state() }}">
<head>
<meta charset="utf-8" >

View File

@@ -3,6 +3,39 @@
from flask import url_for
from .util import live_server_setup
def test_zh_TW(client, live_server, measure_memory_usage, datastore_path):
# Be sure we got a session cookie
res = client.get(url_for("watchlist.index"), follow_redirects=True)
res = client.get(
url_for("set_language", locale="zh_Hant_TW"), # Traditional
follow_redirects=True
)
# HTML follows BCP 47 language tag rules, not underscore-based locale formats.
assert b'<html lang="zh-Hant-TW"' in res.data
assert b'Cannot set language without session cookie' not in res.data
assert '選擇語言'.encode() in res.data
# Check second set works
res = client.get(
url_for("set_language", locale="en_GB"),
follow_redirects=True
)
assert b'Cannot set language without session cookie' not in res.data
res = client.get(url_for("watchlist.index"), follow_redirects=True)
assert b"Select Language" in res.data, "Second set of language worked"
# Check arbitration between zh_Hant_TW<->zh
res = client.get(
url_for("set_language", locale="zh"), # Simplified chinese
follow_redirects=True
)
res = client.get(url_for("watchlist.index"), follow_redirects=True)
assert "选择语言".encode() in res.data, "Simplified chinese worked and it means the flask-babel cache worked"
def test_language_switching(client, live_server, measure_memory_usage, datastore_path):
"""
@@ -13,6 +46,9 @@ def test_language_switching(client, live_server, measure_memory_usage, datastore
3. Switch back to English and verify English text appears
"""
# Establish session cookie
client.get(url_for("watchlist.index"), follow_redirects=True)
# Step 1: Set the language to Italian using the /set-language endpoint
res = client.get(
url_for("set_language", locale="it"),
@@ -61,6 +97,9 @@ def test_invalid_locale(client, live_server, measure_memory_usage, datastore_pat
The app should ignore invalid locales and continue working.
"""
# Establish session cookie
client.get(url_for("watchlist.index"), follow_redirects=True)
# First set to English
res = client.get(
url_for("set_language", locale="en"),
@@ -93,6 +132,9 @@ def test_language_persistence_in_session(client, live_server, measure_memory_usa
within the same session.
"""
# Establish session cookie
client.get(url_for("watchlist.index"), follow_redirects=True)
# Set language to Italian
res = client.get(
url_for("set_language", locale="it"),
@@ -119,6 +161,9 @@ def test_set_language_with_redirect(client, live_server, measure_memory_usage, d
"""
from flask import url_for
# Establish session cookie
client.get(url_for("watchlist.index"), follow_redirects=True)
# Set language with a redirect parameter (simulating language change from /settings)
res = client.get(
url_for("set_language", locale="de", redirect="/settings"),