dynamicweb/cms/tests/test_i18n.py

675 lines
24 KiB
Python

from importlib import import_module
from unittest.mock import patch
from django.conf import settings
from django.template.context import Context
from django.test.utils import override_settings
from django.utils import translation
from cms import api
from cms.test_utils.testcases import CMSTestCase
from cms.utils import get_language_from_request, i18n
from cms.views import details
@override_settings(
LANGUAGE_CODE='en',
LANGUAGES=(('fr', 'French'),
('en', 'English'),
('de', 'German'),
('es', 'Spanish')),
CMS_LANGUAGES={
1: [
{'code': 'en',
'name': 'English',
'public': True},
{'code': 'fr',
'name': 'French',
'public': False},
],
'default': {
'public': True,
'hide_untranslated': False,
},
},
SITE_ID=1,
)
class TestLanguages(CMSTestCase):
def test_language_code(self):
self.assertEqual(i18n.get_language_code('en', site_id=1), 'en')
self.assertEqual(i18n.get_current_language(), 'en')
def test_get_languages_default_site(self):
result = i18n.get_languages(1)
self.assertEqual(2, len(result))
lang = result[0]
self.assertEqual(lang['code'], 'en')
self.assertEqual(i18n.get_language_code(lang['code'], site_id=1), 'en')
self.assertEqual(lang['public'], True)
lang = result[1]
self.assertEqual(lang['code'], 'fr')
self.assertEqual(i18n.get_language_code(lang['code'], site_id=1), 'fr')
self.assertEqual(lang['public'], False)
def test_get_languages_defined_site(self):
result = i18n.get_languages(1)
self.assertEqual(2, len(result))
lang = result[0]
self.assertEqual(lang['code'], 'en')
self.assertEqual(i18n.get_language_code(lang['code'], 1), 'en')
self.assertEqual(lang['public'], True)
lang = result[1]
self.assertEqual(lang['code'], 'fr')
self.assertEqual(i18n.get_language_code(lang['code'], 1), 'fr')
self.assertEqual(lang['public'], False)
def test_get_languages_undefined_site(self):
result = i18n.get_languages(66)
self.assertEqual(4, len(result))
self.assertEqual(result[0]['code'], 'fr')
self.assertEqual(i18n.get_language_code(result[0]['code'], site_id=66), 'fr')
self.assertEqual(result[1]['code'], 'en')
self.assertEqual(i18n.get_language_code(result[1]['code'], site_id=66), 'en')
self.assertEqual(result[2]['code'], 'de')
self.assertEqual(i18n.get_language_code(result[2]['code'], site_id=66), 'de')
self.assertEqual(result[3]['code'], 'es')
self.assertEqual(i18n.get_language_code(result[3]['code'], site_id=66), 'es')
for lang in result:
self.assertEqual(lang['public'], True)
self.assertEqual(lang['hide_untranslated'], False)
@override_settings(
LANGUAGE_CODE='en',
LANGUAGES=(('fr', 'French'),
('en', 'English'),
('de', 'German'),
('es', 'Spanish')),
CMS_LANGUAGES={
1: [
{'code': 'en',
'name': 'English',
'public': True},
{'code': 'fr',
'name': 'French',
'public': False},
],
},
SITE_ID=1,
)
class TestLanguagesNoDefault(CMSTestCase):
def x_test_get_languages_default_site(self):
result = i18n.get_languages()
self.assertEqual(2, len(result))
lang = result[0]
self.assertEqual(lang['code'], 'en')
self.assertEqual(i18n.get_language_code(lang['code']), 'en')
self.assertEqual(lang['public'], True)
lang = result[1]
self.assertEqual(lang['code'], 'fr')
self.assertEqual(i18n.get_language_code(lang['code']), 'fr')
self.assertEqual(lang['public'], False)
def test_get_languages_defined_site(self):
result = i18n.get_languages(1)
self.assertEqual(2, len(result))
lang = result[0]
self.assertEqual(lang['code'], 'en')
self.assertEqual(i18n.get_language_code(lang['code'], site_id=1), 'en')
self.assertEqual(lang['public'], True)
lang = result[1]
self.assertEqual(lang['code'], 'fr')
self.assertEqual(i18n.get_language_code(lang['code'], site_id=1), 'fr')
self.assertEqual(lang['public'], False)
def test_get_languages_undefined_site(self):
result = i18n.get_languages(66)
self.assertEqual(4, len(result))
self.assertEqual(result[0]['code'], 'fr')
self.assertEqual(i18n.get_language_code(result[0]['code'], site_id=66), 'fr')
self.assertEqual(result[1]['code'], 'en')
self.assertEqual(i18n.get_language_code(result[1]['code'], site_id=66), 'en')
self.assertEqual(result[2]['code'], 'de')
self.assertEqual(i18n.get_language_code(result[2]['code'], site_id=66), 'de')
self.assertEqual(result[3]['code'], 'es')
self.assertEqual(i18n.get_language_code(result[3]['code'], site_id=66), 'es')
for lang in result:
self.assertEqual(lang['public'], True)
self.assertEqual(lang['hide_untranslated'], True)
@override_settings(
LANGUAGE_CODE='en-us',
LANGUAGES=(('fr-ca', 'French (Canada)'),
('en-us', 'English (US)'),
('en-gb', 'English (UK)'),
('de', 'German'),
('es', 'Spanish')),
CMS_LANGUAGES={
1: [
{'code': 'en-us',
'name': 'English (US)',
'public': True},
{'code': 'fr-ca',
'name': 'French (Canada)',
'public': False},
],
'default': {
'public': True,
'hide_untranslated': False,
},
},
SITE_ID=1,
)
class TestLanguageCodesEnUS(CMSTestCase):
def test_language_code(self):
self.assertEqual(i18n.get_language_code('en-us', 1), 'en-us')
self.assertEqual(i18n.get_current_language(), 'en-us')
def test_get_languages_default_site(self):
result = i18n.get_languages(1)
self.assertEqual(2, len(result))
lang = result[0]
self.assertEqual(lang['code'], 'en-us')
self.assertEqual(i18n.get_language_code(lang['code'], site_id=1), 'en-us')
self.assertEqual(lang['public'], True)
lang = result[1]
self.assertEqual(lang['code'], 'fr-ca')
self.assertEqual(i18n.get_language_code(lang['code'], site_id=1), 'fr-ca')
self.assertEqual(lang['public'], False)
def test_get_languages_defined_site(self):
result = i18n.get_languages(1)
self.assertEqual(2, len(result))
lang = result[0]
self.assertEqual(lang['code'], 'en-us')
self.assertEqual(i18n.get_language_code(lang['code'], site_id=1), 'en-us')
self.assertEqual(lang['public'], True)
lang = result[1]
self.assertEqual(lang['code'], 'fr-ca')
self.assertEqual(i18n.get_language_code(lang['code'], site_id=1), 'fr-ca')
self.assertEqual(lang['public'], False)
def test_get_languages_undefined_site(self):
result = i18n.get_languages(66)
self.assertEqual(5, len(result))
self.assertEqual(result[0]['code'], 'fr-ca')
self.assertEqual(i18n.get_language_code(result[0]['code'], site_id=66), 'fr-ca')
self.assertEqual(result[1]['code'], 'en-us')
self.assertEqual(i18n.get_language_code(result[1]['code'], site_id=66), 'en-us')
self.assertEqual(result[2]['code'], 'en-gb')
self.assertEqual(i18n.get_language_code(result[2]['code'], site_id=66), 'en-gb')
self.assertEqual(result[3]['code'], 'de')
self.assertEqual(i18n.get_language_code(result[3]['code'], site_id=66), 'de')
self.assertEqual(result[4]['code'], 'es')
self.assertEqual(i18n.get_language_code(result[4]['code'], site_id=66), 'es')
for lang in result:
self.assertEqual(lang['public'], True)
self.assertEqual(lang['hide_untranslated'], False)
@override_settings(
LANGUAGE_CODE='en-gb',
LANGUAGES=(('fr-ca', 'French (Canada)'),
('en-us', 'English (US)'),
('en-gb', 'English (UK)'),
('de', 'German'),
('es', 'Spanish')),
CMS_LANGUAGES={
1: [
{'code': 'en-gb',
'name': 'English (UK)',
'public': True},
{'code': 'fr-ca',
'name': 'French (Canada)',
'public': False},
],
'default': {
'public': True,
'hide_untranslated': False,
},
},
SITE_ID=1,
)
class TestLanguageCodesEnGB(CMSTestCase):
def test_language_code(self):
self.assertEqual(i18n.get_language_code('en-gb', site_id=1), 'en-gb')
self.assertEqual(i18n.get_current_language(), 'en-gb')
def test_get_languages_default_site(self):
result = i18n.get_languages(site_id=1)
self.assertEqual(2, len(result))
lang = result[0]
self.assertEqual(lang['code'], 'en-gb')
self.assertEqual(i18n.get_language_code(lang['code'], site_id=1), 'en-gb')
self.assertEqual(lang['public'], True)
lang = result[1]
self.assertEqual(lang['code'], 'fr-ca')
self.assertEqual(i18n.get_language_code(lang['code'], site_id=1), 'fr-ca')
self.assertEqual(lang['public'], False)
def test_get_languages_defined_site(self):
result = i18n.get_languages(1)
self.assertEqual(2, len(result))
lang = result[0]
self.assertEqual(lang['code'], 'en-gb')
self.assertEqual(i18n.get_language_code(lang['code'], site_id=1), 'en-gb')
self.assertEqual(lang['public'], True)
lang = result[1]
self.assertEqual(lang['code'], 'fr-ca')
self.assertEqual(i18n.get_language_code(lang['code'], site_id=1), 'fr-ca')
self.assertEqual(lang['public'], False)
def test_get_languages_undefined_site(self):
result = i18n.get_languages(66)
self.assertEqual(5, len(result))
self.assertEqual(result[0]['code'], 'fr-ca')
self.assertEqual(i18n.get_language_code(result[0]['code'], site_id=66), 'fr-ca')
self.assertEqual(result[1]['code'], 'en-us')
self.assertEqual(i18n.get_language_code(result[1]['code'], site_id=66), 'en-us')
self.assertEqual(result[2]['code'], 'en-gb')
self.assertEqual(i18n.get_language_code(result[2]['code'], site_id=66), 'en-gb')
self.assertEqual(result[3]['code'], 'de')
self.assertEqual(i18n.get_language_code(result[3]['code'], site_id=66), 'de')
self.assertEqual(result[4]['code'], 'es')
self.assertEqual(i18n.get_language_code(result[4]['code'], site_id=66), 'es')
for lang in result:
self.assertEqual(lang['public'], True)
self.assertEqual(lang['hide_untranslated'], False)
@override_settings(
LANGUAGE_CODE='en',
LANGUAGES=(('fr', 'French'),
('en', 'English'),
('de', 'German'),
('es', 'Spanish')),
CMS_LANGUAGES={
1: [
{'code': 'en',
'name': 'English',
'public': True},
{'code': 'fr',
'name': 'French',
'public': False},
],
2: [
{'code': 'de',
'name': 'German',
'public': True},
{'code': 'es',
'name': 'Spanish',
'public': True},
],
'default': {
'public': True,
'hide_untranslated': False,
},
},
)
class TestGetCurrentLanguageWithoutSiteID(CMSTestCase):
"""
Test get_current_language when SITE_ID is not set in settings.
"""
@override_settings(SITE_ID=None)
def test_get_current_language_returns_valid_language_code(self):
"""Test that get_current_language returns a valid language from settings.LANGUAGES."""
with translation.override('en'):
result = i18n.get_current_language()
self.assertEqual(result, 'en')
@override_settings(SITE_ID=None)
def test_get_current_language_with_base_language_match(self):
"""Test that get_current_language matches base language when exact match not found."""
with translation.override('en-us'):
result = i18n.get_current_language()
# Should match 'en' from settings.LANGUAGES
self.assertEqual(result, 'en')
@override_settings(SITE_ID=None)
def test_get_current_language_with_no_match_returns_active_language(self):
"""Test that get_current_language returns active language when no match found."""
with translation.override('it'): # Italian not in settings.LANGUAGES
result = i18n.get_current_language()
self.assertEqual(result, 'it')
@override_settings(SITE_ID=None)
def test_get_current_language_with_region_variant(self):
"""Test that get_current_language handles region variants correctly."""
with translation.override('de-at'): # Austrian German
result = i18n.get_current_language()
# Should match 'de' from settings.LANGUAGES
self.assertEqual(result, 'de')
@override_settings(
LANGUAGE_CODE='en',
LANGUAGES=[
('en', 'English'),
('de', 'German'),
('fr', 'French')
],
CMS_LANGUAGES={
1: [{'code': 'de',
'name': 'German',
'public': True},
{'code': 'fr',
'name': 'French',
'public': True}],
'default': {
'fallbacks': ['de', 'fr'],
},
},
SITE_ID=1,
)
class TestLanguagesNotInCMSLanguages(CMSTestCase):
def test_get_fallback_languages(self):
languages = i18n.get_fallback_languages('en', 1)
self.assertEqual(languages, ['de', 'fr'])
@override_settings(
LANGUAGE_CODE='en',
LANGUAGES=(('fr', 'French'),
('en', 'English'),
('de', 'German'),
('es', 'Spanish')),
CMS_LANGUAGES={
1: [
{'code': 'en',
'name': 'English',
'public': False},
{'code': 'fr',
'name': 'French',
'public': True},
],
'default': {
'fallbacks': ['en', 'fr'],
'redirect_on_fallback': False,
'public': True,
'hide_untranslated': False,
}
},
SITE_ID=1,
)
class TestLanguageFallbacks(CMSTestCase):
def test_language_code(self):
'''
No redirect_on_fallback will return 200 with the fallback content
'''
self.create_homepage("home", "nav_playground.html", "fr")
response = self.client.get('/')
# no language code will cause a redirect.
self.assertEqual(response.status_code, 302)
response = self.client.get('/en/')
self.assertEqual(response.status_code, 200)
response = self.client.get('/fr/')
self.assertEqual(response.status_code, 200)
@override_settings(
CMS_LANGUAGES={
1: [
{'code': 'en',
'name': 'English',
'public': True},
{'code': 'fr',
'name': 'French',
'public': True},
]
},
)
def test_session_language(self):
page = self.create_homepage("home", "nav_playground.html", "en")
api.create_page_content('fr', "home", page)
response = self.client.get('/')
self.assertEqual(response.status_code, 302)
self.assertRedirects(response, '/en/')
engine = import_module(settings.SESSION_ENGINE)
store = engine.SessionStore()
store.save() # we need to make load() work, or the cookie is worthless
self.client.cookies[settings.SESSION_COOKIE_NAME] = store.session_key
# ugly and long set of session
self.client.cookies[settings.LANGUAGE_COOKIE_NAME] = 'fr'
response = self.client.get('/')
self.assertEqual(response.status_code, 302)
self.assertRedirects(response, '/fr/')
self.client.get('/en/')
self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, 'en')
response = self.client.get('/')
self.assertEqual(response.status_code, 302)
self.assertRedirects(response, '/en/')
@override_settings(
CMS_LANGUAGES={
'default': {
'fallbacks': ['en', 'fr'],
'public': True, # no 404s
'redirect_on_fallback': False
}
},
)
def test_no_redirect_on_fallback(self):
homepage = self.create_homepage(
"home",
"nav_playground.html",
"fr"
)
page_data = self.get_new_page_data_dbfields(
language="fr"
)
page = api.create_page(**page_data)
response = self.client.get(page.get_absolute_url(language="en"))
self.assertEqual(response.status_code, 200)
# homepage should be the same
response = self.client.get(homepage.get_absolute_url(language="en"))
self.assertEqual(response.status_code, 200)
@override_settings(
CMS_LANGUAGES={
'default': {
'fallbacks': ['en', 'fr'],
'public': True, # no 404s
'redirect_on_fallback': False
}
},
)
def test_no_redirect_on_fallback_content(self):
"""
Test that the fallback content will be displayed
"""
homepage = self.create_homepage(
"home",
"nav_playground.html",
"fr"
)
homepage_ph_fr = homepage.get_placeholders(
"fr").get(slot="body")
api.add_plugin(
homepage_ph_fr,
plugin_type="TextPlugin",
language="fr",
body="Hello, world!",
)
page_data = self.get_new_page_data_dbfields(
language="fr"
)
page = api.create_page(**page_data)
page_ph_fr = page.get_placeholders(
"fr").get(slot="body")
api.add_plugin(
page_ph_fr,
plugin_type="TextPlugin",
language="fr",
body="Hello, world!",
)
with patch("cms.views.render_pagecontent") as mock_render:
# normal page
path = page.get_absolute_url(language="en")
request = self.get_request(path, "en")
details(request, slug=page.get_path("en"))
mock_render.assert_called_once_with(
request,
page.get_content_obj()
)
context = Context({'request': self.get_request(path, "fr")})
rendered_placeholder = self._render_placeholder(page_ph_fr, context)
self.assertEqual(rendered_placeholder, "Hello, world!")
with patch("cms.views.render_pagecontent") as mock_render:
# homepage should be the same
path = homepage.get_absolute_url(language="en")
request = self.get_request(path)
details(request, slug=homepage.get_path("en"))
mock_render.assert_called_once_with(
request,
homepage.get_content_obj()
)
# check that the french plugins will render
context = Context({'request': request})
rendered_placeholder = self._render_placeholder(homepage_ph_fr, context)
self.assertEqual(rendered_placeholder, "Hello, world!")
@override_settings(
LANGUAGES=(
('en', 'English'),
('de', 'Deutsch'),
('it', 'Italian'),
('fr', 'French'),
),
CMS_LANGUAGES={
'default': {
'fallbacks': ['en', 'fr'],
'public': True,
'redirect_on_fallback': False,
'hide_untranslated': False,
},
},
)
def test_no_redirect_on_fallback_placeholder_rendering(self):
"""
When redirect_on_fallback is False and hide_untranslated is False,
requesting a page in a language that has no content should render
the placeholder content from the fallback language, not empty placeholders.
Regression test for issue #8556.
"""
homepage = self.create_homepage(
"home",
"nav_playground.html",
"en",
)
homepage_ph = homepage.get_placeholders("en").get(slot="body")
api.add_plugin(
homepage_ph,
plugin_type="TextPlugin",
language="en",
body="English content",
)
# Request the page in Italian which has no translation;
# the fallback chain is ['en', 'fr'] so English content should appear.
response = self.client.get(homepage.get_absolute_url(language="it"))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "English content")
@override_settings(
CMS_LANGUAGES={
'default': {
'fallbacks': ['en', 'fr'],
'redirect_on_fallback': True,
}
}
)
def test_redirect_on_fallback(self):
page_data = self.get_new_page_data_dbfields(
language="fr"
)
page = api.create_page(**page_data)
response_fr = self.client.get(page.get_absolute_url(language="fr"))
self.assertEqual(response_fr.status_code, 200)
response_en = self.client.get(page.get_absolute_url(language="en"))
self.assertRedirects(response_en, page.get_absolute_url(language="fr"))
# homepage should be no different.
home_page_data = self.get_new_page_data_dbfields(
language="fr",
)
self.create_homepage(**home_page_data)
response_fr = self.client.get(page.get_absolute_url(language="fr"))
self.assertEqual(response_fr.status_code, 200)
response_en = self.client.get(page.get_absolute_url(language="en"))
self.assertRedirects(response_en, page.get_absolute_url(language="fr"))
@override_settings(
LANGUAGE_CODE='en',
LANGUAGES=(('fr', 'French'),
('en', 'English'),
('de', 'German'),
('es', 'Spanish')),
CMS_LANGUAGES={
1: [
{'code': 'en',
'name': 'English',
'public': False},
{'code': 'fr',
'name': 'French',
'public': True},
],
'default': {
'fallbacks': ['en', 'fr'],
'redirect_on_fallback': False,
'public': True,
'hide_untranslated': False,
}
},
SITE_ID=1,
)
class TestGetLanguageFromRequest(CMSTestCase):
def test_get_language_from_request_does_not_return_empty_string_from_post(self):
request = self.get_request(language='en', post_data={
'language': '',
})
self.assertEqual(get_language_from_request(request), 'en')
def test_get_language_from_request_does_not_return_empty_string_from_get(self):
request = self.get_request('/en/?language=', language='en')
self.assertEqual(get_language_from_request(request), 'en')
@override_settings(
LANGUAGE_CODE='es',
LANGUAGES=(('fr', 'French'),
('en', 'English'),
('de', 'German'),
('es', 'Spanish')),
SITE_ID=None,
)
class TestLanguagesWithoutSiteID(CMSTestCase):
"""
Test language handling when SITE_ID is not set in settings.
"""
def test_get_languages_without_site_id_uses_all_languages(self):
"""Test that get_languages uses all LANGUAGES when SITE_ID is not set."""
result = i18n.get_languages(site_id=1)
self.assertEqual(result, [{'code': 'fr', 'name': 'French'}, {'code': 'en', 'name': 'English'}, {'code': 'de', 'name': 'German'}, {'code': 'es', 'name': 'Spanish'}])
@override_settings(USE_I18N=False)
def test_get_language_code_without_site_id_and_use_i18n_false_returns_site_language(self):
"""Verify that when SITE_ID is not set and USE_I18N is False, i18n.get_languages()
returns only the current site's default language (a single-item list) rather than
using the full global LANGUAGES setting."""
"""Test that get_languages uses all LANGUAGES when SITE_ID is not set."""
result = i18n.get_languages(site_id=1)
self.assertEqual(result, [{'code': 'es', 'name': 'es'}])