pyramid-localize 0.1.0__py2.7.egg
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- EGG-INFO/PKG-INFO +139 -0
- EGG-INFO/SOURCES.txt +50 -0
- EGG-INFO/dependency_links.txt +1 -0
- EGG-INFO/not-zip-safe +1 -0
- EGG-INFO/requires.txt +15 -0
- EGG-INFO/top_level.txt +2 -0
- pyramid_localize/__init__.py +62 -0
- pyramid_localize/__init__.pyc +0 -0
- pyramid_localize/config/config.yml +13 -0
- pyramid_localize/models.py +37 -0
- pyramid_localize/models.pyc +0 -0
- pyramid_localize/negotiator.py +41 -0
- pyramid_localize/negotiator.pyc +0 -0
- pyramid_localize/request.py +124 -0
- pyramid_localize/request.pyc +0 -0
- pyramid_localize/resources/locale/pyramid_localize.pot +58 -0
- pyramid_localize/resources/templates/_list.mako +33 -0
- pyramid_localize/resources/templates/index.mako +19 -0
- pyramid_localize/resources/templates/layout.mako +12 -0
- pyramid_localize/routing/__init__.py +5 -0
- pyramid_localize/routing/__init__.pyc +0 -0
- pyramid_localize/routing/predicates.py +18 -0
- pyramid_localize/routing/predicates.pyc +0 -0
- pyramid_localize/subscribers/__init__.py +5 -0
- pyramid_localize/subscribers/__init__.pyc +0 -0
- pyramid_localize/subscribers/fake.py +27 -0
- pyramid_localize/subscribers/fake.pyc +0 -0
- pyramid_localize/subscribers/i18n.py +27 -0
- pyramid_localize/subscribers/i18n.pyc +0 -0
- pyramid_localize/tools.py +100 -0
- pyramid_localize/tools.pyc +0 -0
- pyramid_localize/views/__init__.py +5 -0
- pyramid_localize/views/__init__.pyc +0 -0
- pyramid_localize/views/catalogue.py +225 -0
- pyramid_localize/views/catalogue.pyc +0 -0
- tests/__init__.py +1 -0
- tests/__init__.pyc +0 -0
- tests/conftest.py +58 -0
- tests/conftest.pyc +0 -0
- tests/test_negotiator.py +55 -0
- tests/test_negotiator.pyc +0 -0
- tests/test_predicates.py +23 -0
- tests/test_predicates.pyc +0 -0
- tests/test_request.py +89 -0
- tests/test_request.pyc +0 -0
- tests/test_subscribers.py +80 -0
- tests/test_subscribers.pyc +0 -0
- tests/test_tools.py +105 -0
- tests/test_tools.pyc +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Copyright (c) 2013-2014 by pyramid_localize authors and contributors <see AUTHORS file>
|
|
2
|
+
#
|
|
3
|
+
# This module is part of pyramid_localize and is released under
|
|
4
|
+
# the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
5
|
+
"""Subscribers adding mocked translation methods to render context, and request."""
|
|
6
|
+
|
|
7
|
+
from pyramid.events import subscriber
|
|
8
|
+
from pyramid.events import BeforeRender
|
|
9
|
+
from pyramid.events import NewRequest
|
|
10
|
+
|
|
11
|
+
from pyramid_localize.tools import dummy_autotranslate
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@subscriber(BeforeRender)
|
|
15
|
+
def global_renderer(event):
|
|
16
|
+
"""BeforeRender subscriber, adds fake localizer, and translation methods to context."""
|
|
17
|
+
request = event['request']
|
|
18
|
+
try:
|
|
19
|
+
event['_'] = request._
|
|
20
|
+
except AttributeError:
|
|
21
|
+
event['_'] = dummy_autotranslate
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@subscriber(NewRequest)
|
|
25
|
+
def add_localizer(event):
|
|
26
|
+
"""NewRequest subscriber, adds fake localizer and translation methods to request."""
|
|
27
|
+
event.request._ = dummy_autotranslate
|
|
Binary file
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Copyright (c) 2013-2014 by pyramid_localize authors and contributors <see AUTHORS file>
|
|
2
|
+
#
|
|
3
|
+
# This module is part of pyramid_localize and is released under
|
|
4
|
+
# the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
5
|
+
"""i18n subscribers."""
|
|
6
|
+
|
|
7
|
+
from pyramid.events import subscriber
|
|
8
|
+
from pyramid.events import BeforeRender
|
|
9
|
+
from pyramid.events import NewRequest
|
|
10
|
+
|
|
11
|
+
from pyramid_localize.tools import set_localizer
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@subscriber(BeforeRender)
|
|
15
|
+
def global_renderer(event):
|
|
16
|
+
"""BeforeRender subscriber, adds localizer, and translation methods to context."""
|
|
17
|
+
request = event['request']
|
|
18
|
+
set_localizer(request)
|
|
19
|
+
|
|
20
|
+
event['_'] = request._
|
|
21
|
+
event['localizer'] = request.localizer
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@subscriber(NewRequest)
|
|
25
|
+
def add_localizer(event):
|
|
26
|
+
"""NewRequest subscriber, adds localizer and translation methods to request."""
|
|
27
|
+
set_localizer(event.request)
|
|
Binary file
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Copyright (c) 2013-2014 by pyramid_localize authors and contributors <see AUTHORS file>
|
|
2
|
+
#
|
|
3
|
+
# This module is part of pyramid_localize and is released under
|
|
4
|
+
# the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
5
|
+
"""methods in this module are tools, thank to which pyramid_localize works most of its magic."""
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
import os
|
|
9
|
+
import logging
|
|
10
|
+
|
|
11
|
+
from translationstring import _interp_regex
|
|
12
|
+
from pyramid.i18n import make_localizer
|
|
13
|
+
from pyramid.i18n import TranslationString
|
|
14
|
+
from pyramid.asset import resolve_asset_spec
|
|
15
|
+
from pyramid.path import package_path
|
|
16
|
+
from pyramid.interfaces import ILocalizer
|
|
17
|
+
from pyramid.interfaces import ITranslationDirectories
|
|
18
|
+
from pyramid.compat import text_type
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def set_localizer(request, reset=False):
|
|
24
|
+
"""
|
|
25
|
+
Set localizer and auto_translate methods for request.
|
|
26
|
+
|
|
27
|
+
:param pyramid.request.Request request: request object
|
|
28
|
+
:param bool reset: flag that directs resetting localizer within app
|
|
29
|
+
"""
|
|
30
|
+
if reset:
|
|
31
|
+
|
|
32
|
+
for locale in request.registry['config'].localize.locales.available:
|
|
33
|
+
logger.debug('Resetting {0} localizator'.format(locale))
|
|
34
|
+
tdirs = request.registry.queryUtility(ITranslationDirectories,
|
|
35
|
+
default=[])
|
|
36
|
+
localizer = make_localizer(locale, tdirs)
|
|
37
|
+
request.registry.registerUtility(localizer, ILocalizer,
|
|
38
|
+
name=locale)
|
|
39
|
+
|
|
40
|
+
def auto_translate(*args, **kwargs):
|
|
41
|
+
# lets pass default domain, so we don't have to determine it with
|
|
42
|
+
# each _() function in apps.
|
|
43
|
+
if len(args) <= 1 and 'domain' not in kwargs:
|
|
44
|
+
kwargs['domain'] = request.registry['config'].localize.domain
|
|
45
|
+
|
|
46
|
+
# unlike in examples we use TranslationString, to make sure we always
|
|
47
|
+
# use appropriate domain
|
|
48
|
+
return request.localizer.translate(TranslationString(*args, **kwargs))
|
|
49
|
+
|
|
50
|
+
request._ = auto_translate
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def destination_path(request):
|
|
54
|
+
"""
|
|
55
|
+
Return absolute path of the translation destination.
|
|
56
|
+
|
|
57
|
+
:param pyramid.request.Request request: a request object
|
|
58
|
+
|
|
59
|
+
:returns: A combined translation destination path
|
|
60
|
+
:rtype: str
|
|
61
|
+
"""
|
|
62
|
+
package_name, filename = resolve_asset_spec(
|
|
63
|
+
request.registry['config'].localize.translation.destination
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
if package_name is None: # absolute filename
|
|
67
|
+
directory = filename
|
|
68
|
+
else:
|
|
69
|
+
__import__(package_name)
|
|
70
|
+
package = sys.modules[package_name]
|
|
71
|
+
directory = os.path.join(package_path(package), filename)
|
|
72
|
+
return directory
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def dummy_autotranslate(msgid, domain=None, default=None, mapping=None):
|
|
76
|
+
"""
|
|
77
|
+
Method that simulate autotranslate.
|
|
78
|
+
|
|
79
|
+
:param str msgid: Message or message id
|
|
80
|
+
:param str domain: Translation domain
|
|
81
|
+
:param str default: Default message
|
|
82
|
+
:param dict mapping: Mapping dictionary for message variables
|
|
83
|
+
|
|
84
|
+
:returns: *translated* string
|
|
85
|
+
:rtype: str
|
|
86
|
+
"""
|
|
87
|
+
# Try to return defaults first:
|
|
88
|
+
tstr = None
|
|
89
|
+
if default:
|
|
90
|
+
tstr = default
|
|
91
|
+
else:
|
|
92
|
+
tstr = msgid
|
|
93
|
+
|
|
94
|
+
if mapping and tstr:
|
|
95
|
+
def replace(match):
|
|
96
|
+
whole, param1, param2 = match.groups()
|
|
97
|
+
return text_type(mapping.get(param1 or param2, whole))
|
|
98
|
+
tstr = _interp_regex.sub(replace, tstr)
|
|
99
|
+
|
|
100
|
+
return tstr
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Copyright (c) 2013-2014 by pyramid_localize authors and contributors <see AUTHORS file>
|
|
2
|
+
#
|
|
3
|
+
# This module is part of pyramid_localize and is released under
|
|
4
|
+
# the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
5
|
+
"""Catalogue view."""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import os
|
|
10
|
+
import time
|
|
11
|
+
import logging
|
|
12
|
+
import subprocess
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from pyramid.view import view_config
|
|
16
|
+
from pyramid.view import view_defaults
|
|
17
|
+
from pyramid.asset import resolve_asset_spec
|
|
18
|
+
from pyramid.path import package_path
|
|
19
|
+
from pyramid.httpexceptions import HTTPFound
|
|
20
|
+
|
|
21
|
+
from pyramid_localize.tools import destination_path
|
|
22
|
+
from pyramid_localize.tools import set_localizer
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@view_defaults(permission='manage_translations',
|
|
28
|
+
renderer='pyramid_localize:resources/templates/index.mako')
|
|
29
|
+
class CatalogueView(object):
|
|
30
|
+
|
|
31
|
+
"""View class for catalogue manipulation actions."""
|
|
32
|
+
|
|
33
|
+
def __init__(self, request):
|
|
34
|
+
"""
|
|
35
|
+
Assign request.
|
|
36
|
+
|
|
37
|
+
:param pyramid.request.Request request:
|
|
38
|
+
"""
|
|
39
|
+
self.request = request
|
|
40
|
+
|
|
41
|
+
def _translation_file(self, language, domain, extension='po'):
|
|
42
|
+
"""
|
|
43
|
+
Create a translation file path.
|
|
44
|
+
|
|
45
|
+
:param str language: two-letter language code
|
|
46
|
+
:param str domain: translation domain name
|
|
47
|
+
:param str extension: translation file extension (po/mo)
|
|
48
|
+
"""
|
|
49
|
+
translation_destination = destination_path(self.request)
|
|
50
|
+
return os.path.abspath(os.path.join(translation_destination, language,
|
|
51
|
+
'LC_MESSAGES',
|
|
52
|
+
domain + '.' + extension))
|
|
53
|
+
|
|
54
|
+
def _translation_template_path(self, spec):
|
|
55
|
+
"""
|
|
56
|
+
Calculate path to translation template file.
|
|
57
|
+
|
|
58
|
+
:param str spec: either full path, or package related path
|
|
59
|
+
"""
|
|
60
|
+
# resolving possible asset spec to path (pyramid way):
|
|
61
|
+
package_name, filename = resolve_asset_spec(spec)
|
|
62
|
+
if package_name is None: # absolute filename
|
|
63
|
+
return os.path.abspath(filename)
|
|
64
|
+
else:
|
|
65
|
+
__import__(package_name)
|
|
66
|
+
package = sys.modules[package_name]
|
|
67
|
+
return os.path.abspath(os.path.join(package_path(package),
|
|
68
|
+
filename))
|
|
69
|
+
|
|
70
|
+
@view_config(route_name='localize:index')
|
|
71
|
+
def index(self):
|
|
72
|
+
"""
|
|
73
|
+
Simple action listing domains, and its files of files with metadata.
|
|
74
|
+
|
|
75
|
+
:returns:
|
|
76
|
+
|
|
77
|
+
.. code-block:: python
|
|
78
|
+
|
|
79
|
+
{
|
|
80
|
+
'language': {
|
|
81
|
+
'domain1': {
|
|
82
|
+
'po': 'modification time',
|
|
83
|
+
'pot': 'modification time',
|
|
84
|
+
'mo': 'modification time',
|
|
85
|
+
},
|
|
86
|
+
# more domains
|
|
87
|
+
},
|
|
88
|
+
# more languages
|
|
89
|
+
}
|
|
90
|
+
"""
|
|
91
|
+
translations = {}
|
|
92
|
+
translation_sources = self.request.registry['config'].localize.translation.sources
|
|
93
|
+
|
|
94
|
+
for language in self.request.registry['config'].localize.locales.available:
|
|
95
|
+
translations[language] = {}
|
|
96
|
+
for domain in translation_sources:
|
|
97
|
+
translations[language][domain] = {
|
|
98
|
+
'po': None,
|
|
99
|
+
'pot': None,
|
|
100
|
+
'mo': None
|
|
101
|
+
}
|
|
102
|
+
po_file = self._translation_file(language, domain)
|
|
103
|
+
if os.path.isfile(po_file):
|
|
104
|
+
translations[language][domain]['po'] = time.ctime(os.path.getmtime(po_file))
|
|
105
|
+
|
|
106
|
+
pot_file = self._translation_template_path(translation_sources[domain])
|
|
107
|
+
if os.path.isfile(pot_file):
|
|
108
|
+
translations[language][domain]['pot'] = time.ctime(os.path.getmtime(pot_file))
|
|
109
|
+
|
|
110
|
+
mo_file = self._translation_file(language, domain, 'mo')
|
|
111
|
+
if os.path.isfile(mo_file):
|
|
112
|
+
translations[language][domain]['mo'] = time.ctime(os.path.getmtime(mo_file))
|
|
113
|
+
|
|
114
|
+
return {'translations': translations}
|
|
115
|
+
|
|
116
|
+
@view_config(route_name='localize:update')
|
|
117
|
+
def update_catalogue(self):
|
|
118
|
+
"""
|
|
119
|
+
Update or initialize translation catalogues.
|
|
120
|
+
|
|
121
|
+
Create (.po files) for each language/catalogue from their respective
|
|
122
|
+
translation templates (.pot). This action is performed for every language
|
|
123
|
+
defined within `localize.locales.available` config key.
|
|
124
|
+
|
|
125
|
+
Redirects itself to **localize:index**.
|
|
126
|
+
"""
|
|
127
|
+
self.index()
|
|
128
|
+
translation_sources = self.request.registry['config'].localize.translation.sources
|
|
129
|
+
|
|
130
|
+
for domain in translation_sources:
|
|
131
|
+
|
|
132
|
+
pot_file = self._translation_template_path(translation_sources[domain])
|
|
133
|
+
if not os.path.isfile(pot_file):
|
|
134
|
+
logger.critical('pot file for {domain} does not exists!'.format(domain=domain))
|
|
135
|
+
|
|
136
|
+
for language in self.request.registry['config'].localize.locales.available:
|
|
137
|
+
po_file = self._translation_file(language, domain)
|
|
138
|
+
if os.path.isfile(po_file):
|
|
139
|
+
logger.debug(
|
|
140
|
+
'po file for {domain}, {language} exists, proceeding with update'.format(
|
|
141
|
+
domain=domain, language=language))
|
|
142
|
+
|
|
143
|
+
if subprocess.call([self.request.registry['config'].localize.pybabel,
|
|
144
|
+
'update',
|
|
145
|
+
'-l', language,
|
|
146
|
+
'-i', pot_file,
|
|
147
|
+
'-o', po_file,
|
|
148
|
+
'--previous']):
|
|
149
|
+
logger.error('Error while trying to update {po} file!'.format(po=po_file))
|
|
150
|
+
else:
|
|
151
|
+
logger.debug(
|
|
152
|
+
'''po file for {domain}, {language} does not exists,
|
|
153
|
+
proceeding with initialize'''.format(domain=domain, language=language))
|
|
154
|
+
if subprocess.call([self.request.registry['config'].localize.pybabel,
|
|
155
|
+
'init',
|
|
156
|
+
'-l', language,
|
|
157
|
+
'-i', pot_file,
|
|
158
|
+
'-o', po_file]):
|
|
159
|
+
logger.error('Error while trying to update {po} file!'.format(po=po_file))
|
|
160
|
+
|
|
161
|
+
return HTTPFound(location=self.request.route_url('localize:index'))
|
|
162
|
+
|
|
163
|
+
@view_config(route_name='localize:compile')
|
|
164
|
+
def compile_catalogue(self):
|
|
165
|
+
"""
|
|
166
|
+
Compile all translation files.
|
|
167
|
+
|
|
168
|
+
For every language defined compile .po files into into .mo file that's used by gettext.
|
|
169
|
+
|
|
170
|
+
Redirects to **localize:index**.
|
|
171
|
+
"""
|
|
172
|
+
self.index()
|
|
173
|
+
translation_sources = self.request.registry['config'].localize.translation.sources
|
|
174
|
+
|
|
175
|
+
for domain in translation_sources:
|
|
176
|
+
|
|
177
|
+
for language in self.request.registry['config'].localize.locales.available:
|
|
178
|
+
po_file = self._translation_file(language, domain)
|
|
179
|
+
mo_file = self._translation_file(language, domain, 'mo')
|
|
180
|
+
if os.path.isfile(po_file):
|
|
181
|
+
logger.debug(
|
|
182
|
+
'''po file for {domain}, {language} exists,
|
|
183
|
+
proceeding with compilation'''.format(domain=domain, language=language))
|
|
184
|
+
if subprocess.call([self.request.registry['config'].localize.pybabel,
|
|
185
|
+
'compile',
|
|
186
|
+
'-l', language,
|
|
187
|
+
'-i', po_file,
|
|
188
|
+
'-o', mo_file,
|
|
189
|
+
'--use-fuzzy']):
|
|
190
|
+
logger.error('Error while trying to compile {po} file!'.format(po=po_file))
|
|
191
|
+
|
|
192
|
+
return HTTPFound(location=self.request.route_url('localize:index'))
|
|
193
|
+
|
|
194
|
+
@view_config(route_name='localize:reload', xhr='True', renderer='json')
|
|
195
|
+
@view_config(route_name='localize:reload')
|
|
196
|
+
def reload_catalogue(self):
|
|
197
|
+
"""
|
|
198
|
+
Reload translation catalogue for application it's run in.
|
|
199
|
+
|
|
200
|
+
.. note::
|
|
201
|
+
|
|
202
|
+
To see how is this happening, you might want to see
|
|
203
|
+
:func:`~pyramid_localize.tools.set_localizer`
|
|
204
|
+
|
|
205
|
+
:returns:
|
|
206
|
+
|
|
207
|
+
Only for xhr requests:
|
|
208
|
+
|
|
209
|
+
.. code-block:: python
|
|
210
|
+
|
|
211
|
+
{
|
|
212
|
+
'status': True,
|
|
213
|
+
'msg': 'Localizators has been reloaded' # translated
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
non xhr requests: Redirects to **localize:index**.
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
"""
|
|
220
|
+
set_localizer(self.request, True)
|
|
221
|
+
|
|
222
|
+
if self.request.is_xhr:
|
|
223
|
+
return {'status': True, 'msg': self.request._('Localizators has been reloaded')}
|
|
224
|
+
|
|
225
|
+
return HTTPFound(location=self.request.route_url('localize:index'))
|
|
Binary file
|
tests/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Test suite."""
|
tests/__init__.pyc
ADDED
|
Binary file
|
tests/conftest.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Test suite main conftest."""
|
|
2
|
+
import pytest
|
|
3
|
+
from mock import Mock
|
|
4
|
+
from pyramid.decorator import reify
|
|
5
|
+
from pyramid.request import Request
|
|
6
|
+
from pyramid import testing
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.fixture
|
|
10
|
+
def web_request():
|
|
11
|
+
"""Mocked web request for views testing."""
|
|
12
|
+
from pyramid_localize.request import LocalizeRequestMixin
|
|
13
|
+
from pyramid_localize.request import database_locales
|
|
14
|
+
from pyramid_localize.request import locale_id
|
|
15
|
+
from pyramid_localize.request import locales
|
|
16
|
+
|
|
17
|
+
class TestRequest(LocalizeRequestMixin, Request):
|
|
18
|
+
|
|
19
|
+
@reify
|
|
20
|
+
def _database_locales(self):
|
|
21
|
+
return database_locales(self)
|
|
22
|
+
|
|
23
|
+
@reify
|
|
24
|
+
def locale_id(self):
|
|
25
|
+
return locale_id(self)
|
|
26
|
+
|
|
27
|
+
def locales(self, *args, **kwargs):
|
|
28
|
+
return locales(self, *args, **kwargs)
|
|
29
|
+
|
|
30
|
+
request = TestRequest({})
|
|
31
|
+
config = Mock()
|
|
32
|
+
config.configure_mock(
|
|
33
|
+
**{'localize.locales.available': ['en', 'pl', 'de', 'cz']}
|
|
34
|
+
)
|
|
35
|
+
configurator = testing.setUp()
|
|
36
|
+
request.registry = configurator.registry
|
|
37
|
+
request.registry['config'] = config
|
|
38
|
+
|
|
39
|
+
return request
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@pytest.fixture
|
|
43
|
+
def locale_negotiator_request():
|
|
44
|
+
"""Request for locale_negotiator tests."""
|
|
45
|
+
request = Mock()
|
|
46
|
+
mock_configuration = {
|
|
47
|
+
'cookies': {'_LOCALE_': 'cz'},
|
|
48
|
+
'_LOCALE_': 'fr',
|
|
49
|
+
'accept_language.best_match.return_value': 'de',
|
|
50
|
+
'path': '/pl/page'}
|
|
51
|
+
request.configure_mock(**mock_configuration)
|
|
52
|
+
config = Mock()
|
|
53
|
+
config.configure_mock(**{
|
|
54
|
+
'localize.locales.available': ['en', 'pl', 'de', 'cz', 'fr'],
|
|
55
|
+
'localize.locales.default': 'en'
|
|
56
|
+
})
|
|
57
|
+
request.registry = {'config': config}
|
|
58
|
+
return request
|
tests/conftest.pyc
ADDED
|
Binary file
|
tests/test_negotiator.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Locale negotiator related tests."""
|
|
2
|
+
from pyramid_localize.negotiator import locale_negotiator
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_negotiate_attr(locale_negotiator_request):
|
|
6
|
+
"""Locale_negotiator - negotiate locale from request attribute."""
|
|
7
|
+
locale = locale_negotiator(locale_negotiator_request)
|
|
8
|
+
|
|
9
|
+
assert locale == 'fr'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_negotiate_path(locale_negotiator_request):
|
|
13
|
+
"""Locale_negotiator - negotiate locale from path."""
|
|
14
|
+
locale_negotiator_request._LOCALE_ = None
|
|
15
|
+
locale = locale_negotiator(locale_negotiator_request)
|
|
16
|
+
|
|
17
|
+
assert locale == 'pl'
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_negotiate_cookie(locale_negotiator_request):
|
|
21
|
+
"""locale_negotiator - negotiate locale from cookie."""
|
|
22
|
+
locale_negotiator_request._LOCALE_ = None
|
|
23
|
+
locale_negotiator_request.path = '/page'
|
|
24
|
+
locale = locale_negotiator(locale_negotiator_request)
|
|
25
|
+
|
|
26
|
+
assert locale == 'cz'
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_negotiate_headers(locale_negotiator_request):
|
|
30
|
+
"""
|
|
31
|
+
Locale_negotiator:header.
|
|
32
|
+
|
|
33
|
+
Negotiate locale from a header.
|
|
34
|
+
"""
|
|
35
|
+
locale_negotiator_request._LOCALE_ = None
|
|
36
|
+
locale_negotiator_request.path = '/page'
|
|
37
|
+
locale_negotiator_request.cookies = {}
|
|
38
|
+
locale = locale_negotiator(locale_negotiator_request)
|
|
39
|
+
|
|
40
|
+
assert locale == 'de'
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_negotiate_default(locale_negotiator_request):
|
|
44
|
+
"""
|
|
45
|
+
Locale_negotiator:default.
|
|
46
|
+
|
|
47
|
+
Other ways fail, return default locale.
|
|
48
|
+
"""
|
|
49
|
+
locale_negotiator_request.path = '/page'
|
|
50
|
+
locale_negotiator_request._LOCALE_ = None
|
|
51
|
+
locale_negotiator_request.cookies = {}
|
|
52
|
+
locale_negotiator_request.accept_language = None
|
|
53
|
+
locale = locale_negotiator(locale_negotiator_request)
|
|
54
|
+
|
|
55
|
+
assert locale == 'en'
|
|
Binary file
|
tests/test_predicates.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Route predicate related tests."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from pyramid_localize.routing.predicates import language
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@pytest.mark.parametrize('match_info, matched', (
|
|
9
|
+
(
|
|
10
|
+
{'match': {'_LOCALE_': 'en'}},
|
|
11
|
+
True
|
|
12
|
+
), (
|
|
13
|
+
{'match': {'_LOCALE_': 'fr'}},
|
|
14
|
+
False
|
|
15
|
+
), (
|
|
16
|
+
{'match': {}},
|
|
17
|
+
False
|
|
18
|
+
)
|
|
19
|
+
))
|
|
20
|
+
def test_predicate(web_request, match_info, matched):
|
|
21
|
+
"""Test matches according to web_request config."""
|
|
22
|
+
predicate = language('_LOCALE_')
|
|
23
|
+
assert predicate(match_info, web_request) == matched
|
|
Binary file
|
tests/test_request.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""Test request related code."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
import transaction
|
|
6
|
+
from pyramid.compat import text_type
|
|
7
|
+
import pyramid_basemodel
|
|
8
|
+
from sqlalchemy import create_engine
|
|
9
|
+
from sqlalchemy.orm import scoped_session, sessionmaker
|
|
10
|
+
from sqlalchemy.pool import NullPool
|
|
11
|
+
from zope.sqlalchemy import ZopeTransactionExtension
|
|
12
|
+
|
|
13
|
+
from pyramid_localize.models import Language
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.mark.parametrize('kwargs, expected_locale', (
|
|
17
|
+
( # not filled __LOCALE__ , should return default one
|
|
18
|
+
{'slug': 'some-slug'},
|
|
19
|
+
'en'
|
|
20
|
+
),
|
|
21
|
+
( # filled __LOCALE__ within available, returned exact that
|
|
22
|
+
{
|
|
23
|
+
'slug': 'some-slug',
|
|
24
|
+
'__LOCALE__': 'pl'
|
|
25
|
+
},
|
|
26
|
+
'pl'
|
|
27
|
+
),
|
|
28
|
+
( # filled __LOCALE__ within one not in available, returned default one
|
|
29
|
+
{
|
|
30
|
+
'slug': 'some-slug',
|
|
31
|
+
'__LOCALE__': 'fr'
|
|
32
|
+
},
|
|
33
|
+
'en'
|
|
34
|
+
),
|
|
35
|
+
))
|
|
36
|
+
def test_request(web_request, kwargs, expected_locale):
|
|
37
|
+
"""Test whether route-parameters gets filled correctly."""
|
|
38
|
+
route_params = web_request.default_locale(**kwargs)
|
|
39
|
+
assert '__LOCALE__' in route_params
|
|
40
|
+
assert route_params['__LOCALE__'] in web_request.registry['config'].localize.locales.available
|
|
41
|
+
assert route_params['__LOCALE__'] == expected_locale
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@pytest.fixture
|
|
45
|
+
def db_session(request):
|
|
46
|
+
"""SQLAlchemy session."""
|
|
47
|
+
from pyramid_localize.models import Base
|
|
48
|
+
|
|
49
|
+
engine = create_engine('sqlite:///fullauth.sqlite', echo=False, poolclass=NullPool)
|
|
50
|
+
pyramid_basemodel.Session = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
|
|
51
|
+
pyramid_basemodel.bind_engine(engine, pyramid_basemodel.Session, should_drop=True)
|
|
52
|
+
|
|
53
|
+
def destroy():
|
|
54
|
+
transaction.commit()
|
|
55
|
+
Base.metadata.drop_all(engine)
|
|
56
|
+
|
|
57
|
+
request.addfinalizer(destroy)
|
|
58
|
+
|
|
59
|
+
return pyramid_basemodel.Session
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@pytest.fixture
|
|
63
|
+
def db_locales(db_session):
|
|
64
|
+
"""Add Languages to db_session."""
|
|
65
|
+
for locale in ['pl', 'cz', 'fr']:
|
|
66
|
+
locale_object = Language(name=text_type(locale),
|
|
67
|
+
native_name=text_type(locale),
|
|
68
|
+
language_code=text_type(locale))
|
|
69
|
+
db_session.add(locale_object)
|
|
70
|
+
transaction.commit()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_locale_id(db_locales, web_request):
|
|
74
|
+
"""Test for creating, and getting loacel id."""
|
|
75
|
+
assert isinstance(web_request.locale_id, int)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_locales(db_locales, web_request):
|
|
79
|
+
"""test return locales list."""
|
|
80
|
+
assert len(web_request.locales()) == 3
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_locales_config(db_locales, web_request):
|
|
84
|
+
"""
|
|
85
|
+
test return locales list limited by config.
|
|
86
|
+
|
|
87
|
+
There's a new locale, so it should create new Language entry.
|
|
88
|
+
"""
|
|
89
|
+
assert len(web_request.locales(True)) == 4
|
tests/test_request.pyc
ADDED
|
Binary file
|