application development - separating content from function
Max M
maxm at mxm.dk
Thu Jun 20 19:06:48 EDT 2002
Chris Liechti wrote:
> start with:
> def _(s): return s
>
> and write all the string you want to localize later with
> _("hello")
> _("this can be translated later by replacing the _ function")
>
> later you can use locale or a simple dictionary lookup to translate.
> i saw that technique in "cplay" http://www.tf.hut.fi/~flu/cplay/
>
> simple with a dict:
> translation = {'hello':'ole'}
> def _(s):
> return translation.get(s,s)
I have a small class I sometimes use when I need to do i18n.
class I18n:
"Very simple i18n"
def __init__(self, textBundle, language='uk'):
self.language = language
self.textBundle = textBundle
def __call__(self, id):
language = getattr(self, 'language', self.language)
return self.textBundle[language].get(id,
'TRANSLATION MISSING!!')
textBundle = {}
textBundle['dk'] = {}
textBundle['dk']['name'] = 'Navn'
textBundle['dk']['address'] = 'Danmark'
textBundle['dk']['date_format'] = '%d-%m-%Y %H:%M:%S'
textBundle['dk']['money_format'] = '%.2f'
textBundle['uk'] = {}
textBundle['uk']['name'] = 'Name'
textBundle['uk']['address'] = 'Denmark'
textBundle['uk']['date_format'] = '%Y.%m.%d %H:%M:%S'
textBundle['uk']['money_format'] = '%.2f'
language = 'dk'
i18n = I18n(textBundle, language)
print i18n('names')
This works to my satisfaction most of the time.
##############################################################
A pattern I frequently use is the view- Adapter/wrapper::
The idea is that the "logic" object is a python object with python types
and methods as attributes.
To make a view of this ie. on a html page I create an adapter that takes
the logic view as a creation parameter, and then it puts a shell/wrapper
around the logic object to create a view without changing anything in
the logic object.
###############################################################
## The logic object
class User:
def __init__(self):
self.firstName = 'Max'
self.lastName = 'Møller <b>Sneaky code</b>'
self.answer = 42
self.books = [
'Learning Python',
'Python Essential Reference',
'Python & XML'
]
## The view adapter/wrapper
# allways escape untrusted code !
import cgi
class HtmlViewAdapter:
"this can be subclassed for several views"
def __init__(self, obj):
self._obj = obj
def __getitem__(self, item):
"Makes usage from string formatting easy"
value = getattr(self, item)
if callable(value):
return str(value())
else:
return str(value)
class UserHtmlViewAdapter(HtmlViewAdapter):
def firstName(self):
return cgi.escape(self._obj.firstName)
def lastName(self):
return cgi.escape(self._obj.lastName)
def answer(self):
return self._obj.lastName
def books(self):
return '\n'.join(
['Title %s<br>' % cgi.escape(book) \
for book in self._obj.books])
userTemplate = """
<table>
<tr>
<td>
<b>First name:</b> %(firstName)s<br>
</td>
<td>
<b>Last name:</b> %(lastName)s<br>
</td>
<td>
<b>Answer:</b> %(answer)s<br>
</td>
<td>
<b>Booklist:</b><br>
%(books)s<br>
</td>
</tr>
</table>
"""
user = User()
# pass the view adapter the user
userHtmlViewAdapter = UserHtmlViewAdapter(user)
# render the view
userHtmlView = userTemplate % userHtmlViewAdapter
print userHtmlView
###############################################################
The userHtmlViewAdapter can also be used for outputting directly to an
.asp page like:
###############
<% userView = UserHtmlViewAdapter(user) %>
<%
<table>
<tr>
<td>
<b>First name:</b> <%= userView.firstName()%><br>
</td>
<td>
<b>Last name:</b> <%= userView.lastName()%><br>
</td>
<td>
<b>Answer:</b> <%= userView.answer()%><br>
</td>
<td>
<b>Booklist:</b><br>
<%= userView.books()%><br>
</td>
</tr>
</table>
%>
This gives a good seperation of logic and view, and it's easy to see
months later where to put the generation of view.
You can also keep as much of your code as possible in pure Python
modules this way. Making it easier to test, debug, cross-platform etc.
regards Max M
More information about the Python-list
mailing list