Clean-up Localizer fork

Remove files/functionalities not needed by ERP5
parent 52146f5e
# -*- coding: UTF-8 -*-
# Copyright (C) 2000-2002 Juan David Ibáñez Palomar <jdavid@itaapy.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Import from Zope
from ExtensionClass import Base
class LocalAttribute(Base):
"""
Provides a way to override class variables, useful for example
for title (defined in SimpleItem).
"""
def __init__(self, id):
self.id = id
def __of__(self, parent):
return parent.getLocalAttribute(self.id)
class LocalAttributesBase:
def getLocalAttribute(self, name, lang=None):
""" """
raise NotImplemented
class LocalAttributes(LocalAttributesBase):
"""
Example of a 'LocalAttributesBase' derived class, this also a base class
for 'LocalFolder.LocalFolder' and 'Locale.Locale', it can be considered
the default implementation.
Returns attributes of the form <name>_<lang>. When <lang> has more than
one level, for example es-CO, the dashes are transformed to underscores,
as dashes aren't valid charecters for identifiers in Python. For example,
the call 'getLocalAttribute("long_date", "es-CO")' would return
'self.long_date_es_CO'.
"""
def getLocalAttribute(self, name, lang=None):
if lang is None:
lang = self.get_selected_language()
lang = lang.replace('-', '_')
name = '%s_%s' % (name, lang)
return getattr(self, name)
# -*- coding: UTF-8 -*-
# Copyright (C) 2000-2005 Juan David Ibáñez Palomar <jdavid@itaapy.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Import from the Standard Library
from hashlib import md5
# Import from itools
from itools.datatypes import LanguageTag
from itools.tmx import TMXFile, Sentence, TMXUnit
from itools.xliff import XLFFile
# Import from Zope
from Acquisition import aq_base, aq_parent
from App.class_init import InitializeClass
from App.Dialogs import MessageDialog
from OFS.SimpleItem import SimpleItem
from OFS.PropertyManager import PropertyManager
from Products.ZCatalog.CatalogPathAwareness import CatalogAware
from AccessControl import ClassSecurityInfo
# Import from Localizer
from LocalAttributes import LocalAttribute
from LocalFiles import LocalDTMLFile
from LocalPropertyManager import LocalPropertyManager
from utils import _
def md5text(str):
"""Create an MD5 sum (or hash) of a text. It is guaranteed to be 32 bytes
long.
"""
return md5(str.encode('utf-8')).hexdigest()
manage_addLocalContentForm = LocalDTMLFile('ui/LocalContent_add', globals())
def manage_addLocalContent(self, id, sourcelang, languages, REQUEST=None):
""" """
languages.append(sourcelang) # Make sure source is one of the target langs
self._setObject(id, LocalContent(id, sourcelang, tuple(languages)))
if REQUEST is not None:
return self.manage_main(self, REQUEST)
class LocalContent(CatalogAware, LocalPropertyManager, PropertyManager,
SimpleItem):
""" """
meta_type = 'LocalContent'
security = ClassSecurityInfo()
# Properties metadata
_local_properties_metadata = ({'id': 'title', 'type': 'string'},
{'id': 'body', 'type': 'text'})
_properties = ()
title = LocalAttribute('title') # Override title from SimpleItem
body = LocalAttribute('body')
manage_options = \
LocalPropertyManager.manage_options \
+ PropertyManager.manage_options[:1] \
+ ({'action': 'manage_import', 'label': u'Import',
'help': ('Localizer', 'MC_importExport.stx')},
{'action': 'manage_export', 'label': u'Export',
'help': ('Localizer', 'MC_importExport.stx')}) \
+ PropertyManager.manage_options[1:] \
+ SimpleItem.manage_options
def __init__(self, id, sourcelang, languages):
self.id = id
self._default_language = sourcelang
self._languages = languages
index_html = None # Prevent accidental acquisition
def __call__(self, client=None, REQUEST=None, RESPONSE=None, **kw):
if REQUEST is None:
REQUEST = self.REQUEST
# Get the template to use
template_id = 'default_template'
if hasattr(aq_base(self), 'default_template'):
template_id = self.default_template
# Render the object
template = getattr(aq_parent(self), template_id)
template = template.__of__(self)
return apply(template, ((client, self), REQUEST), kw)
# Override some methods to be sure that LocalContent objects are
# reindexed when changed.
def set_localpropvalue(self, id, lang, value):
LocalContent.inheritedAttribute('set_localpropvalue')(self, id, lang,
value)
self.reindex_object()
def del_localproperty(self, id):
LocalContent.inheritedAttribute('del_localproperty')(self, id)
self.reindex_object()
security.declareProtected('View management screens', 'manage_import')
manage_import = LocalDTMLFile('ui/LC_import_form', globals())
#######################################################################
# TMX support
security.declareProtected('View management screens', 'manage_export')
manage_export = LocalDTMLFile('ui/LC_export_form', globals())
security.declareProtected('Manage messages', 'tmx_export')
def tmx_export(self, REQUEST, RESPONSE):
"""Exports the content of the message catalog to a TMX file.
"""
src_lang = self._default_language
# Init the TMX handler
tmx = TMXFile()
tmx.header['creationtool'] = u'Localizer'
tmx.header['creationtoolversion'] = u'1.x'
tmx.header['datatype'] = u'plaintext'
tmx.header['segtype'] = u'paragraph'
tmx.header['adminlang'] = src_lang
tmx.header['srclang'] = src_lang
tmx.header['o-encoding'] = u'utf-8'
# Add the translation units
for key in self._local_properties.keys():
unit = TMXUnit({})
for lang in self._languages:
sentence = Sentence({'lang': lang})
trans, fuzzy = self.get_localproperty(key, lang)
sentence.text = trans
unit.msgstr[lang] = sentence
tmx.messages[self.get_localproperty(key, src_lang)[0]] = unit
# Serialize
data = tmx.to_str()
# Set response headers
RESPONSE.setHeader('Content-type','application/data')
RESPONSE.setHeader('Content-Disposition',
'attachment; filename="%s.tmx"' % self.id)
# Ok
return data
security.declareProtected('Manage messages', 'tmx_import')
def tmx_import(self, file, REQUEST=None, RESPONSE=None):
"""Imports a TMX level 1 file.
"""
try:
data = file.read()
tmx = TMXFile(string=data)
except:
return MessageDialog(title = 'Parse error',
message = _('impossible to parse the file') ,
action = 'manage_import',)
for id, msg in tmx.messages.items():
for prop, d in self._local_properties.items():
if d[self._default_language][0] == id:
msg.msgstr.pop(self._default_language)
for lang in msg.msgstr.keys():
# normalize the languageTag and extract the core
(core, local) = LanguageTag.decode(lang)
lang = LanguageTag.encode((core, local))
if lang not in self._languages:
self._languages += (lang,)
texte = msg.msgstr[lang].text
if texte:
self.set_localpropvalue(prop, lang, texte)
if core != lang and core != self._default_language:
if core not in self._languages:
self._languages += (core,)
if not msg.msgstr.has_key(core):
self.set_localpropvalue(prop, lang, texte)
if REQUEST is not None:
RESPONSE.redirect('manage_localPropertiesForm')
security.declareProtected('Manage messages', 'xliff_export')
def xliff_export(self, dst_lang, export_all=1, REQUEST=None,
RESPONSE=None):
""" Exports the content of the message catalog to an XLIFF file
"""
from DateTime import DateTime
src_lang = self._default_language
export_all = int(export_all)
# Init the XLIFF handler
xliff = XLFFile()
# Add the translation units
original = '/%s' % self.absolute_url(1)
for prop in self._local_properties.keys():
target, fuzzy = self.get_localproperty(prop, dst_lang)
msgkey, fuzzy = self.get_localproperty(prop, src_lang)
# If 'export_all' is true export all messages, otherwise export
# only untranslated messages
if export_all or not target:
unit = xliff.add_unit(original, msgkey, None)
unit.attributes['id'] = md5text(msgkey)
if target:
unit.target = target
# Set the file attributes
file = xliff.files[original]
attributes = file.attributes
attributes['original'] = original
attributes['product-name'] = u'Localizer'
attributes['product-version'] = u'1.1.x'
attributes['data-type'] = u'plaintext'
attributes['source-language'] = src_lang
attributes['target-language'] = dst_lang
attributes['date'] = DateTime().HTML4()
# Serialize
xliff = xliff.to_str()
# Set response headers
RESPONSE.setHeader('Content-Type', 'text/xml; charset=UTF-8')
filename = '%s_%s_%s.xlf' % (self.id, src_lang, dst_lang)
RESPONSE.setHeader('Content-Disposition',
'attachment; filename="%s"' % filename)
# Ok
return xliff
security.declareProtected('Manage messages', 'xliff_import')
def xliff_import(self, file, REQUEST=None):
""" XLIFF is the XML Localization Interchange File Format
designed by a group of software providers.
It is specified by www.oasis-open.org
"""
try:
data = file.read()
xliff = XLFFile(string=data)
except:
return MessageDialog(title = 'Parse error',
message = _('impossible to parse the file') ,
action = 'manage_import',)
num_trans = 0
(file_ids, sources, targets) = xliff.get_languages()
# update languages
if len(sources) > 1 or sources[0] != self._default_language:
return MessageDialog(title = 'Language error',
message = _('incompatible language sources') ,
action = 'manage_import',)
for lang in targets:
if lang != self._default_language and lang not in self._languages:
self._languages += (lang,)
# get messages
for file in xliff.files:
cur_target = file.attributes.get('target-language', '')
for msg in file.body.keys():
for (prop, val) in self._local_properties.items():
if val[self._default_language][0] == msg:
if cur_target and file.body[msg].target:
texte = file.body[msg].target
self.set_localpropvalue(prop, cur_target, texte)
num_trans += 1
if REQUEST is not None:
return MessageDialog(
title = _(u'Messages imported'),
message = (_(u'Imported %d messages to %s') %
(num_trans, ' '.join(targets))),
action = 'manage_localPropertiesForm')
InitializeClass(LocalContent)
# -*- coding: UTF-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2000-2005 Juan David Ibáñez Palomar <jdavid@itaapy.com> # Copyright (C) 2000-2005 Juan David Ibáñez Palomar <jdavid@itaapy.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
...@@ -47,29 +47,3 @@ class LocalDTMLFile(DomainAware, DTMLFile): ...@@ -47,29 +47,3 @@ class LocalDTMLFile(DomainAware, DTMLFile):
bound_data['gettext'] = self.gettext bound_data['gettext'] = self.gettext
return apply(LocalDTMLFile.inheritedAttribute('_exec'), return apply(LocalDTMLFile.inheritedAttribute('_exec'),
(self, bound_data, args, kw)) (self, bound_data, args, kw))
# Zope Page Templates (ZPT)
# XXX Deprecated, use the i18n namespace instead.
try:
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
except ImportError:
# If ZPT is not installed
class LocalPageTemplateFile:
pass
else:
class LocalPageTemplateFile(DomainAware, PageTemplateFile):
""" """
def __init__(self, name, _prefix=None, **kw):
PageTemplateFile.__init__(self, name, _prefix, **kw)
DomainAware.__init__(self, _prefix)
def _exec(self, bound_data, args, kw):
# Add our gettext first
bound_data['gettext'] = self.gettext
return apply(LocalPageTemplateFile.inheritedAttribute('_exec'),
(self, bound_data, args, kw))
# -*- coding: UTF-8 -*-
# Copyright (C) 2000-2004 Juan David Ibáñez Palomar <jdavid@itaapy.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Import from Zope
from App.Common import package_home
from OFS.Folder import Folder
# Import from Localizer
from LanguageManager import LanguageManager
from LocalFiles import LocalDTMLFile
from LocalAttributes import LocalAttribute, LocalAttributes
from utils import _
manage_addLocalFolderForm = LocalDTMLFile('ui/LocalFolder_add', globals())
def manage_addLocalFolder(self, id, title, languages, REQUEST=None):
""" """
id = id.strip()
self._setObject(id, LocalFolder(id, title, languages))
if REQUEST is not None:
return self.manage_main(self, REQUEST)
class LocalFolder(LanguageManager, LocalAttributes, Folder):
""" """
meta_type = 'LocalFolder'
_properties = ({'id': 'title', 'type': 'string'},)
def __init__(self, id, title, languages):
self.id = id
self.title = title
# Language Manager data
self._languages = tuple(languages)
self._default_language = languages[0]
# Local attributes
self._local_attributes = ()
manage_options = \
Folder.manage_options[:1] \
+ ({'action': 'manage_attributes', 'label': u'Attributes'},) \
+ LanguageManager.manage_options \
+ Folder.manage_options[1:]
# Manage attributes
manage_attributes = LocalDTMLFile('ui/LocalFolder_attributes', globals())
def get_local_attributes(self):
return self._local_attributes
def manage_delAttributes(self, attributes, REQUEST=None, RESPONSE=None):
""" """
local_attributes = list(self._local_attributes)
for attr in attributes:
local_attributes.remove(attr)
delattr(self, attr)
self._local_attributes = tuple(local_attributes)
if RESPONSE is not None:
RESPONSE.redirect("%s/manage_attributes" % REQUEST['URL1'])
def manage_addAttribute(self, id, REQUEST=None, RESPONSE=None):
""" """
id = id.strip()
setattr(self, id, LocalAttribute(id))
self._local_attributes = self._local_attributes + (id,)
if RESPONSE is not None:
RESPONSE.redirect("%s/manage_attributes" % REQUEST['URL1'])
# -*- coding: UTF-8 -*-
# Copyright (C) 2000-2004 Juan David Ibáñez Palomar <jdavid@itaapy.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Import from the Standard Library
from urllib import quote
from time import time
# Import from Zope
from AccessControl import ClassSecurityInfo
from Acquisition import aq_base
from App.class_init import InitializeClass
# Import from Localizer
from LanguageManager import LanguageManager
from LocalAttributes import LocalAttribute, LocalAttributesBase
from LocalFiles import LocalDTMLFile
# FIXME
# For backwards compatibility (<= 0.8.0): other classes import 'LocalProperty'
# Since this may be stored as a persistent value, we cannot remove it, first
# we must provide an upgrade facility
LocalProperty = LocalAttribute
class LocalPropertyManager(LanguageManager, LocalAttributesBase):
"""
Mixin class that allows to manage localized properties.
Somewhat similar to OFS.PropertyManager.
"""
security = ClassSecurityInfo()
# Metadata for local properties
# Example: ({'id': 'title', 'type': 'string'},)
_local_properties_metadata = ()
# Local properties are stored here
# Example: {'title': {'en': ('Title', timestamp), 'es': ('Títul', timestamp)}}
_local_properties = {}
# Useful to find or index all LPM instances
isLocalPropertyManager = 1
def getLocalPropertyManager(self):
"""
Returns the instance, useful to get the object through acquisition.
"""
return self
manage_options = (
{'action': 'manage_localPropertiesForm',
'label': u'Local properties',
'help': ('Localizer', 'LPM_properties.stx')},
{'action': 'manage_transPropertiesForm',
'label': u'Translate properties',
'help': ('Localizer', 'LPM_translate.stx')}) \
+ LanguageManager.manage_options
security.declarePublic('hasLocalProperty')
def hasLocalProperty(self, id):
"""Return true if object has a property 'id'"""
for property in self._local_properties_metadata:
if property['id'] == id:
return 1
return 0
security.declareProtected('View management screens',
'manage_localPropertiesForm')
manage_localPropertiesForm = LocalDTMLFile('ui/LPM_properties', globals())
security.declareProtected('View management screens',
'manage_transPropertiesForm')
manage_transPropertiesForm = LocalDTMLFile('ui/LPM_translations', globals())
security.declareProtected('Manage properties', 'set_localpropvalue')
def set_localpropvalue(self, id, lang, value):
# Get previous value
old_value, timestamp = self.get_localproperty(id, lang)
if old_value is None:
old_value = ''
# Update value only if it is different
if value != old_value:
properties = self._local_properties.copy()
if not properties.has_key(id):
properties[id] = {}
properties[id][lang] = (value, time())
self._local_properties = properties
def get_localproperty(self, name, language):
if name not in self._local_properties:
return None, None
property = self._local_properties[name]
if language not in property:
return None, None
value = property[language]
if isinstance(value, tuple):
return value
return value, None
security.declareProtected('Manage properties', 'set_localproperty')
def set_localproperty(self, id, type, lang=None, value=None):
"""Adds a new local property"""
if not self.hasLocalProperty(id):
self._local_properties_metadata += ({'id': id, 'type': type},)
setattr(self, id, LocalAttribute(id))
if lang is not None:
self.set_localpropvalue(id, lang, value)
security.declareProtected('Manage properties', 'del_localproperty')
def del_localproperty(self, id):
"""Deletes a property"""
# Update properties metadata
p = [ x for x in self._local_properties_metadata if x['id'] != id ]
self._local_properties_metadata = tuple(p)
# delete attribute
try:
del self._local_properties[id]
except KeyError:
pass
try:
delattr(self, id)
except KeyError:
pass
security.declareProtected('Manage properties', 'manage_addLocalProperty')
def manage_addLocalProperty(self, id, type, REQUEST=None, RESPONSE=None):
"""Adds a new local property"""
self.set_localproperty(id, type)
if RESPONSE is not None:
url = "%s/manage_localPropertiesForm?manage_tabs_message=Saved changes." % REQUEST['URL1']
RESPONSE.redirect(url)
security.declareProtected('Manage properties', 'manage_editLocalProperty')
def manage_editLocalProperty(self, REQUEST, RESPONSE=None):
"""Edit a property"""
def_lang = self.get_default_language()
form = REQUEST.form
for prop in self.getLocalProperties():
name = prop['id']
if form.has_key(name):
value = form[name].strip()
self.set_localpropvalue(name, def_lang, value)
if REQUEST is not None:
url = "%s/%s?manage_tabs_message=Saved changes." \
% (REQUEST['URL1'], REQUEST['destination'])
REQUEST.RESPONSE.redirect(url)
security.declareProtected('Manage properties', 'manage_delLocalProperty')
def manage_delLocalProperty(self, ids=[], REQUEST=None, RESPONSE=None):
"""Deletes a property"""
for id in ids:
self.del_localproperty(id)
if RESPONSE is not None:
url = "%s/manage_localPropertiesForm?manage_tabs_message=Saved changes." % REQUEST['URL1']
RESPONSE.redirect(url)
security.declareProtected('Manage properties', 'manage_transLocalProperty')
def manage_transLocalProperty(self, id, code, value, REQUEST,
RESPONSE=None):
"""Translate a property."""
self.set_localpropvalue(id, code, value.strip())
if RESPONSE is not None:
url = "%s/%s?lang=%s&prop=%s&manage_tabs_message=Saved changes." \
% (REQUEST['URL1'], REQUEST['destination'], code, id)
RESPONSE.redirect(url)
security.declareProtected('Manage properties', 'is_obsolete')
def is_obsolete(self, prop, lang):
default_language = self.get_default_language()
value, t0 = self.get_localproperty(prop, default_language)
value, t1 = self.get_localproperty(prop, lang)
if t0 is None:
return False
if t1 is None:
return True
return t1 < t0
security.declarePublic('getTargetLanguages')
def get_targetLanguages(self):
"""Get all languages except the default one."""
def_lang = self.get_default_language()
all_langs = self.get_languages_mapping()
for record in all_langs:
if def_lang == record['code']:
all_langs.remove(record)
return all_langs
security.declarePublic('getLocalProperties')
def getLocalProperties(self):
"""Returns a copy of the properties metadata."""
return tuple([ x.copy() for x in self._local_properties_metadata ])
security.declarePublic('getLocalAttribute')
def getLocalAttribute(self, id, lang=None):
"""Returns a local property"""
# No language, look for the first non-empty available version
if lang is None:
lang = self.get_selected_language(property=id)
value, timestamp = self.get_localproperty(id, lang)
if value is None:
return ''
return value
# Languages logic
security.declarePublic('get_available_languages')
def get_available_languages(self, **kw):
""" """
languages = self.get_languages()
id = kw.get('property', None)
if id is None:
# Is this thing right??
return languages
else:
if id in self._local_properties:
property = self._local_properties[id]
return [ x for x in languages if property.get(x, None) ]
else:
return []
security.declarePublic('get_default_language')
def get_default_language(self):
""" """
if self._default_language:
return self._default_language
languages = self.get_languages()
if languages:
return languages[0]
return None
# Upgrading..
def _needs_upgrade(self):
return hasattr(aq_base(self), 'original_language')
def _upgrade(self):
# In version 0.7 the language management logic moved to the
# mixin class LanguageManager, as a consequence the attribute
# "original_language" changes its name to "_default_language".
if hasattr(aq_base(self), 'original_languge'):
self._default_language = self.original_language
del self.original_language
# XXX With version 1.1.0b5 (as of patch 14) the '_local_properties'
# data structure keeps a timestamp to mark obsolete translations.
# The upgrade code below must be activated once the new upgrade
# framework is deployed, something that should happen for the 1.2
# release.
## for k, v in self._local_properties.items():
## for i, j in v.items():
## if type(j) is not tuple:
## # XXX add the timestamp for every property
## self._local_properties[k][i] = (j, time())
## self._p_changed = 1
# Define <id>_<lang> attributes, useful for example to catalog
def __getattr__(self, name):
try:
index = name.rfind('_')
id, lang = name[:index], name[index+1:]
property = self._local_properties[id]
except:
raise AttributeError, "%s instance has no attribute '%s'" \
% (self.__class__.__name__, name)
return self.getLocalAttribute(id, lang)
InitializeClass(LocalPropertyManager)
# -*- coding: UTF-8 -*-
# Copyright (C) 2000-2002 Juan David Ibáñez Palomar <jdavid@itaapy.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Import from Localizer
from LocalAttributes import LocalAttributes, LocalAttribute
class Locale(LocalAttributes):
# Time, hours and minutes
time = LocalAttribute('time')
def time_en(self, datetime):
return datetime.strftime('%H:%M')
def time_es(self, datetime):
return datetime.strftime('%H.%M')
# -*- coding: UTF-8 -*-
# Copyright (C) 2002-2004 Juan David Ibáñez Palomar <jdavid@itaapy.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
This module makes more easy to implement multilingual Zope products based
on Localizer that also work when Localizer is not installed (they are
monolingual in this situation).
It provides dummy versions of some Localizer features. To internationalize
your code copy and paste this module to your product directory and, in the
modules you need it, just type:
from LocalizerSupport import _
from LocalizerSupport import LocalDTMLFile as DTMLFile
from LocalizerSupport import LocalPageTemplateFile as PageTemplateFile
Another option is not to rename the classes, then you will have to
change from 'DTMLFile' to 'LocalDTMLFile' and from 'PageTemplateFile'
to 'LocalPageTemplateFile' wherever you need it.
Note that Localizer requieres Python 2.4 or above, so the multilingual
version of your product will also requiere Python 2.4 or above.
Of course, you don't need to import the features you don't need.
"""
# The version information refers to the Localizer product version.
# If you change this module, please update the version number to
# show it.
__version__ = '1.2.0'
try:
from Products.Localizer import LocalDTMLFile, LocalPageTemplateFile
from Products.Localizer import _
except ImportError:
# For Python code
def _(message, language=None):
"""
Used to markup a string for translation but without translating it,
this is known as deferred translations.
"""
return message
# For DTML and Page Templates
def gettext(self, message, language=None):
""" """
return message
# Document Template Markup Langyage (DTML)
from Globals import DTMLFile
class LocalDTMLFile(DTMLFile):
def _exec(self, bound_data, args, kw):
# Add our gettext first
bound_data['gettext'] = self.gettext
return apply(LocalDTMLFile.inheritedAttribute('_exec'),
(self, bound_data, args, kw))
gettext = gettext
# Zope Page Templates (ZPT)
try:
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
except ImportError:
# If ZPT is not installed
class LocalPageTemplateFile:
pass
else:
class LocalPageTemplateFile(PageTemplateFile):
def _exec(self, bound_data, args, kw):
# Add our gettext first
bound_data['gettext'] = self.gettext
return apply(LocalPageTemplateFile.inheritedAttribute('_exec'),
(self, bound_data, args, kw))
gettext = gettext
# Dummy dtml-gettext tag
from DocumentTemplate.DT_Util import InstanceDict, namespace, render_blocks
class GettextTag:
""" """
name = 'gettext'
blockContinuations = ()
def __init__(self, blocks):
tname, args, section = blocks[0]
self.section = section.blocks
def __call__(self, md):
ns = namespace(md)[0]
md._push(InstanceDict(ns, md))
message = render_blocks(self.section, md)
md._pop(1)
return message
# Register the dtml-gettext tag
from DocumentTemplate.DT_String import String
if not String.commands.has_key('gettext'):
String.commands['gettext'] = GettextTag
PYTHON=python
po:
${PYTHON} zgettext.py *.py ui/*.dtml -l ca de es eu fr hu it ja pt ru
mo:
${PYTHON} zgettext.py -m
clean:
rm -f *~ *.pyc
rm -f locale/*~ locale/locale.pot.bak locale/*.mo
rm -f help/*~
rm -f tests/*~ tests/*.pyc
rm -f ui/*~
test:
${PYTHON} tests/test_zgettext.py
binary: clean mo
rm -f refresh.txt
...@@ -665,109 +665,6 @@ class MessageCatalog(LanguageManager, ObjectManager, SimpleItem): ...@@ -665,109 +665,6 @@ class MessageCatalog(LanguageManager, ObjectManager, SimpleItem):
manage_Export_form = LocalDTMLFile('ui/MC_Export_form', globals()) manage_Export_form = LocalDTMLFile('ui/MC_Export_form', globals())
security.declareProtected('Manage messages', 'tmx_export')
def tmx_export(self, REQUEST, RESPONSE=None):
"""Exports the content of the message catalog to a TMX file
"""
src_lang = self._default_language
# Get the header info
header = self.get_po_header(src_lang)
charset = header['charset']
# Init the TMX handler
tmx = TMXFile()
tmx.header['creationtool'] = u'Localizer'
tmx.header['creationtoolversion'] = u'1.x'
tmx.header['datatype'] = u'plaintext'
tmx.header['segtype'] = u'paragraph'
tmx.header['adminlang'] = src_lang
tmx.header['srclang'] = src_lang
tmx.header['o-encoding'] = u'%s' % charset.lower()
# handle messages
for msgkey, transunit in self._messages.items():
unit = TMXUnit({})
for lang in transunit.keys():
if lang != 'note':
sentence = Sentence({'lang': lang})
sentence.text = transunit[lang]
unit.msgstr[lang] = sentence
if src_lang not in transunit.keys():
sentence = Sentence({'lang': src_lang})
sentence.text = msgkey
unit.msgstr[src_lang] = sentence
if transunit.has_key('note'):
note = TMXNote(transunit.get('note'))
unit.notes.append(note)
tmx.messages[msgkey] = unit
if RESPONSE is not None:
RESPONSE.setHeader('Content-type','application/data')
RESPONSE.setHeader('Content-Disposition',
'attachment; filename="%s.tmx"' % self.id)
return tmx.to_str()
security.declareProtected('Manage messages', 'tmx_import')
def tmx_import(self, howmuch, file, REQUEST=None, RESPONSE=None):
"""Imports a TMX level 1 file.
"""
try:
data = file.read()
tmx = TMXFile(string=data)
except:
return MessageDialog(title = 'Parse error',
message = _('impossible to parse the file') ,
action = 'manage_Import_form',)
num_notes = 0
num_trans = 0
if howmuch == 'clear':
# Clear the message catalogue prior to import
self._messages = {}
self._languages = ()
self._default_language = tmx.get_srclang()
for id, msg in tmx.messages.items():
if not self._messages.has_key(id) and howmuch == 'existing':
continue
msg.msgstr.pop(self._default_language)
if not self._messages.has_key(id):
self._messages[id] = {}
for lang in msg.msgstr.keys():
# normalize the languageTag and extract the core
(core, local) = LanguageTag.decode(lang)
lang = LanguageTag.encode((core, local))
if lang not in self._languages:
self._languages += (lang,)
if msg.msgstr[lang].text:
self._messages[id][lang] = msg.msgstr[lang].text
if core != lang and core != self._default_language:
if core not in self._languages:
self._languages += (core,)
if not msg.msgstr.has_key(core):
self._messages[id][core] = msg.msgstr[lang].text
if msg.notes:
ns = [m.text for m in msg.notes]
self._messages[id]['note'] = u' '.join(ns)
num_notes += 1
num_trans += 1
if REQUEST is not None:
message = _(u'Imported %d messages and %d notes')
return MessageDialog(
title = _(u'Messages imported'),
message = message % (num_trans, num_notes),
action = 'manage_messages')
####################################################################### #######################################################################
# Backwards compatibility (XXX) # Backwards compatibility (XXX)
####################################################################### #######################################################################
...@@ -775,116 +672,6 @@ class MessageCatalog(LanguageManager, ObjectManager, SimpleItem): ...@@ -775,116 +672,6 @@ class MessageCatalog(LanguageManager, ObjectManager, SimpleItem):
hasmsg = message_exists hasmsg = message_exists
hasLS = message_exists # CMFLocalizer uses it hasLS = message_exists # CMFLocalizer uses it
security.declareProtected('Manage messages', 'xliff_export')
def xliff_export(self, dst_lang, export_all=1, REQUEST=None,
RESPONSE=None):
"""Exports the content of the message catalog to an XLIFF file
"""
from DateTime import DateTime
src_lang = self._default_language
export_all = int(export_all)
# Init the XLIFF handler
xliff = XLFFile()
# Add the translation units
original = '/%s' % self.absolute_url(1)
for msgkey, transunit in self._messages.items():
target = transunit.get(dst_lang, '')
# If 'export_all' is true export all messages, otherwise export
# only untranslated messages
if export_all or not target:
unit = xliff.add_unit(original, msgkey, None)
unit.attributes['id'] = md5text(msgkey)
if target:
unit.target = target
# Add note
note = transunit.get('note')
if note:
unit.notes.append(XLFNote(note))
# build the data-stucture for the File tag
file = xliff.files[original]
attributes = file.attributes
attributes['original'] = original
attributes['product-name'] = u'Localizer'
attributes['product-version'] = u'1.1.x'
attributes['data-type'] = u'plaintext'
attributes['source-language'] = src_lang
attributes['target-language'] = dst_lang
attributes['date'] = DateTime().HTML4()
# Serialize
xliff = xliff.to_str()
# Set response headers
RESPONSE.setHeader('Content-Type', 'text/xml; charset=UTF-8')
filename = '%s_%s_%s.xlf' % (self.id, src_lang, dst_lang)
RESPONSE.setHeader('Content-Disposition',
'attachment; filename="%s"' % filename)
# Ok
return xliff
security.declareProtected('Manage messages', 'xliff_import')
def xliff_import(self, howmuch, file, REQUEST=None):
"""XLIFF is the XML Localization Interchange File Format designed by a
group of software providers. It is specified by www.oasis-open.org
"""
try:
data = file.read()
xliff = XLFFile(string=data)
except:
return MessageDialog(title = 'Parse error',
message = _('impossible to parse the file') ,
action = 'manage_Import_form',)
num_notes = 0
num_trans = 0
(file_ids, sources, targets) = xliff.get_languages()
if howmuch == 'clear':
# Clear the message catalogue prior to import
self._messages = {}
self._languages = ()
self._default_language = sources[0]
# update languages
if len(sources) > 1 or sources[0] != self._default_language:
return MessageDialog(title = 'Language error',
message = _('incompatible language sources') ,
action = 'manage_Import_form',)
for lang in targets:
if lang != self._default_language and lang not in self._languages:
self._languages += (lang,)
# get messages
for file in xliff.files:
cur_target = file.attributes.get('target-language', '')
for msg in file.body.keys():
if not self._messages.has_key(msg) and howmuch == 'existing':
pass
else:
if not self._messages.has_key(msg):
self._messages[msg] = {}
if cur_target and file.body[msg].target:
self._messages[msg][cur_target] = file.body[msg].target
num_trans += 1
if file.body[msg].notes:
ns = [n.text for n in file.body[msg].notes]
comment = ' '.join(ns)
self._messages[msg]['note'] = comment
num_notes += 1
if REQUEST is not None:
return MessageDialog(
title = _(u'Messages imported'),
message = (_(u'Imported %d messages and %d notes to %s') % \
(num_trans, num_notes, ' '.join(targets))),
action = 'manage_messages')
class POFile(SimpleItem): class POFile(SimpleItem):
""" """ """ """
......
This is a fork of the Localizer product, as found originally at:
Localizer is the de-facto standard to build multilingual applications with https://github.com/hforge/Localizer
Zope. It helps to internationalize and localize Zope products and to build
multilingual web sites through the Management Interface. It deals with
both user interfaces and content.
All functionality not explicitly used by ERP5 has been or will be removed.
Requirements Moreover, all monkey-patches, and all dependencies on itools should be
moved into native Zope APIs.
- Python 2.5.2 or later
- Zope 2.12.2 or later
- itools 0.50.6 or later (download from
"http://www.hforge.org/itools":http://www.hforge.org/itools)
Installation
Download Localizer. Unpack the tarball and install it in the "Products"
directory::
$ tar xzf Localizer-1.3.0.tar.gz
$ cp -r Localizer-1.3.0 <Zope instance>/Products/Localizer
Another option, case you are running Unix, is to use symbolic links::
$ ln -s Localizer-1.3.0 <Zope instance>/Products/Localizer
Resources
- "Home site":http://www.localizer.org/
- "Mailing list subscription":http://www.hforge.org/community
- "Mailing list archives":http://archives.hforge.org/index.cgi?list=localizer
- "Bug Tracker":http://bugs.hforge.org/
Examples of sites powered by Localizer
- "European Environment Agency":http://www.eea.eu.int/
- "Bank Winter":http://www.bankwinter.com/
- "Castagnari":http://www.castagnari.com/
- "Hiru":http://www.hiru.com/
- "Hotsak":http://www.hotsak.com/
- "Ego Ibarra":http://www.egoibarra.com/
- "Udaleuskaltegiak":http://www.udaleuskaltegiak.net/
The copyright notice of the original code is as follows:
Author and License Author and License
......
Localizer 1.3.0 (2009/XX/XX)
============================
Localizer is a Zope product for developers and web masters. Localizer
solves the problem of building multilingual products and web sites,
ranging from internationalization and localization of the user
interface to management of multilingual content.
What is new?
------------
Upgraded to Zope 2.12, Python 2.5 and itools 0.50 (previous versions are
not supported).
Some API obsolete since at least 2004 has been removed:
- The 'ugettext' function has been removed from DTML and ZPT templates,
use instead 'gettext'.
- Four methods from the 'LocalPropertyManger' class have been removed:
_setLocalPropValue => set_localpropvalue
_setLocalProperty => set_localproperty
_delLocalProperty => del_localproperty
getLocalProperty => getLocalAttribute
Resources
---------
Download
http://download.hforge.org/localizer/Localizer-1.3.0.tar.gz
http://download.hforge.org/itools/0.50/itools-0.50.7.tar.gz
Home
http://www.localizer.org/
Mailing list
http://www.hforge.org/community
http://archives.hforge.org/index.cgi?list=localizer
Bug Tracker
http://bugs.hforge.org/
See http://in-girum.net/cgi-bin/bugzilla/index.cgi
Things should be removed from here and added to the bug tracker.
Bugs
----
- Bo M. Maryniuck:
"I can't reproduce the error anymore though I can't send you traceback,
but I just found, that Localizer crashes Medusa threads if someone else
object uses "register before traverse". In my case there is an product,
which is always modifies the request. So if I put there also Localizer,
you'll never enter the site.
Quality Assurance
-----------------
- Audit the code, update the idioms (e.g. use "get_context" to access the
request and response objects).
API
---
- When importing modules from Localizer, either the sort or the long
way should always be used. Update the documentation to reflect it
(Rainer Thaden).
Where the sort form is:
from Products.Localizer import LocalPropertyManager
and the long form is:
from Products.Localizer.LocalPropertyManager import LocalPropertyManager
See if this can be addressed without compromising backwards compatibility,
if not document exactly which is the current situation.
- Develop an API to get messages and translations from the message catalog,
see email from Pierre-Yves Delens.
- Implement the whole mapping interface in the "AcceptLanguage" and
"AcceptCharset" classes (itools.i18n.accept). Sugested by Bjorn.
Documentation
-------------
- Update (rewrite) the documentation. Most likely to be in latex, and
distributed with the source.
- Add a section "Localizer application anatomy" to the tutorial:
"One thing you may want to consider is an overview of how a site
using all the products should be laid out. The examples and guide
you are providing are very very good and explain all the techcinal
components of the variouse packages quite well. What seems to be
missing is a higher level view that ties it all together in terms
of layout for a demo site.
An example of a 2-3 language basic site that uses the variouse
components would be very attractive for new programs and users
(moi) and help the adoption of this most excellent product."
- Comment about "management_page_charset" to switch the ZMI to utf-8,
or maybe patch Zope so they're in utf-8 by default.
Localizer.org
-------------
- Kill "http://www.j-david.net/software/localizer", everything should be
in "http://www.ikaaro.org/localizer".
User Interface (ZMI)
--------------------
- Complete the help screens.
- Be sure the framed messages appear in all the management screens every
time an action is performed, i.e. "Content changed (2002-02-08 15:26)".
- Add PrincipiaSearchSource
Standards Support
-----------------
- Support fuzzy in "itools.handlers.PO".
- Use the library libgettextpo introduced in gettext 0.12 to parse the
PO files?? See the docs: "Writing your own programs that process PO
files"
Message Extraction
------------------
- Kill "zgettext", use "igettext" from "itools.i18n" instead.
- Add support for ZPT to "igettext". This means to implement part of
the "i18n" namespace in "itools.xml.ZPT". See [1] for a sample code.
[1] http://savannah.nongnu.org/cgi-bin/viewcvs/opental/opental/OpenPTi18n/i18n_xgettext.py?rev=1.8&content-type=text/vnd.viewcvs-markup
Not yet classified
------------------
- (Zope bug) See if something feasible can be done to remove the hardcoded
use of Latin-1 encoding from Zope and Localizer.
If not, explain which the problems are and what the developer can
do (add this as a task for the documentation).
- When importing a message catalog, should be done something with
the header? When managing the message catalog through FTP, should
the header also be editable?
- François Meehan:
"Also found that using the import/export function in Localizer/zope
can bring corruption to the po file, a problem with the accents it
seems."
- Document the path where Localizer.changeLanguage sets the cookie,
which is the path from where it is called, not its physical path.
See the mails exchanged with Claus Rosenberger. Maybe a FAQ?
- Work on locale information: dates, money, etc..
- Integrate the File System Message Catalog from CMFLocalizer.
- Add the ability to manage localized versions of standard files
in a product: the on-line help system, README.txt, etc..
- Let to implement ZClasses that inherite from 'MessageCatalog'
- Set the 'Vary' header.
The problem is: which value should it have?
This could allow to remove the patch to Zope for images, if UA
take care of the 'Vary' header.
- Rework 'changeLanguageForm' to support browsers without javascript.
- Build user management interfaces similar to the ZMI
(standard_html_header/footer instead of manage_page_header/footer
and manage_tabs).
***************************************************************************
Localizer 0.8.1
***************************************************************************
* The request variable USER_PREF_LANGUAGES isn't a list anymore,
now it's an object that represents a tree. Any code that directly
reads or modifies USER_PREF_LANGUAGES will be broken. Tell me
if you did it.
* The Localizer class provides a feature known as "locale folders"
that lets to manage any kind of multilingual content. Now this
feature is deprecated. A new class named "LocalFolder" provides
a better solution for this, please move to it as soon as posible,
in the next release the deprecated feature will be removed!!
The quickest way to move from "Localizer" to "LocalFolder" is:
0. Do a backup of the database;
1. Create in the root of your web site a "LocalFolder" instance called,
for example, "locale";
2. Go to the management screens of "locale" and create an attribute
named, for example, "folder";
3. Add as many languages as needed in the tab "Languages";
4. Create a folder for every language in the "Contents" tab, for
example, "folder_en", "folder_es", etc..;
5. For each language copy all the stuff from the Localizer instance
to "locale". For example, copy everything in "Localizer/es" to
"locale/folder_es";
6. Now the most time expensive step, go to all the templates and scripts
that refer to any object in the "Localizer" instance and change to
use "locale" instead.
For example, if you had an image named "logo" and you called it with:
<dtml-var logo>
change it to:
<dtml-with locale><dtml-var logo></dtml-with>
or to:
<dtml-var "locale.logo()">
Hopefully you will have to modify few methods;
7. And finally, remove the "Localizer" instance!!
* The previous way to internationalize Python code from Python
products has been deprecated. Read the documentation to know
how it should be done from now on. However, the deprecated
way will be preserved for a while, probably a long while.
***************************************************************************
Localizer 0.8.0
***************************************************************************
* The 0.7 version saw a big redesign of message catalogs, and
also of the way they're used. Before they were implicitly called,
through a globaly available "gettext" method, this feature
was implemented in the "Localizer" class.
In the 0.7 version message catalogs became an independent class,
its instances are explicitly called. The old way to use message
catalogs was preserved for backwards compatibility.
Now, in version 0.8, the old way to use message catalogs (through
the global "gettext" method) has been removed. To upgrade to this
version follow the steps:
0. If you upgrade from a version previous to 0.7 upgrade first
to 0.7.x
1. Move all your 'MessageCatalog' instances with the id
'Messages' that are inside of a 'Localizer' instance
to the same level in the hierarchy where is the
'Localizer' object, but with the name 'gettext'.
For example if you have "/a/b/c/Localizer/Messages" you
should move the 'Messages' object to "/a/b/c/gettext".
[!] This will work in most situations, you only could get
wrong behaviour if you're using Localizer instances
inside other Localizer instances. For example if you
have the objects "/a/b/c/Localizer/Messages" and
"/a/b/c/d/Localizer/Messages".
I guess very few people, if any, will have a configuration
like this one, so I don't provide any upgrade path. If
you've something like this send me an email before doing
anything.
2. Don't do anything for a few days, just to be sure that
everything works.
3. Upgrade to the 0.8 version.
Don't hesitate to contact me if you have any problem or doubt.
***************************************************************************
Localizer 0.7.0
***************************************************************************
* There're several changes that require all Localizer instances
to be upgraded, to do so go to the management interfaces of
each Localizer instance and click the "upgrade" button that
will appear.
Be careful, the upgrading must be done with access rules
deactivated, for example: "www.foo.com/bar/Z/manage"
* LocalContent instances and other instances of classes that
inherit from LocalPropertyManager also need to be upgraded.
To do it just run the same script used to upgrade to the
0.6 version, it is:
obs = context.ZopeFind(context, None, None, None,
'isLocalPropertyManager == 1',
None, None, None, None, 1)
for path, ob in obs:
ob.manage_upgrade()
return '%d objects upgraded' % len(obs)
* There're several changes in the API that could break your
code if you have used directly the Localizer API, if in
doubt send me an email.
***************************************************************************
Localizer 0.6.1
***************************************************************************
Before 0.6.0 changeLanguageForm was a LocalDTMLFile, in 0.6.0
I changed it to a DTML Method. Now it's again a LocalDTMLFile.
To upgrade go to each Localizer instance and remove the
changeLanguageForm method. If you don't do it nothing will
break, but anyway it's encouraged.
If you're curious about this change, it's because I've finally
discovered which is the difference between DTMLFile and HTMLFile:
bindings can be used from a DTMLFile.
***************************************************************************
Localizer 0.6
***************************************************************************
* LocalContent and LocalPropertyManager
All LocalContent objects and instances of classes that inherit
from LocalPropertyManager need to be upgraded.
Create and run a Python script in the root with the code:
obs = context.ZopeFind(context, None, None, None,
'isLocalPropertyManager == 1',
None, None, None, None, 1)
for path, ob in obs:
ob.manage_upgrade()
return '%d objects upgraded' % len(obs)
* All Localizer instances also need to be upgraded, but it's done
automatically. To verify it:
- test that the 'hook_traversal' property has been removed.
- test that the Localizer has a DTML Method called changeLanguageForm.
Some future release, probably 0.7, will be incompatible with
versions < 0.6. So it won't be possible, for example, to upgrade
from 0.5.1 to 0.7 directly; it must be from 0.5.1 to 0.6.x to 0.7.
In short: upgrade to 0.6 as soon as posible!!
* Other minor changes:
- Now get_available_languages returns a list of tuples of two
elements: [(id, title), ..]
For example, [('en', 'English'), ('es', 'Spanish'), ...]
- Now the title of local folders is not used in changeLanguageForm.
Perhaps there're other minor changes that could break something.
***************************************************************************
Localizer 0.3
***************************************************************************
In Localizer versions < 0.3 the way to localize DTML files was:
from Products.Localizer.LocalizedDTMLFile import LocalizedDTMLFile
xxx = LocalizedDTMLFile('xxx', globals())
Since version 0.3 the right way to do it is:
from Products.Localizer import LocalDTMLFile
xxx = LocalDTMLFile('xxx', globals())
In 0.3 version the old way was still supported, but deprecated. Since
version 0.4 the old way is no longer available, so products using it
will break.
# -*- coding: UTF-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2000-2005 Juan David Ibáñez Palomar <jdavid@itaapy.com> # Copyright (C) 2000-2005 Juan David Ibáñez Palomar <jdavid@itaapy.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
...@@ -14,17 +14,6 @@ ...@@ -14,17 +14,6 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# Check whether itools is installed
msg = ('itools 0.50 or later is needed, download from '
'http://download.hforge.org/itools/0.50')
try:
import itools
except ImportError:
raise ImportError, msg
# Check itools is version 0.50 or later
if itools.__version__ < '0.50':
raise ImportError, msg
# Import from the Standard Library # Import from the Standard Library
import os.path import os.path
...@@ -34,10 +23,8 @@ from DocumentTemplate.DT_String import String ...@@ -34,10 +23,8 @@ from DocumentTemplate.DT_String import String
# Import from Localizer # Import from Localizer
from patches import get_request from patches import get_request
import Localizer, LocalContent, MessageCatalog, LocalFolder import Localizer, MessageCatalog
from LocalAttributes import LocalAttribute from LocalFiles import LocalDTMLFile
from LocalFiles import LocalDTMLFile, LocalPageTemplateFile
from LocalPropertyManager import LocalPropertyManager, LocalProperty
from GettextTag import GettextTag from GettextTag import GettextTag
...@@ -72,13 +59,6 @@ def initialize(context): ...@@ -72,13 +59,6 @@ def initialize(context):
Localizer.manage_addLocalizer), Localizer.manage_addLocalizer),
icon = 'img/localizer.gif') icon = 'img/localizer.gif')
# Register LocalContent
context.registerClass(
LocalContent.LocalContent,
constructors = (LocalContent.manage_addLocalContentForm,
LocalContent.manage_addLocalContent),
icon='img/local_content.gif')
# Register MessageCatalog # Register MessageCatalog
context.registerClass( context.registerClass(
MessageCatalog.MessageCatalog, MessageCatalog.MessageCatalog,
...@@ -86,13 +66,6 @@ def initialize(context): ...@@ -86,13 +66,6 @@ def initialize(context):
MessageCatalog.manage_addMessageCatalog), MessageCatalog.manage_addMessageCatalog),
icon='img/message_catalog.gif') icon='img/message_catalog.gif')
# Register LocalFolder
context.registerClass(
LocalFolder.LocalFolder,
constructors = (LocalFolder.manage_addLocalFolderForm,
LocalFolder.manage_addLocalFolder),
icon='img/local_folder.gif')
context.registerHelp() context.registerHelp()
# Register the dtml-gettext tag # Register the dtml-gettext tag
......
***************************************************************************
See the "RELEASE.txt" file
***************************************************************************
1.1.2 (2005/10/21)
Upgrade to itools 0.9
1.1.1 (2005/05/26)
User Interface
- Improved message catalog user interface, suggested by Christopher
Lozinski.
Fixes
- Fix "LPM.get_available_languages" when property is empty.
- Backwards compatility improvements by Yoshinori Okuji.
- Fix Localizer with Zope 2.8, problem found by Lennart Regebro.
- Fixed english of the release notes, by Chris H.
1.1.0 (2005/04/10)
Nothing new, just some information files have been updated.
1.1.0rc1 (2005/03/21)
User Interface
- The text area to edit local properties is bigger now.
Packaging
- Check itools and iHotfix are installed.
1.1.0b5 (2005/01/28)
ZPT
- More robust support for the "i18n" namespace, check the domain object is
a message catalog.
User Interface
- New LocalPropertyManager/LocalContent interface, by Cornel Nitu.
Translations
- Updated the portuguese translation, by Rodrigo Senra.
Plone
- Remove conflict with PlacelessTranslationService, Plone and Localizer
work again together.
1.1.0b4 (2005/01/09)
ZPT
- Add support for i18n:domain
1.1.0b3 (2004/12/17)
Translations
- Added the italian version, by Marco Bizzarri
***************************************************************************
See "RELEASE.txt" for the changes between 0.8.1 and 1.1.0b3
***************************************************************************
0.8.1 (2002/02/25)
Now the language selection algorithm is compliant with the
RFC 2068 (HTTP 1.1).
New meta type LocalFolder. Now the "locale folders" feature of
the Localizer meta type are is deprecated, the new meta type
LocalFolder should be used instead.
Change internationalization of Python code from Python products.
Little cleanups: LocalObjects moved to LocalFiles;..
0.8.0 (2002/01/31)
Fixed bug in the ZMI reported by Magnus Heino.
Fixed use of file system message catalogs from ZPT.
Some improvements in the LanguageManager API.
Updated the few tests available to use PyUnit.
Fixed export of message catalogs, now the empty message is included.
Now LocalContent is CatalogAware, still remains to update the catalog
each time it's edited.
Now LocalPropertyManager implements __getattr__ to define attributes
of the form <name>_<lang>.
Moved the changeLanguageForm and changeLanguage helper methods to
the LanguageManager class.
Added the ugettext method in LocalObjects, beginning to work with
unicode.
Disabled the global gettext method that was added with a dynamnic patch
to to the Application class.
Improvements in the LocalPropertyManager web interface.
Now it's possible to change the default template for a LocalContent object.
0.7.1 (2001/10/26)
Improved zgettext.py script
First unit tests.
More online help screens.
Several security fixes.
Several bugs fixed.
Some minor improvements in the user interfaces.
Completed internationalization.
Updated several translations: french, hungarian and spanish.
0.7.0 (2001/10/10)
Several fixes in zgettext.py
New meta type MessageCatalog, it's possible to create message catalogs
with any id. Now the Localizer class no longer stores messages, but it
can contain MessageCatalog instances; specifically, if it contains a
MC named "Messages" gettext will behave in a similar way than before.
New mixin class LanguageManager that allows to manage list of available
languages and a default language. Used in LocalPropertyManager,
MessageCatalog and Localizer classes.
Added a dtml-gettext tag, useful for long messages.
Added the hungarian translation, thanks to Gabor Suveg.
Updated documentation.
More online help screens, improved some web interfaces.
0.6.2 (2001/10/01)
Completed the list of languages, ISO 639 compliance.
Now the language negotation algortithm is implemented in
a helper function (before this code was replicated in several
places).
Improvements in the message catalog user interface. Added a
help screen.
Minor changes in standard files (VERSION.txt and LICENSE.txt)
to comply ZDG guidelines.
0.6.1 (2001/09/28)
Added "original language" to LocalPropertyManager.
Minor improvements in the LocalPropertyManager user interface.
Now Localizer can be refreshed, except if Zope version >= 2.4.1b1.
Added the basque translation.
changeLanguageForm is a LocalDTMLFile again. Read UPGRADE.txt if
you're upgrading from 0.6.0
Some internal changes in the way message translations are searched.
Sometimes the translations were looked for in the wrong place, this
bug is fixed.
Now the localizer tutorial works with Zope < 2.4
0.6.0 (2001/09/25)
LocalPropertyManager
LocalProperty must be used always.
Improved user interface: posibility to add/delete languages;
show only few properties at a time.
Added a isLocalPropertyManager class attribute.
LocalPropertyManager can be used as base class for ZClasses.
LocalContent
Inherit also from PropertyManeger.
Localizer
Export and import message catalogs to and from .pot/.po files.
Changed the way to hook/unhook the traversal machinery.
Now changeLanguageForm is a DTML Method.
Now get_available_languages returns a list of tuples: [(id, title),..]
New method get_languages_map, used from changeLanguageForm.
Securtiy
Use "Declarative Assertions".
Several bugs fixed, mainly related with local folders. Also fixes
in zgettext.py, and probably others I don't remember now.
0.5.1 (2001/07/19)
Several fixes for LocalPropertyManager and LocalContent.
Added a tutorial (localizer_tutorial.zexp).
Now __version__ module attributes show the CVS revision number.
0.5.0 (2001/07/17)
Reorganization of the directory structure.
Added the LocalPropertyManager and LocalContent classes.
Patch OFS.Image to prevent browsers to cache images in localized folders.
0.4.0 (2001/07/10)
The gettext and locale modules have been removed, Python 2.x required.
License changed to GPL.
Management interface tabs internationalized, spanish and catalan
translations updated.
Fixed a bug in changeLanguage when the Localizer was used with other
SiteAccess, virtual hosting for example.
The script zgettext now keeps the locale.pot changes and uses msgmerge
to build the .po files.
Added new files BUGS.txt, TODO.txt and UPGRADE.txt
Old LocalizedDTMLFile removed.
0.3.0 (2001/06/..)
Fixed a bug that prevented proper copy&paste of Localized objects.
Changed the usage of localized dtml files, old usage preserved for
backwards compatibility.
Added support for page template files. Added documentation about
how to localize zpt.
0.2.1 (2001/05/23)
Ops, 0.2.0 bug fixed, I should test the code before releasing it,
apologies.
0.2.0 (2001/05/22)
Localized strings are looked for in all the Localizer instances in the path.
Now it's possible to override the user prefered language with the path.
Added the german version.
Some bugs fixed.
0.1.1 (2001/??/??)
Bug fixing release.
0.1.0 (2001/??/??)
Initial version.
Localizer 0.9.0
===============
General arquitecture
In the version 0.9 there're four meta types (Localizer, MessageCatalog,
LocalContent and LocalFolder), each one specialized in one task, finishing
this way with the confusion present in previous versions, where the
different features weren't clearly separated.
Previous versions mixed two features in the Localizer meta type, language
negotiation and generic support of multilingual objects.
Now the Localizer meta type is specialized in language negotiation. And a
new meta type, named LocalFolder, provides the generic support for language
negotiation following a different approach.
The old "locale folders" feature that was present in the Localizer meta
type has been definitely removed.
Language negotiation
This is one of the areas that has seen mayor improvements since version
0.8, now there's a simple default criteria to choose the language, based
only in the browser configuration. But the developer has much more power
to customize the language negotiation policy through the Localizer meta
type.
Also, the algorithm that chooses the language is finally standards compliant.
Unicode
The Unicode support is another of the big new features in this version.
To implement it now Localizer depends on the Unicode patches from Toby
Dickenson (http://www.zope.org/Members/htrd/wstring), which are part of
Zope since the version 2.6.
Now the policy is to use Python Unicode strings for everything:
- translations in the message catalog are stored as unicode strings;
- multilingual properties of LocalContent objects are stored as unicode
strings;
- the gettext method, when used from the file system, always returns
unicode strings (as the "ugettext" method of the "gettext" python
module).
The problem could raise when unicode and normal strings are mixed. By
default Python converts the normal strings to unicode as if they were
in ASCII. However, in Zope the default is considered to be iso-8859-1,
which is hardcoded in several places. Just be careful if you mix normal
and unicode strings, specially if they're in an encoding different than
iso-8859-1.
But maybe the main problem is the lack of proper unicode support in ZPT,
this will cause problems to anybody that wants to use ZPT and Unicode.
So it's likely that both Zope and Localizer will need a bit of work before
the Unicode support becomes stable.
Message Catalog
The message catalog interface has been completely redone. Now it correctly
supports multiline messages, including correct import and export from and
to PO files (thanks to Jean-Paul Smets).
There're other minor changes, like some improvements in the management
screens. The relevant links are:
- Home page
http://www.j-david.net/localizer
- Download
http://sourceforge.net/projects/lleu
- Mailing list
http://mail.freesoftware.fsf.org/mailman/listinfo/nuxeo-localizer
Localizer 0.9.1
===============
Localizer is a Zope [1] product that provides a set of facilities
to develop multilingual web applications. It offers solutions to
internationalize the user interfaces and to manage multilingual
content.
Localizer becomes beta
----------------------
Finally I've decided to officially declare Localizer as beta. This
means that no new features will be added for the 1.0 release, the
focus will be stability and documentation.
What's new
----------
Added unicode support to ZPT. Final version by Florent Guillaume.
New icons for all the meta types. Now Localizer has a logo (see logo.gif).
This is a contribution of Maite Rementeria, from Code&Syntax [2].
Spanish translation updated. New japanese version!, by Kazuya Fukamachi.
Some minor bugs fixed.
Resources
---------
Home page
http://www.j-david.net/software/localizer
Download
http://sourceforge.net/projects/lleu
Mailing list
http://mail.freesoftware.fsf.org/mailman/listinfo/nuxeo-localizer
Footnotes
---------
[1] http://www.zope.org
[2] http://www.codesyntax.com
Localizer 0.9.2
===============
Localizer is a Zope product that provides a set of facilities
to develop multilingual web applications. It offers solutions to
internationalize the user interfaces and to manage multilingual
content.
This is a bug fix release, the changes are:
- The "zgettext.py" script correctly parses Python files, to do
it the xgettext program from the GNU Gettext utilities is used.
- Now "zgettext.py" don't preserves the old messages in the
locale.pot file.
- Updated the Unicode patch, by Florent Guillaume.
- In some rare conditions the request object dissapears from the
global dictionary, this produces a key error when it's tried to be
removed. Fixed catching the exception (I couldn't reproduce the
error).
And a new "feature":
- Added the new module "LocalizerSupport.py", it helps to develop
Localizer based products that become monolingual when Localizer
is not installed (instead of becoming broken). It provides dummy
versions for some of the features of Localizer, not all.
Resources
---------
Home page
http://www.j-david.net/software/localizer
Download
http://sourceforge.net/projects/lleu
Mailing list
http://mail.freesoftware.fsf.org/mailman/listinfo/nuxeo-localizer
Localizer 0.9.3
===============
Localizer is a Zope product that provides a set of facilities
to develop multilingual web applications. It offers solutions to
internationalize the user interfaces and to manage multilingual
content.
This is a bug fix release, the changes are:
- Open MO files as binary files, this caused problems on Windows.
Thanks to Johan Carlsson
- Correctly copy and paste Localizer instances.
- Correctly detect Netscape 4.x, before Internet Explorer was thought
to be NS, this caused problems with the language negotiation. Thanks
to Olivier Nibart.
- Add the languages from a Localizer instance (if it exists) to the
languages input box of the LocalFolder add screen (as it already
was done with LocalContent).
- Quote messages in the Message Catalog interface, thanks to Geir Bækholt.
Resources
---------
Home page
http://www.localizer.org
Download
http://sourceforge.net/projects/lleu
Mailing list
http://mail.freesoftware.fsf.org/mailman/listinfo/nuxeo-localizer
Localizer 1.0.0
===============
Localizer is a Zope product that provides a set of facilities
to develop multilingual web applications. It offers solutions to
internationalize the user interfaces and to manage multilingual
content.
This is a bug fix release, the changes are:
- The dynamic global request patch is not installed if the static
version (by Tim McLaughlin) is already applied.
Resources
---------
Home page
http://www.localizer.org
Download
http://sourceforge.net/projects/lleu
Mailing list
http://mail.freesoftware.fsf.org/mailman/listinfo/nuxeo-localizer
Localizer 1.0.1
===============
Localizer is a Zope product that provides a set of facilities
to develop multilingual web applications. It offers solutions to
internationalize the user interfaces and to manage multilingual
content.
The changes of this release are:
- Added missing docstring to the Localizer class, thanks to
Christian Scholz.
- Strip the quality when parsing an accept header, this lets the
browser w3m and mobile phones to work, thanks to Helge Tesdal.
- Don't trigger Localizer instances when traversing if the request
variable AcceptLanguage does not exist. Thanks to Florent Guillaume.
- Now LocalPropertyManager.get_default_language returns None if
there isn't _default_language and get_languages returns an
empty list. Thanks to Greg Ward.
- Renamed the VERSION.txt file to version.txt, this lets to see the
version string from the control panel in the Zope management screens.
Thanks to Gilles Lenfant.
- Fixed bug in MessageCatalog.manage_export, thanks to Joachim Werner.
Resources
---------
Home page
http://www.localizer.org
Download
http://sourceforge.net/projects/lleu
Mailing list
http://mail.freesoftware.fsf.org/mailman/listinfo/nuxeo-localizer
Localizer 1.1
=============
April 11, 2005 - Two years after release of Localizer 1.0, I am
pleased to announce the availability of the next major version,
Localizer 1.1.
Localizer is a Zope [1] product for developers and web masters.
Localizer solves the problem of building multilingual products
and web sites, ranging from internationalization and localization
of the user interface to management of multilingual content.
jdavid at itaapy.com [2]
What's new in 1.1
-----------------
This release brings several new features. Specifically Localizer
now supports industry standards such as TMX [3] and XLIFF [4],
which enhance the interoperability of Localizer based applications
within mainstream environments.
Native support for 'i18n' namespaces for ZPT (Zope Page Templates)
is included avoiding the need to install other products.
The user interfaces have been vastly improved, specially for
'LocalContent' objects.
Four new translations are available: Danish, Italian, Portuguese
and Russian.
Localizer 1.1 has been re-packaged and now depends on itools Python
package and iHotfix Zope product. While these changes make installation
a bit more complex, the added benefit is simplified source management.
Furthermore this subtle change makes Localizer Services available to
the wider audience of Python [5] developers.
Last but not least, Localizer's stability has been dramatically
improved by resolution of many bugs resulting in a mature and even
more reliable product.
Credits
-------
This is the first release where the majority of work has been
contributed by community users and the original author. Credit
where credit is due.
To Eduardo Corrales and Roberto Quero from the Deusto University [6],
for the original implementation of the TMX standard.
To Søren Roug and Cornel Nitu from the European Environment Agency [7],
for their work on the TMX code, the implementation of the XLIFF standard,
the overhaul of the LocalContent interfaces, and the Danish translation.
To Alexey Lubimov for the Russian translation.
To Mario Olimpio de Menezes for the original Portuguese translation.
To Rodrigo Senra for updating the Portuguese translation, and for improving
the Localizer API.
To Marco Bizzarri for the Italian translation, and for improving the
stability.
Download and Install
--------------------
1. Download the Localizer meta-package from http://www.localizer.org
2. Unpack the tarball
3. Follow the instructions within the README file
Resources
---------
Home
http://www.localizer.org
Mailing list
http://in-girum.net/mailman/listinfo/localizer
Bug Tracker
http://in-girum.net/cgi-bin/bugzilla/index.cgi
References
----------
[1] http://www.zope.org
[2] http://www.itaapy.com
[3] http://www.lisa.org/tmx/
[4] http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xliff
[5] http://www.python.org
[6] http://www.deusto.es/
[7] http://www.eea.eu.int/
Localizer 1.1.3 (2006/12/13)
============================
Localizer is a Zope product for developers and web masters. Localizer
solves the problem of building multilingual products and web sites,
ranging from internationalization and localization of the user interface
to management of multilingual content.
The 1.1.3 release brings some new features for ZPT. Most important is
the support of interpolation. And now message catalogs are searched for
within the "Localizer" objects, if it exists.
There are also a couple of bugs fixed:
- The method "LocalPropertyManager.__getattr__" works again.
- The function "Utils.lang_negotiator" works now when the context
is not available.
Credits:
- Mikel Larreategi fixed "LocalPropertyManager.__getattr__".
- Josef Meile worked on ZPT.
- Yoshinori Okuji fixed "Utils.lang_negotiator".
Resources
---------
Download
http://download.ikaaro.org/localizer/Localizer-1.1.3.tar.gz
Home
http://www.localizer.org
Mailing list
http://mail.ikaaro.org/mailman/listinfo/localizer
Bug Tracker
http://bugs.ikaaro.org/
Localizer 1.2.0 (2006/12/22)
============================
Localizer is a Zope product for developers and web masters. Localizer
solves the problem of building multilingual products and web sites,
ranging from internationalization and localization of the user interface
to management of multilingual content.
The release 1.2.0 is a version update: it requires Python 2.4 and
itools 0.13.10, and the product iHotfix is not required anymore (it
has been merged back into Localizer).
This grid show the possible software combinations:
Localizer Python Zope itools
1.2 2.4 2.9, 2.10 0.13
1.1 (+iHotfix) 2.3 2.7, 2.8 0.9
1.0 2.1 2.6 ---
Of course it is recommended to use Localizer 1.2 with Zope 2.9 or later.
Resources
---------
Download
http://download.ikaaro.org/localizer/Localizer-1.2.0.tar.gz
http://download.ikaaro.org/itools/itools-0.13.10.tar.gz
Home
http://www.localizer.org
Mailing list
http://mail.ikaaro.org/mailman/listinfo/localizer
Bug Tracker
http://bugs.ikaaro.org/
Localizer 1.2.1 (2007/02/12)
============================
Localizer is a Zope product for developers and web masters. Localizer
solves the problem of building multilingual products and web sites,
ranging from internationalization and localization of the user interface
to management of multilingual content.
Fixed a serious regression, with 1.2.0 the Localizer object (used to
customize the language negotiation policy) stopped working. Thanks to
Igor Leturia for pointing out the problem.
Resources
---------
Download
http://download.ikaaro.org/localizer/Localizer-1.2.1.tar.gz
http://download.ikaaro.org/itools/itools-0.13.10.tar.gz
Home
http://www.localizer.org
Mailing list
http://mail.ikaaro.org/mailman/listinfo/localizer
Bug Tracker
http://bugs.ikaaro.org/
Localizer 1.2.2 (2008/01/18)
============================
Localizer is a Zope product for developers and web masters. Localizer
solves the problem of building multilingual products and web sites,
ranging from internationalization and localization of the user interface
to management of multilingual content.
What is new?
- Upgraded itools version to 0.20
- Compatibility fixes for Zope 2.10
- Upgraded the license to GPL version 3
Resources
---------
Download
http://download.ikaaro.org/localizer/Localizer-1.2.2.tar.gz
http://download.ikaaro.org/itools/itools-0.20.2.tar.gz
Home
http://www.localizer.org
Mailing list
http://mail.ikaaro.org/mailman/listinfo/localizer
Bug Tracker
http://bugs.ikaaro.org/
Localizer 1.2.3 (2008/12/03)
============================
Localizer is a Zope product for developers and web masters. Localizer
solves the problem of building multilingual products and web sites,
ranging from internationalization and localization of the user
interface to management of multilingual content.
What is new?
- Compatibility fixes for Zope 2.10/2.11 (bug #381)
- Other minor fixes (including bug #304)
Resources
---------
Download
http://download.hforge.org/localizer/Localizer-1.2.3.tar.gz
http://download.hforge.org/itools/itools-0.20.6.tar.gz
Home
http://www.localizer.org/
Mailing list
http://www.hforge.org/community
http://archives.hforge.org/index.cgi?list=localizer
Bug Tracker
http://bugs.hforge.org/
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<fieldset><legend><dtml-var "gettext('Export messages to TMX file')"></legend>
<p class="form-help">
<dtml-gettext>
You can export the messages and their translations to TMX level 1 files.
To do that just click the <tt>Export</tt> button.
</dtml-gettext>
</p>
<form action="tmx_export" method="post">
<table>
<tr>
<td><br></td>
<tr>
<td><input type="submit" value=" <dtml-var "gettext('Export')"> "></td>
<td></td>
</tr>
</table>
</form>
</fieldset>
<fieldset><legend><dtml-var "gettext('Export messages to XLIFF file')"></legend>
<p class="form-help">
<dtml-gettext>
You can export the messages and their translations to XLIFF files.
Check any option to get a XLIFF file with the messages and their
translations to the selected language. Then click the <tt>Export</tt>
button.
</dtml-gettext>
</p>
<form action="xliff_export" method="post">
<table border=0 cellpadding="2" cellspacing="2">
<tr>
<td><input type="radio" name="export_all" value="1" checked>Export all messages<br>
<input type="radio" name="export_all" value="0">Export only untranslated messages
for the language you select
</td>
</tr>
<tr>
<th align="left">
<dtml-var "gettext('Target language')">
</th>
</tr>
<tr>
<td valign="top">
<select name="targetlang">
<dtml-in get_languages_mapping mapping>
<option value="<dtml-var code>"><dtml-var code> / <dtml-var "gettext(name)"></option>
</dtml-in>
</select>
</td>
</tr>
<tr>
<td><input type="submit" value=" <dtml-var "gettext('Export')"> "></td>
<td></td>
</tr>
</table>
</form>
</fieldset>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<fieldset><legend><dtml-var "gettext('Import translations from TMX file')"></legend>
<p class="form-help">
<dtml-gettext>
The message catalog also supports importing TMX files. You can add new
messages and translations importing a TMX file in TMX level 1. Enter the
filename and click the
<tt>Import</tt> button.
</dtml-gettext>
</p>
<form action="tmx_import" method="post" enctype="multipart/form-data">
<table>
<tr>
<th align="right"><dtml-var "gettext('File')"></th>
<td><input type="file" name="file"></td>
</tr>
<tr>
<th></th>
<td><input type="submit" value=" <dtml-var "gettext('Import')"> "></td>
</tr>
</table>
</form>
</fieldset>
<fieldset><legend><dtml-var "gettext('Import translations from XLIFF file')"></legend>
<form action="xliff_import" method="post" enctype="multipart/form-data">
<table>
<tr>
<th align="right"><dtml-var "gettext('File')"></th>
<td><input type="file" name="file"></td>
</tr>
<tr>
<th></th>
<td><input type="submit" value=" <dtml-var "gettext('Import')"> "></td>
</tr>
</table>
</form>
</fieldset>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<p class="form-help">
This page allows you to define, edit and delete properties of LocalContent.
To change property values, edit the values and click "Save Changes".
If you want to remove a property select it and click "Delete".
</p>
<dtml-let properties="getLocalProperties()">
<dtml-if properties>
<dtml-let curr_prop="REQUEST.get('prop', properties[0]['id'])"
default_lang="get_default_language()"
curr_value="getLocalAttribute(curr_prop, default_lang)">
<form action="<dtml-var URL1>" method="post" name="frmProperties">
<table cellspacing="0" cellpadding="2" border="0">
<tr class="list-header">
<td align="left" valign="top" width="16">&nbsp;</td>
<td align="left" valign="top">
<div class="form-label"><dtml-var "gettext('Name')"></div>
</td>
<td align="left" valign="top">
<div class="form-label"><dtml-var "gettext('Value')"></div>
</td>
<td align="left" valign="top">
<div class="form-label"><dtml-var "gettext('Type')"></div>
</td>
</tr>
<dtml-in properties mapping>
<tr>
<td align="left" valign="top" width="16">
<input type="checkbox" name="ids:list"
value="<dtml-var id>" id="cb-title">
</td>
<td align="left" valign="top">
<div class="form-label"><label for="cb-title"><dtml-var id></label></div>
</td>
<td align="left" valign="top">
<dtml-if "type == 'string'">
<input type="text" name="<dtml-var id>:utf8:ustring" size="65" value="<dtml-var "getLocalAttribute(id, default_lang)">" />
<dtml-elif "type == 'text'">
<textarea name="<dtml-var id>:utf8:ustring" rows="10" cols="65"><dtml-var "getLocalAttribute(id, default_lang)"></textarea>
</dtml-if>
</td>
<td align="left" valign="top">
<div class="list-item"><dtml-var type></div>
</td>
</tr>
</dtml-in>
<tr>
<td colspan="2"></td>
<td align="left" valign="top">
<div class="form-element">
<input type="hidden" name="code" value="<dtml-var default_lang>" />
<input type="hidden" name="destination" value="manage_localPropertiesForm" />
<input name="manage_editLocalProperty:method" type="submit" class="form-element" value=" <dtml-var "gettext('Save changes')"> " />
<input name="manage_delLocalProperty:method" type="submit" class="form-element" value=" <dtml-var "gettext('Delete')"> " />
</div>
</td>
<td></td>
</tr>
</table>
</form>
</dtml-let>
</dtml-if>
<form action="manage_addLocalProperty" method="post">
<p class="form-help">
To add a new property, enter a name, type and value for the new
property and click the &quot;Add&quot; button.
</p>
<table>
<tr>
<td align="left" valign="top">
<div class="form-label"><dtml-var "gettext('Name')"></div>
</td>
<td align="left" valign="top">
<input type="text" name="id:utf8:ustring" size="30" value=""/>
</td>
<td align="left" valign="top" class="form-label">
<dtml-var "gettext('Type')">
</td>
<td align="left" valign="top">
<div class="form-element">
<select name="type">
<option>string</option>
<option>text</option>
</select>
</div>
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label"><dtml-var "gettext('Value')"></div>
</td>
<td colspan=2 align="left" valign="top">
<input type="text" name="value:utf8:ustring" size="30" />
</td>
<td align="right" valign="top">
<div class="form-element">
<input class="form-element" type="submit" name="submit" value=" <dtml-var "gettext('Add')"> " />
</div>
</td>
</tr>
</table>
</form>
</dtml-let>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<dtml-comment>
Set here the default values for the REQUEST varibiles used
for the navigation of the web interface
</dtml-comment>
<p class="form-help">
This page allows you to see the properties of LocalContent and translate them.
Select a property and the property value will appear in the default language.
You can navigate throw the property translations by clicking on one of the available
languages. After changing the translation click Save Changes.
</p>
<p class="form-help">
When the property value in the default language changes all the translations become
obsolete and they are marked with <img src="misc_/Localizer/obsolete" border="0" alt="Obsolete translation flag" />.
</p>
<dtml-let languages="get_targetLanguages()"
properties="getLocalProperties()">
<dtml-if languages>
<dtml-if properties>
<dtml-let curr_lang="REQUEST.get('lang', None) or languages[0]['code']"
default_lang="get_default_language()"
curr_prop="REQUEST.get('prop', properties[0]['id'])"
curr_value="getLocalAttribute(curr_prop, curr_lang)">
<table border="0" cellspacing="3" cellpadding="3" width="90%">
<tr>
<td rowspan="2" width="30%">
<textarea cols="65" rows="10" wrap="virtual"
readonly="readonly"><dtml-var "getLocalAttribute(curr_prop, default_lang)" html_quote></textarea>
<br />
<dtml-in languages mapping sort=name>
<dtml-let name="gettext(name)">
<dtml-if "code != get_default_language()">
<a href="?lang=<dtml-var code url_quote>&prop=<dtml-var curr_prop url_quote>">
<dtml-if "code==curr_lang">
<dtml-if "is_obsolete(curr_prop, code)">
<span style="font-weight:bold"><dtml-var name></span>
<img src="misc_/Localizer/obsolete" border="0" alt="Obsolete translation flag" />
<dtml-else>
<span style="font-weight:bold"><dtml-var name></span>
</dtml-if>
<dtml-else>
<dtml-if "is_obsolete(curr_prop, code)">
<dtml-var name><img src="misc_/Localizer/obsolete" border="0" alt="Obsolete translation flag" />
<dtml-else>
<dtml-var name>
</dtml-if>
</dtml-if>
</a>
</dtml-if>
</dtml-let>
</dtml-in>
<form action="<dtml-var URL1>" method="post" name="frmProperties">
<textarea name="value:utf8:ustring" cols="65" rows="10"
wrap="virtual"><dtml-var curr_value html_quote></textarea>
<input type="hidden" name="id" value="<dtml-var curr_prop>" />
<input type="hidden" name="destination" value="manage_transPropertiesForm" />
<input type="hidden" name="code" value="<dtml-var curr_lang>" />
<dtml-if languages>
<input type="submit" name="manage_transLocalProperty:method" value=" <dtml-var "gettext('Save changes')"> " />
</dtml-if>
</form>
</td>
<td valign="top">
<div class="list-header" style="font-weight:bold"> Properties </div>
<dtml-in properties mapping>
<div <dtml-if sequence-even> style="background-color:white"<dtml-elif sequence-odd> style="background-color:#F0F0F0"</dtml-if>>
<a href="?lang=<dtml-var curr_lang url_quote>&prop=<dtml-var id url_quote>">
<dtml-if "id == curr_prop">
<span style="font-weight:bold"><em><dtml-var id></em></span>
<dtml-else>
<dtml-var id>
</dtml-if></a></div>
</dtml-in>
</td>
</tr>
</table>
</dtml-let>
<dtml-else>
There are no properties.
</dtml-if>
<dtml-else>
<p>No languages available, please add them using the
<a href='manage_languages'>Languages</a> tab</p>
</dtml-if>
</dtml-let>
<dtml-var manage_page_footer>
<dtml-unless management_page_charset>
<dtml-call "REQUEST.set('management_page_charset', 'UTF-8')">
</dtml-unless>
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title=gettext('Add Local Content'),
help_product='Localizer',
help_topic='LocalContent_add.stx')">
<p class="form-help">
<dtml-gettext>
A Local Content object provides a storage for multilingual (and
non multilingual) properties. It also helps you keep your content
separated from the logic and the presentation.
</dtml-gettext>
</p>
<form action="manage_addLocalContent" method="post">
<table cellspacing="2">
<tr>
<th align="right"><dtml-var "gettext('Id')"></th>
<td><input type="text" name="id" size="50"></td>
</tr>
<tr>
<th align="right"><dtml-var "gettext('Original language')"></th>
<td><input type="text" size="10" name="sourcelang" value="en"></td>
</tr>
<tr>
<th align="right"><dtml-var "gettext('Target languages')"></th>
<td><input type="text" name="languages:tokens" size="50"
value="<dtml-try><dtml-in "Localizer.get_languages()"><dtml-var sequence-item> </dtml-in><dtml-except></dtml-try>"></td>
</tr>
<tr>
<td></td>
<td><br><input type="submit" value=" <dtml-var "gettext('Add')"> "></td>
</tr>
</table>
</form>
<dtml-var manage_page_footer>
<dtml-unless management_page_charset>
<dtml-call "REQUEST.set('management_page_charset', 'UTF-8')">
</dtml-unless>
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title=gettext('Add Local Folder'),
help_product='Localizer',
help_topic='LocalFolder_add.stx')">
<p class="form-help">
<dtml-gettext>
A local folder is a generic solution to manage any kind of multingual
objects, files, images, scripts, etc..
</dtml-gettext>
</p>
<form action="manage_addLocalFolder" method="post">
<table>
<tr>
<th align="right"><dtml-var "gettext('Id')"></th>
<td><input type="text" name="id"></td>
</tr>
<tr>
<th align="right"><em><dtml-var "gettext('Title')"></em></th>
<td><input type="text" name="title"></td>
</tr>
<tr>
<th align="right"><dtml-var "gettext('Languages')"></th>
<td><input type="text" name="languages:tokens"
value="<dtml-try><dtml-in "Localizer.get_languages()"><dtml-var sequence-item> </dtml-in><dtml-except>en </dtml-try>"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value=" <dtml-var "gettext('Add')"> "></td>
</tr>
</table>
</form>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<dtml-let local_attributes="get_local_attributes()">
<dtml-if local_attributes>
<p class="form-help">
<dtml-gettext>
To delete an attribute check it and click the <tt>Delete</tt> button.
</dtml-gettext>
</p>
<blockquote>
<form action="manage_delAttributes" method="post">
<table>
<dtml-in get_local_attributes>
<tr>
<td>
<input type="checkbox" name="attributes:tuple"
value="<dtml-var sequence-item>">
</td>
<td>
<dtml-var sequence-item>
</td>
</tr>
</dtml-in>
<tr>
<td></td>
<td>
<input type="submit" value=" <dtml-var "gettext('Delete')"> ">
</td>
</tr>
</table>
</form>
</blockquote>
<dtml-else>
<p class="form-help">
<dtml-gettext>There are no attributes</dtml-gettext>
</p>
</dtml-if>
</dtml-let>
<p class="form-help">
<dtml-gettext>
To add an attribute introduce its id and click the <tt>Add</tt> button.
</dtml-gettext>
</p>
<blockquote>
<form action="manage_addAttribute" method="post">
<input type="text" name="id">
<input type="submit" value=" <dtml-var "gettext('Add')"> ">
</form>
</blockquote>
<dtml-var manage_page_footer>
...@@ -37,65 +37,4 @@ ...@@ -37,65 +37,4 @@
</form> </form>
</fieldset> </fieldset>
<fieldset><legend><dtml-var "gettext('Export messages to TMX file')"></legend>
<p class="form-help">
<dtml-gettext>
You can export the messages and their translations to TMX level 1 files.
To do that just click the <tt>Export</tt> button.
</dtml-gettext>
</p>
<form action="tmx_export" method="post">
<table>
<tr>
<td><br></td>
<tr>
<td><input type="submit" value=" <dtml-var "gettext('Export')"> "></td>
<td></td>
</tr>
</table>
</form>
</fieldset>
<fieldset><legend><dtml-var "gettext('Export messages to XLIFF file')"></legend>
<p class="form-help">
<dtml-gettext>
You can export the messages and their translations to XLIFF files.
Check any option to get a XLIFF file with the messages and their
translations to the selected language. Then click the <tt>Export</tt>
button.
</dtml-gettext>
</p>
<form action="xliff_export" method="post">
<table border=0 cellpadding="2" cellspacing="2">
<tr>
<td><input type="radio" name="export_all" value="1" checked>Export all messages<br>
<input type="radio" name="export_all" value="0">Export only untranslated messages
for the language you select
</td>
</tr>
<tr>
<th align="left">
<dtml-var "gettext('Target language')">
</th>
</tr>
<tr>
<td valign="top">
<select name="x">
<dtml-in get_languages_mapping mapping sort=name>
<option value="<dtml-var code>"><dtml-var code> / <dtml-var "gettext(name)"></option>
</dtml-in>
</select>
</td>
</tr>
<tr>
<td><input type="submit" value=" <dtml-var "gettext('Export')"> "></td>
<td></td>
</tr>
</table>
</form>
</fieldset>
<dtml-var manage_page_footer> <dtml-var manage_page_footer>
...@@ -35,69 +35,4 @@ ...@@ -35,69 +35,4 @@
</form> </form>
</fieldset> </fieldset>
<fieldset><legend><dtml-var "gettext('Import translations from TMX file')"></legend>
<p class="form-help">
<dtml-gettext>
The message catalog also supports importing TMX files. You can add new
messages and translations importing a TMX file in TMX level 1. Enter the
filename and click the
<tt>Import</tt> button.
</dtml-gettext>
</p>
<form action="tmx_import" method="post" enctype="multipart/form-data">
<table>
<tr>
<th align="right"><dtml-var "gettext('How much')"></th>
<td>
<input type="radio" name="howmuch" value="existing" checked>
<dtml-gettext>Import only translations for messages that
exist already</dtml-gettext><br>
<input type="radio" name="howmuch" value="all">
<dtml-gettext>Import all messages</dtml-gettext><br>
<input type="radio" name="howmuch" value="clear">
<dtml-gettext>Clear catalog and import all messages</dtml-gettext>
</td>
</tr>
<tr>
<th align="right"><dtml-var "gettext('File')"></th>
<td><input type="file" name="file"></td>
</tr>
<tr>
<th></th>
<td><input type="submit" value=" <dtml-var "gettext('Import')"> "></td>
</tr>
</table>
</form>
</fieldset>
<fieldset><legend><dtml-var "gettext('Import translations from XLIFF file')"></legend>
<form action="xliff_import" method="post" enctype="multipart/form-data">
<table>
<tr>
<th align="right"><dtml-var "gettext('How much')"></th>
<td>
<input type="radio" name="howmuch" value="existing" checked>
<dtml-gettext>Import only translations for messages that
exist already</dtml-gettext><br>
<input type="radio" name="howmuch" value="all">
<dtml-gettext>Import all messages</dtml-gettext><br>
<input type="radio" name="howmuch" value="clear">
<dtml-gettext>Clear catalog and import all messages</dtml-gettext>
</td>
</tr>
<tr>
<th align="right"><dtml-var "gettext('File')"></th>
<td><input type="file" name="file"></td>
</tr>
<tr>
<th></th>
<td><input type="submit" value=" <dtml-var "gettext('Import')"> "></td>
</tr>
</table>
</form>
</fieldset>
<dtml-var manage_page_footer> <dtml-var manage_page_footer>
# -*- coding: UTF-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2000-2003 Juan David Ibáñez Palomar <jdavid@itaapy.com> # Copyright (C) 2000-2003 Juan David Ibáñez Palomar <jdavid@itaapy.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
...@@ -15,9 +15,8 @@ ...@@ -15,9 +15,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# Import from itools # Import from itools
from itools import get_abspath from .itools.utils import get_abspath
from itools.i18n import AcceptLanguageType, init_language_selector from .itools.i18n import AcceptLanguageType, init_language_selector
from itools.gettext import get_domain, register_domain
# Import from Zope # Import from Zope
from App.Common import package_home from App.Common import package_home
...@@ -62,20 +61,22 @@ init_language_selector(lang_negotiator) ...@@ -62,20 +61,22 @@ init_language_selector(lang_negotiator)
# directory. # directory.
########################################################################### ###########################################################################
class DomainAware(object): class DomainAware(object):
"""
This class is just a stub. We're not interested in filesystem-based
po-file translations.
All subclasses should be either changed not to require DomainAware
or removed altogether.
"""
def __init__(self, namespace): def __init__(self, namespace):
mname = namespace['__name__'] mname = namespace['__name__']
domain = get_abspath('locale', mname=mname) domain = get_abspath('locale', mname=mname)
self.class_domain = domain self.class_domain = domain
register_domain(domain, domain)
def gettext(self, message, language=None): def gettext(self, message, language=None):
domain = get_domain(self.class_domain) return message
if language is None:
languages = domain.get_languages()
language = select_language(languages)
return domain.gettext(message, language)
_ = DomainAware(globals()).gettext _ = DomainAware(globals()).gettext
......
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Copyright (C) 2001 Andrés Marzal Varo
# Copyright (C) 2001-2002 J. David Ibáñez <jdavid@itaapy.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
zgettext.py is a script that parses DTML files and generates .pot and .po
files, and then generates .mo files from the .po files.
Future (XXX):
zgettext should provide a similar interface to xgettext, it just should
detect dtml and zpt files, parse them, and call xgettext for the rest.
another script should do the wrap up to easily create multilingual products,
or maybe we could avoid this and just use make
Anyway, the trend is to levereage the gettext tools as much as posible.
"""
# Import from the Standard Library
from os import listdir, mkdir, remove, system
from os.path import exists, isdir
from re import compile, DOTALL, findall
import sys
from tempfile import mktemp
from time import gmtime, strftime, time
# Import from itools
from itools.handlers import get_handler
from itools.gettext import POFile
# Exceptions
class UnknownStatus(Exception):
pass
def create_mo_files():
for filename in [ x for x in listdir('locale') if x.endswith('.po') ]:
language = filename[:-3]
system('msgfmt locale/%s.po -o locale/%s.mo' % (language, language))
def parse_generic(text, commands=('gettext',)):
"""Search for patterns like: gettext('message').
XXX
Originally it was used to parse Python code, but it fails to parse
some of the Python strings, now xgettext is used instead. So currently
this function is only used to parse DTML and ZPT; probably the regular
expression could be simplified as in DTML and ZPT there're (maybe)
less options for Python strings due to the syntax constrains of these
languages.
"""
r = []
for command in commands:
pattern = command + '\s*\(\s*(\'.*?[^\\\\]\'|\".*?[^\\\\]\")\s*\)'
regex = compile(pattern, DOTALL)
r.extend([ x[1:-1] for x in findall(regex, text) ])
return r
def parse_dtml(text):
"""Extract the messages from a DTML template.
"""
messages = parse_generic(text)
# Search the "<dtml-gettext>message</dtml-gettext>" pattern
regex = compile('<dtml-gettext(.*?)>(.*?)</dtml-gettext>', DOTALL)
for parameters, message in findall(regex, text):
if parameters.find('verbatim') == -1:
message = ' '.join([ x.strip() for x in message.split() ])
messages.append(message)
return messages
def parse_zpt(text):
"""Extract the messages from a ZPT template.
XXX It should be improved to parse the i18n namespace.
"""
return parse_generic(text)
def do_all(filenames, languages):
# Create the locale directory
if not isdir('./locale'):
try:
mkdir('./locale')
except OSError, msg:
sys.stderr.write('Error: Cannot create directory "locale".\n%s\n'
% msg)
sys.exit(1)
# Create the pot file
if not exists('locale/locale.pot'):
f = open('locale/locale.pot', 'w')
f.write("# SOME DESCRIPTIVE TITLE.\n")
f.write("# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n")
f.write("# This file is distributed under the same license as the PACKAGE package.\n")
f.write("# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n")
f.write("#\n")
f.write("#, fuzzy\n")
f.write('msgid ""\n')
f.write('msgstr ""\n')
f.write('"Project-Id-Version: PACKAGE VERSION\\n"\n')
f.write('"POT-Creation-Date: %s\\n"\n' % strftime('%Y-%m-%d %H:%m+%Z',
gmtime(time())))
f.write('"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"\n')
f.write('"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"\n')
f.write('"Language-Team: LANGUAGE <LL@li.org>\\n"\n')
f.write('"MIME-Version: 1.0\\n"\n')
f.write('"Content-Type: text/plain; charset=CHARSET\\n"\n')
f.write('"Content-Transfer-Encoding: 8bit\\n"\n')
f.close()
# Filter and parse the DTML and ZPT files, the rest will be parsed
# with xgettext.
filenames2 = []
messages = []
for filename in filenames:
filetype = filename.split('.')[-1]
if filetype == 'dtml':
text = open(filename).read()
messages.extend(parse_dtml(text))
elif filetype == 'zpt':
text = open(filename).read()
messages.extend(parse_zpt(text))
else:
filenames2.append(filename)
filenames = []
# Write a PO file with the messages from DTML and ZPT
if messages:
filename = mktemp('.po')
filenames.append(filename)
f = open(filename, 'w')
aux = []
for message in messages:
if message not in aux:
f.write('msgid "%s"\n' % message)
f.write('msgstr ""\n')
f.write('\n')
aux.append(message)
f.close()
# Parse the rest of the files
if filenames2:
po = POFile()
for filename in filenames2:
handler = get_handler(filename)
for source, context, line in handler.get_units():
po.add_unit(filename, source, context, line)
filename = mktemp('.po')
filenames.append(filename)
open(filename, 'w').write(po.to_str())
# Create the POT file
if filenames:
filename = mktemp('.po')
cmd = 'msgcat -s --output-file=%s %s' % (filename, ' '.join(filenames))
system(cmd)
system('msgmerge -U locale/locale.pot %s' % filename)
# Remove temporal files
remove(filename)
for filename in filenames:
remove(filename)
# Generate the PO files
for language in languages:
if exists('./locale/%s.po' % language):
# a .po file already exist, merge it with locale.pot
system('msgmerge -U locale/%s.po locale/locale.pot' % language)
else:
# po doesn't exist, just copy locale.pot
text = open('./locale/locale.pot').read()
open('./locale/%s.po' % language, 'w').write(text)
if __name__ == '__main__':
# Parse the command line
status = 0
files = []
langs = []
for arg in sys.argv[1:]:
if status == 0:
if arg == '-h':
status = 1
elif arg == '-m':
status = 2
elif arg == '-l':
status = 3
else:
files.append(arg)
status = 4
elif status == 1:
status = 'Error'
break
elif status == 2:
status = 'Error'
break
elif status == 3:
langs.append(arg)
status = 5
elif status == 4:
if arg == '-l':
status = 3
else:
files.append(arg)
elif status == 5:
langs.append(arg)
else:
raise UnknownStatus, str(status)
# Action
if status in (0, 1, 3, 'Error'):
# Provide help if the line format is wrong or if the -h modifier
# is provided
print 'Usage:'
print ' zgettext.py -h'
print ' Shows this help message.'
print ' zgettext.py [file file ... file] [-l languages]'
print ' Parses all the specified files, creates the locale'
print ' directory, creates the locale.pot file and the .po'
print ' files of the languages specified.'
print ' zgettxt.py -m'
print ' Compiles all the .po files in the locale directory'
print ' and creates the .mo files.'
print
print 'Examples:'
print ' zgettext.py *.dtml -l ca es en'
print ' zgettext.py -m'
elif status == 2:
create_mo_files()
elif status in (4, 5):
do_all(files, langs)
else:
raise UnknownStatus, str(status)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment