diff --git a/addons/web/__init__.py b/addons/web/__init__.py index 8802cb548c3..06e7fa1f0e3 100644 --- a/addons/web/__init__.py +++ b/addons/web/__init__.py @@ -1,6 +1,5 @@ import common import controllers -import common.dispatch import logging import optparse @@ -22,6 +21,6 @@ def wsgi_postload(): o.serve_static = True o.backend = 'local' - app = common.dispatch.Root(o) + app = common.http.Root(o) openerp.wsgi.register_wsgi_handler(app) diff --git a/addons/web/__openerp__.py b/addons/web/__openerp__.py index 990f0b445a0..d304825bd64 100644 --- a/addons/web/__openerp__.py +++ b/addons/web/__openerp__.py @@ -1,5 +1,6 @@ { "name" : "web", + "category" : "Hidden", "depends" : [], 'active': True, 'post_load' : 'wsgi_postload', diff --git a/addons/web/common/__init__.py b/addons/web/common/__init__.py index 9257f51d037..53bf3e3ed08 100644 --- a/addons/web/common/__init__.py +++ b/addons/web/common/__init__.py @@ -1,2 +1,6 @@ #!/usr/bin/python -from dispatch import * +import http +import nonliterals +import release +import session +import xml2json diff --git a/addons/web/common/ast.py b/addons/web/common/ast.py deleted file mode 100644 index 2fd565aa30d..00000000000 --- a/addons/web/common/ast.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf-8 -*- -""" Backport of Python 2.6's ast.py for Python 2.5 -""" -__all__ = ['literal_eval'] -try: - from ast import literal_eval -except ImportError: - from _ast import * - from _ast import __version__ - - - def parse(expr, filename='', mode='exec'): - """ - Parse an expression into an AST node. - Equivalent to compile(expr, filename, mode, PyCF_ONLY_AST). - """ - return compile(expr, filename, mode, PyCF_ONLY_AST) - - - def literal_eval(node_or_string): - """ - Safely evaluate an expression node or a string containing a Python - expression. The string or node provided may only consist of the - following Python literal structures: strings, numbers, tuples, lists, - dicts, booleans, and None. - """ - _safe_names = {'None': None, 'True': True, 'False': False} - if isinstance(node_or_string, basestring): - node_or_string = parse(node_or_string, mode='eval') - if isinstance(node_or_string, Expression): - node_or_string = node_or_string.body - def _convert(node): - if isinstance(node, Str): - return node.s - elif isinstance(node, Num): - return node.n - elif isinstance(node, Tuple): - return tuple(map(_convert, node.elts)) - elif isinstance(node, List): - return list(map(_convert, node.elts)) - elif isinstance(node, Dict): - return dict((_convert(k), _convert(v)) for k, v - in zip(node.keys, node.values)) - elif isinstance(node, Name): - if node.id in _safe_names: - return _safe_names[node.id] - raise ValueError('malformed string') - return _convert(node_or_string) diff --git a/addons/web/common/dates.py b/addons/web/common/dates.py deleted file mode 100644 index caa7f83c84a..00000000000 --- a/addons/web/common/dates.py +++ /dev/null @@ -1,88 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (). -# Copyright (C) 2010 OpenERP s.a. (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -import datetime - -DEFAULT_SERVER_DATE_FORMAT = "%Y-%m-%d" -DEFAULT_SERVER_TIME_FORMAT = "%H:%M:%S" -DEFAULT_SERVER_DATETIME_FORMAT = "%s %s" % ( - DEFAULT_SERVER_DATE_FORMAT, - DEFAULT_SERVER_TIME_FORMAT) - -def str_to_datetime(str): - """ - Converts a string to a datetime object using OpenERP's - datetime string format (exemple: '2011-12-01 15:12:35'). - - No timezone information is added, the datetime is a naive instance, but - according to OpenERP 6.1 specification the timezone is always UTC. - """ - if not str: - return str - return datetime.datetime.strptime(str, DEFAULT_SERVER_DATETIME_FORMAT) - -def str_to_date(str): - """ - Converts a string to a date object using OpenERP's - date string format (exemple: '2011-12-01'). - """ - if not str: - return str - return datetime.datetime.strptime(str, DEFAULT_SERVER_DATE_FORMAT).date() - -def str_to_time(str): - """ - Converts a string to a time object using OpenERP's - time string format (exemple: '15:12:35'). - """ - if not str: - return str - return datetime.datetime.strptime(str, DEFAULT_SERVER_TIME_FORMAT).time() - -def datetime_to_str(obj): - """ - Converts a datetime object to a string using OpenERP's - datetime string format (exemple: '2011-12-01 15:12:35'). - - The datetime instance should not have an attached timezone and be in UTC. - """ - if not obj: - return False - return obj.strftime(DEFAULT_SERVER_DATETIME_FORMAT) - -def date_to_str(obj): - """ - Converts a date object to a string using OpenERP's - date string format (exemple: '2011-12-01'). - """ - if not obj: - return False - return obj.strftime(DEFAULT_SERVER_DATE_FORMAT) - -def time_to_str(obj): - """ - Converts a time object to a string using OpenERP's - time string format (exemple: '15:12:35'). - """ - if not obj: - return False - return obj.strftime(DEFAULT_SERVER_TIME_FORMAT) diff --git a/addons/web/common/dispatch.py b/addons/web/common/dispatch.py deleted file mode 100644 index cb998caf891..00000000000 --- a/addons/web/common/dispatch.py +++ /dev/null @@ -1,428 +0,0 @@ -#!/usr/bin/python -from __future__ import with_statement - -import functools -import logging -import urllib -import os -import pprint -import sys -import traceback -import uuid -import xmlrpclib - -import simplejson -import werkzeug.datastructures -import werkzeug.exceptions -import werkzeug.utils -import werkzeug.wrappers -import werkzeug.wsgi - -import ast -import nonliterals -import http -import session -import openerplib - -__all__ = ['Root', 'jsonrequest', 'httprequest', 'Controller', - 'WebRequest', 'JsonRequest', 'HttpRequest'] - -_logger = logging.getLogger(__name__) - -#----------------------------------------------------------- -# Globals (wont move into a pool) -#----------------------------------------------------------- - -addons_module = {} -addons_manifest = {} -controllers_class = {} -controllers_object = {} -controllers_path = {} - -#---------------------------------------------------------- -# OpenERP Web RequestHandler -#---------------------------------------------------------- -class WebRequest(object): - """ Parent class for all OpenERP Web request types, mostly deals with - initialization and setup of the request object (the dispatching itself has - to be handled by the subclasses) - - :param request: a wrapped werkzeug Request object - :type request: :class:`werkzeug.wrappers.BaseRequest` - :param config: configuration object - - .. attribute:: httprequest - - the original :class:`werkzeug.wrappers.Request` object provided to the - request - - .. attribute:: httpsession - - a :class:`~collections.Mapping` holding the HTTP session data for the - current http session - - .. attribute:: config - - config parameter provided to the request object - - .. attribute:: params - - :class:`~collections.Mapping` of request parameters, not generally - useful as they're provided directly to the handler method as keyword - arguments - - .. attribute:: session_id - - opaque identifier for the :class:`session.OpenERPSession` instance of - the current request - - .. attribute:: session - - :class:`~session.OpenERPSession` instance for the current request - - .. attribute:: context - - :class:`~collections.Mapping` of context values for the current request - - .. attribute:: debug - - ``bool``, indicates whether the debug mode is active on the client - """ - def __init__(self, request, config): - self.httprequest = request - self.httpresponse = None - self.httpsession = request.session - self.config = config - - def init(self, params): - self.params = dict(params) - # OpenERP session setup - self.session_id = self.params.pop("session_id", None) or uuid.uuid4().hex - self.session = self.httpsession.setdefault(self.session_id, session.OpenERPSession()) - self.session.config = self.config - self.context = self.params.pop('context', None) - self.debug = self.params.pop('debug', False) != False - -class JsonRequest(WebRequest): - """ JSON-RPC2 over HTTP. - - Sucessful request:: - - --> {"jsonrpc": "2.0", - "method": "call", - "params": {"session_id": "SID", - "context": {}, - "arg1": "val1" }, - "id": null} - - <-- {"jsonrpc": "2.0", - "result": { "res1": "val1" }, - "id": null} - - Request producing a error:: - - --> {"jsonrpc": "2.0", - "method": "call", - "params": {"session_id": "SID", - "context": {}, - "arg1": "val1" }, - "id": null} - - <-- {"jsonrpc": "2.0", - "error": {"code": 1, - "message": "End user error message.", - "data": {"code": "codestring", - "debug": "traceback" } }, - "id": null} - - """ - - def dispatch(self, controller, method, requestf=None, request=None): - """ Calls the method asked for by the JSON-RPC2 request - - :param controller: the instance of the controller which received the request - :param method: the method which received the request - :param requestf: a file-like object containing an encoded JSON-RPC2 request - :param request: a JSON-RPC2 request - - :returns: an utf8 encoded JSON-RPC2 reply - """ - response = {"jsonrpc": "2.0" } - error = None - try: - # Read POST content or POST Form Data named "request" - if requestf: - self.jsonrequest = simplejson.load(requestf, object_hook=nonliterals.non_literal_decoder) - else: - self.jsonrequest = simplejson.loads(request, object_hook=nonliterals.non_literal_decoder) - self.init(self.jsonrequest.get("params", {})) - if _logger.isEnabledFor(logging.DEBUG): - _logger.debug("--> %s.%s\n%s", controller.__class__.__name__, method.__name__, pprint.pformat(self.jsonrequest)) - response['id'] = self.jsonrequest.get('id') - response["result"] = method(controller, self, **self.params) - except openerplib.AuthenticationError: - error = { - 'code': 100, - 'message': "OpenERP Session Invalid", - 'data': { - 'type': 'session_invalid', - 'debug': traceback.format_exc() - } - } - except xmlrpclib.Fault, e: - error = { - 'code': 200, - 'message': "OpenERP Server Error", - 'data': { - 'type': 'server_exception', - 'fault_code': e.faultCode, - 'debug': "Client %s\nServer %s" % ( - "".join(traceback.format_exception("", None, sys.exc_traceback)), e.faultString) - } - } - except Exception: - logging.getLogger(__name__ + '.JSONRequest.dispatch').exception\ - ("An error occured while handling a json request") - error = { - 'code': 300, - 'message': "OpenERP WebClient Error", - 'data': { - 'type': 'client_exception', - 'debug': "Client %s" % traceback.format_exc() - } - } - if error: - response["error"] = error - - if _logger.isEnabledFor(logging.DEBUG): - _logger.debug("<--\n%s", pprint.pformat(response)) - content = simplejson.dumps(response, cls=nonliterals.NonLiteralEncoder) - return werkzeug.wrappers.Response( - content, headers=[('Content-Type', 'application/json'), - ('Content-Length', len(content))]) - -def jsonrequest(f): - """ Decorator marking the decorated method as being a handler for a - JSON-RPC request (the exact request path is specified via the - ``$(Controller._cp_path)/$methodname`` combination. - - If the method is called, it will be provided with a :class:`JsonRequest` - instance and all ``params`` sent during the JSON-RPC request, apart from - the ``session_id``, ``context`` and ``debug`` keys (which are stripped out - beforehand) - """ - @functools.wraps(f) - def json_handler(controller, request, config): - return JsonRequest(request, config).dispatch( - controller, f, requestf=request.stream) - json_handler.exposed = True - return json_handler - -class HttpRequest(WebRequest): - """ Regular GET/POST request - """ - def dispatch(self, controller, method): - params = dict(self.httprequest.args) - params.update(self.httprequest.form) - params.update(self.httprequest.files) - self.init(params) - akw = {} - for key, value in self.httprequest.args.iteritems(): - if isinstance(value, basestring) and len(value) < 1024: - akw[key] = value - else: - akw[key] = type(value) - _logger.debug("%s --> %s.%s %r", self.httprequest.method, controller.__class__.__name__, method.__name__, akw) - r = method(controller, self, **self.params) - if self.debug or 1: - if isinstance(r, werkzeug.wrappers.BaseResponse): - _logger.debug('<-- %s', r) - else: - _logger.debug("<-- size: %s", len(r)) - return r - - def make_response(self, data, headers=None, cookies=None): - """ Helper for non-HTML responses, or HTML responses with custom - response headers or cookies. - - While handlers can just return the HTML markup of a page they want to - send as a string if non-HTML data is returned they need to create a - complete response object, or the returned data will not be correctly - interpreted by the clients. - - :param basestring data: response body - :param headers: HTTP headers to set on the response - :type headers: ``[(name, value)]`` - :param collections.Mapping cookies: cookies to set on the client - """ - response = werkzeug.wrappers.Response(data, headers=headers) - if cookies: - for k, v in cookies.iteritems(): - response.set_cookie(k, v) - return response - - def not_found(self, description=None): - """ Helper for 404 response, return its result from the method - """ - return werkzeug.exceptions.NotFound(description) - -def httprequest(f): - """ Decorator marking the decorated method as being a handler for a - normal HTTP request (the exact request path is specified via the - ``$(Controller._cp_path)/$methodname`` combination. - - If the method is called, it will be provided with a :class:`HttpRequest` - instance and all ``params`` sent during the request (``GET`` and ``POST`` - merged in the same dictionary), apart from the ``session_id``, ``context`` - and ``debug`` keys (which are stripped out beforehand) - """ - @functools.wraps(f) - def http_handler(controller, request, config): - return HttpRequest(request, config).dispatch(controller, f) - http_handler.exposed = True - return http_handler - -class ControllerType(type): - def __init__(cls, name, bases, attrs): - super(ControllerType, cls).__init__(name, bases, attrs) - controllers_class["%s.%s" % (cls.__module__, cls.__name__)] = cls - -class Controller(object): - __metaclass__ = ControllerType - -class Root(object): - """Root WSGI application for the OpenERP Web Client. - - :param options: mandatory initialization options object, must provide - the following attributes: - - ``server_host`` (``str``) - hostname of the OpenERP server to dispatch RPC to - ``server_port`` (``int``) - RPC port of the OpenERP server - ``serve_static`` (``bool | None``) - whether this application should serve the various - addons's static files - ``storage_path`` (``str``) - filesystem path where HTTP session data will be stored - ``dbfilter`` (``str``) - only used in case the list of databases is requested - by the server, will be filtered by this pattern - """ - def __init__(self, options): - self.root = '/web/webclient/home' - self.config = options - - if self.config.backend == 'local': - conn = openerplib.get_connector(protocol='local') - else: - conn = openerplib.get_connector(hostname=self.config.server_host, - port=self.config.server_port) - self.config.connector = conn - - self.session_cookie = 'sessionid' - self.addons = {} - - static_dirs = self._load_addons() - if options.serve_static: - self.dispatch = werkzeug.wsgi.SharedDataMiddleware( - self.dispatch, static_dirs) - - if options.session_storage: - if not os.path.exists(options.session_storage): - os.mkdir(options.session_storage, 0700) - self.session_storage = options.session_storage - - def __call__(self, environ, start_response): - """ Handle a WSGI request - """ - return self.dispatch(environ, start_response) - - def dispatch(self, environ, start_response): - """ - Performs the actual WSGI dispatching for the application, may be - wrapped during the initialization of the object. - - Call the object directly. - """ - request = werkzeug.wrappers.Request(environ) - request.parameter_storage_class = werkzeug.datastructures.ImmutableDict - - if request.path == '/': - params = urllib.urlencode(dict(request.args, debug='')) - return werkzeug.utils.redirect(self.root + '?' + params, 301)( - environ, start_response) - elif request.path == '/mobile': - return werkzeug.utils.redirect( - '/web_mobile/static/src/web_mobile.html', 301)(environ, start_response) - - handler = self.find_handler(*(request.path.split('/')[1:])) - - if not handler: - response = werkzeug.exceptions.NotFound() - else: - with http.session(request, self.session_storage, self.session_cookie) as session: - result = handler( - request, self.config) - - if isinstance(result, basestring): - response = werkzeug.wrappers.Response( - result, headers=[('Content-Type', 'text/html; charset=utf-8'), - ('Content-Length', len(result))]) - else: - response = result - - response.set_cookie(self.session_cookie, session.sid) - - return response(environ, start_response) - - def _load_addons(self): - """ - Loads all addons at the specified addons path, returns a mapping of - static URLs to the corresponding directories - """ - statics = {} - for addons_path in self.config.addons_path: - if addons_path not in sys.path: - sys.path.insert(0, addons_path) - for module in os.listdir(addons_path): - if module not in addons_module: - manifest_path = os.path.join(addons_path, module, '__openerp__.py') - path_static = os.path.join(addons_path, module, 'static') - if os.path.isfile(manifest_path) and os.path.isdir(path_static): - manifest = ast.literal_eval(open(manifest_path).read()) - manifest['addons_path'] = addons_path - _logger.info("Loading %s", module) - m = __import__(module) - addons_module[module] = m - addons_manifest[module] = manifest - statics['/%s/static' % module] = path_static - for k, v in controllers_class.items(): - if k not in controllers_object: - o = v() - controllers_object[k] = o - if hasattr(o, '_cp_path'): - controllers_path[o._cp_path] = o - return statics - - def find_handler(self, *l): - """ - Tries to discover the controller handling the request for the path - specified by the provided parameters - - :param l: path sections to a controller or controller method - :returns: a callable matching the path sections, or ``None`` - :rtype: ``Controller | None`` - """ - if len(l) > 1: - for i in range(len(l), 1, -1): - ps = "/" + "/".join(l[0:i]) - if ps in controllers_path: - c = controllers_path[ps] - rest = l[i:] or ['index'] - meth = rest[0] - m = getattr(c, meth) - if getattr(m, 'exposed', False): - _logger.debug("Dispatching to %s %s %s", ps, c, meth) - return m - return None diff --git a/addons/web/common/http.py b/addons/web/common/http.py index 0186fd985cc..453484acee7 100644 --- a/addons/web/common/http.py +++ b/addons/web/common/http.py @@ -1,13 +1,286 @@ # -*- coding: utf-8 -*- - +#---------------------------------------------------------- +# OpenERP Web HTTP layer +#---------------------------------------------------------- +import ast import contextlib +import functools +import logging +import urllib +import os +import pprint +import sys +import traceback +import uuid +import xmlrpclib +import simplejson import werkzeug.contrib.sessions +import werkzeug.datastructures +import werkzeug.exceptions +import werkzeug.utils +import werkzeug.wrappers +import werkzeug.wsgi +import nonliterals +import session +import openerplib + +__all__ = ['Root', 'jsonrequest', 'httprequest', 'Controller', + 'WebRequest', 'JsonRequest', 'HttpRequest'] + +_logger = logging.getLogger(__name__) + +#---------------------------------------------------------- +# OpenERP Web RequestHandler +#---------------------------------------------------------- +class WebRequest(object): + """ Parent class for all OpenERP Web request types, mostly deals with + initialization and setup of the request object (the dispatching itself has + to be handled by the subclasses) + + :param request: a wrapped werkzeug Request object + :type request: :class:`werkzeug.wrappers.BaseRequest` + :param config: configuration object + + .. attribute:: httprequest + + the original :class:`werkzeug.wrappers.Request` object provided to the + request + + .. attribute:: httpsession + + a :class:`~collections.Mapping` holding the HTTP session data for the + current http session + + .. attribute:: config + + config parameter provided to the request object + + .. attribute:: params + + :class:`~collections.Mapping` of request parameters, not generally + useful as they're provided directly to the handler method as keyword + arguments + + .. attribute:: session_id + + opaque identifier for the :class:`session.OpenERPSession` instance of + the current request + + .. attribute:: session + + :class:`~session.OpenERPSession` instance for the current request + + .. attribute:: context + + :class:`~collections.Mapping` of context values for the current request + + .. attribute:: debug + + ``bool``, indicates whether the debug mode is active on the client + """ + def __init__(self, request, config): + self.httprequest = request + self.httpresponse = None + self.httpsession = request.session + self.config = config + + def init(self, params): + self.params = dict(params) + # OpenERP session setup + self.session_id = self.params.pop("session_id", None) or uuid.uuid4().hex + self.session = self.httpsession.setdefault(self.session_id, session.OpenERPSession()) + self.session.config = self.config + self.context = self.params.pop('context', None) + self.debug = self.params.pop('debug', False) != False + +class JsonRequest(WebRequest): + """ JSON-RPC2 over HTTP. + + Sucessful request:: + + --> {"jsonrpc": "2.0", + "method": "call", + "params": {"session_id": "SID", + "context": {}, + "arg1": "val1" }, + "id": null} + + <-- {"jsonrpc": "2.0", + "result": { "res1": "val1" }, + "id": null} + + Request producing a error:: + + --> {"jsonrpc": "2.0", + "method": "call", + "params": {"session_id": "SID", + "context": {}, + "arg1": "val1" }, + "id": null} + + <-- {"jsonrpc": "2.0", + "error": {"code": 1, + "message": "End user error message.", + "data": {"code": "codestring", + "debug": "traceback" } }, + "id": null} + + """ + + def dispatch(self, controller, method, requestf=None, request=None): + """ Calls the method asked for by the JSON-RPC2 request + + :param controller: the instance of the controller which received the request + :param method: the method which received the request + :param requestf: a file-like object containing an encoded JSON-RPC2 request + :param request: a JSON-RPC2 request + + :returns: an utf8 encoded JSON-RPC2 reply + """ + response = {"jsonrpc": "2.0" } + error = None + try: + # Read POST content or POST Form Data named "request" + if requestf: + self.jsonrequest = simplejson.load(requestf, object_hook=nonliterals.non_literal_decoder) + else: + self.jsonrequest = simplejson.loads(request, object_hook=nonliterals.non_literal_decoder) + self.init(self.jsonrequest.get("params", {})) + if _logger.isEnabledFor(logging.DEBUG): + _logger.debug("--> %s.%s\n%s", controller.__class__.__name__, method.__name__, pprint.pformat(self.jsonrequest)) + response['id'] = self.jsonrequest.get('id') + response["result"] = method(controller, self, **self.params) + except openerplib.AuthenticationError: + error = { + 'code': 100, + 'message': "OpenERP Session Invalid", + 'data': { + 'type': 'session_invalid', + 'debug': traceback.format_exc() + } + } + except xmlrpclib.Fault, e: + error = { + 'code': 200, + 'message': "OpenERP Server Error", + 'data': { + 'type': 'server_exception', + 'fault_code': e.faultCode, + 'debug': "Client %s\nServer %s" % ( + "".join(traceback.format_exception("", None, sys.exc_traceback)), e.faultString) + } + } + except Exception: + logging.getLogger(__name__ + '.JSONRequest.dispatch').exception\ + ("An error occured while handling a json request") + error = { + 'code': 300, + 'message': "OpenERP WebClient Error", + 'data': { + 'type': 'client_exception', + 'debug': "Client %s" % traceback.format_exc() + } + } + if error: + response["error"] = error + + if _logger.isEnabledFor(logging.DEBUG): + _logger.debug("<--\n%s", pprint.pformat(response)) + content = simplejson.dumps(response, cls=nonliterals.NonLiteralEncoder) + return werkzeug.wrappers.Response( + content, headers=[('Content-Type', 'application/json'), + ('Content-Length', len(content))]) + +def jsonrequest(f): + """ Decorator marking the decorated method as being a handler for a + JSON-RPC request (the exact request path is specified via the + ``$(Controller._cp_path)/$methodname`` combination. + + If the method is called, it will be provided with a :class:`JsonRequest` + instance and all ``params`` sent during the JSON-RPC request, apart from + the ``session_id``, ``context`` and ``debug`` keys (which are stripped out + beforehand) + """ + @functools.wraps(f) + def json_handler(controller, request, config): + return JsonRequest(request, config).dispatch( + controller, f, requestf=request.stream) + json_handler.exposed = True + return json_handler + +class HttpRequest(WebRequest): + """ Regular GET/POST request + """ + def dispatch(self, controller, method): + params = dict(self.httprequest.args) + params.update(self.httprequest.form) + params.update(self.httprequest.files) + self.init(params) + akw = {} + for key, value in self.httprequest.args.iteritems(): + if isinstance(value, basestring) and len(value) < 1024: + akw[key] = value + else: + akw[key] = type(value) + _logger.debug("%s --> %s.%s %r", self.httprequest.method, controller.__class__.__name__, method.__name__, akw) + r = method(controller, self, **self.params) + if self.debug or 1: + if isinstance(r, werkzeug.wrappers.BaseResponse): + _logger.debug('<-- %s', r) + else: + _logger.debug("<-- size: %s", len(r)) + return r + + def make_response(self, data, headers=None, cookies=None): + """ Helper for non-HTML responses, or HTML responses with custom + response headers or cookies. + + While handlers can just return the HTML markup of a page they want to + send as a string if non-HTML data is returned they need to create a + complete response object, or the returned data will not be correctly + interpreted by the clients. + + :param basestring data: response body + :param headers: HTTP headers to set on the response + :type headers: ``[(name, value)]`` + :param collections.Mapping cookies: cookies to set on the client + """ + response = werkzeug.wrappers.Response(data, headers=headers) + if cookies: + for k, v in cookies.iteritems(): + response.set_cookie(k, v) + return response + + def not_found(self, description=None): + """ Helper for 404 response, return its result from the method + """ + return werkzeug.exceptions.NotFound(description) + +def httprequest(f): + """ Decorator marking the decorated method as being a handler for a + normal HTTP request (the exact request path is specified via the + ``$(Controller._cp_path)/$methodname`` combination. + + If the method is called, it will be provided with a :class:`HttpRequest` + instance and all ``params`` sent during the request (``GET`` and ``POST`` + merged in the same dictionary), apart from the ``session_id``, ``context`` + and ``debug`` keys (which are stripped out beforehand) + """ + @functools.wraps(f) + def http_handler(controller, request, config): + return HttpRequest(request, config).dispatch(controller, f) + http_handler.exposed = True + return http_handler + +#---------------------------------------------------------- +# OpenERP Web werkzeug Session Managment wraped using with +#---------------------------------------------------------- STORES = {} @contextlib.contextmanager -def session(request, storage_path, session_cookie='sessionid'): +def session_context(request, storage_path, session_cookie='sessionid'): session_store = STORES.get(storage_path) if not session_store: session_store = werkzeug.contrib.sessions.FilesystemSessionStore( @@ -24,3 +297,157 @@ def session(request, storage_path, session_cookie='sessionid'): yield request.session finally: session_store.save(request.session) + +#---------------------------------------------------------- +# OpenERP Web Module/Controller Loading and URL Routing +#---------------------------------------------------------- +addons_module = {} +addons_manifest = {} +controllers_class = {} +controllers_object = {} +controllers_path = {} + +class ControllerType(type): + def __init__(cls, name, bases, attrs): + super(ControllerType, cls).__init__(name, bases, attrs) + controllers_class["%s.%s" % (cls.__module__, cls.__name__)] = cls + +class Controller(object): + __metaclass__ = ControllerType + +class Root(object): + """Root WSGI application for the OpenERP Web Client. + + :param options: mandatory initialization options object, must provide + the following attributes: + + ``server_host`` (``str``) + hostname of the OpenERP server to dispatch RPC to + ``server_port`` (``int``) + RPC port of the OpenERP server + ``serve_static`` (``bool | None``) + whether this application should serve the various + addons's static files + ``storage_path`` (``str``) + filesystem path where HTTP session data will be stored + ``dbfilter`` (``str``) + only used in case the list of databases is requested + by the server, will be filtered by this pattern + """ + def __init__(self, options): + self.root = '/web/webclient/home' + self.config = options + + if self.config.backend == 'local': + conn = openerplib.get_connector(protocol='local') + else: + conn = openerplib.get_connector(hostname=self.config.server_host, + port=self.config.server_port) + self.config.connector = conn + + self.session_cookie = 'sessionid' + self.addons = {} + + static_dirs = self._load_addons() + if options.serve_static: + self.dispatch = werkzeug.wsgi.SharedDataMiddleware( + self.dispatch, static_dirs) + + if options.session_storage: + if not os.path.exists(options.session_storage): + os.mkdir(options.session_storage, 0700) + self.session_storage = options.session_storage + + def __call__(self, environ, start_response): + """ Handle a WSGI request + """ + return self.dispatch(environ, start_response) + + def dispatch(self, environ, start_response): + """ + Performs the actual WSGI dispatching for the application, may be + wrapped during the initialization of the object. + + Call the object directly. + """ + request = werkzeug.wrappers.Request(environ) + request.parameter_storage_class = werkzeug.datastructures.ImmutableDict + + if request.path == '/': + params = urllib.urlencode(dict(request.args, debug='')) + return werkzeug.utils.redirect(self.root + '?' + params, 301)( + environ, start_response) + elif request.path == '/mobile': + return werkzeug.utils.redirect( + '/web_mobile/static/src/web_mobile.html', 301)(environ, start_response) + + handler = self.find_handler(*(request.path.split('/')[1:])) + + if not handler: + response = werkzeug.exceptions.NotFound() + else: + with session_context(request, self.session_storage, self.session_cookie) as session: + result = handler( request, self.config) + + if isinstance(result, basestring): + headers=[('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', len(result))] + response = werkzeug.wrappers.Response(result, headers=headers) + else: + response = result + + response.set_cookie(self.session_cookie, session.sid) + + return response(environ, start_response) + + def _load_addons(self): + """ + Loads all addons at the specified addons path, returns a mapping of + static URLs to the corresponding directories + """ + statics = {} + for addons_path in self.config.addons_path: + if addons_path not in sys.path: + sys.path.insert(0, addons_path) + for module in os.listdir(addons_path): + if module not in addons_module: + manifest_path = os.path.join(addons_path, module, '__openerp__.py') + path_static = os.path.join(addons_path, module, 'static') + if os.path.isfile(manifest_path) and os.path.isdir(path_static): + manifest = ast.literal_eval(open(manifest_path).read()) + manifest['addons_path'] = addons_path + _logger.info("Loading %s", module) + m = __import__(module) + addons_module[module] = m + addons_manifest[module] = manifest + statics['/%s/static' % module] = path_static + for k, v in controllers_class.items(): + if k not in controllers_object: + o = v() + controllers_object[k] = o + if hasattr(o, '_cp_path'): + controllers_path[o._cp_path] = o + return statics + + def find_handler(self, *l): + """ + Tries to discover the controller handling the request for the path + specified by the provided parameters + + :param l: path sections to a controller or controller method + :returns: a callable matching the path sections, or ``None`` + :rtype: ``Controller | None`` + """ + if len(l) > 1: + for i in range(len(l), 1, -1): + ps = "/" + "/".join(l[0:i]) + if ps in controllers_path: + c = controllers_path[ps] + rest = l[i:] or ['index'] + meth = rest[0] + m = getattr(c, meth) + if getattr(m, 'exposed', False): + _logger.debug("Dispatching to %s %s %s", ps, c, meth) + return m + return None + +# diff --git a/addons/web/common/session.py b/addons/web/common/session.py index 2ed50bd6131..e8027db8ea4 100644 --- a/addons/web/common/session.py +++ b/addons/web/common/session.py @@ -1,17 +1,16 @@ #!/usr/bin/python import datetime import dateutil.relativedelta +import logging import time import openerplib import nonliterals -import logging _logger = logging.getLogger(__name__) #---------------------------------------------------------- # OpenERPSession RPC openerp backend access #---------------------------------------------------------- - class OpenERPSession(object): """ An OpenERP RPC session, a given user can own multiple such sessions diff --git a/addons/web/common/xml2json.py b/addons/web/common/xml2json.py new file mode 100644 index 00000000000..16022624fe7 --- /dev/null +++ b/addons/web/common/xml2json.py @@ -0,0 +1,38 @@ +# xml2json-direct +# Simple and straightforward XML-to-JSON converter in Python +# New BSD Licensed +# +# URL: http://code.google.com/p/xml2json-direct/ + +class Xml2Json(object): + @staticmethod + def convert_to_json(s): + return simplejson.dumps( + Xml2Json.convert_to_structure(s), sort_keys=True, indent=4) + + @staticmethod + def convert_to_structure(s): + root = ElementTree.fromstring(s) + return Xml2Json.convert_element(root) + + @staticmethod + def convert_element(el, skip_whitespaces=True): + res = {} + if el.tag[0] == "{": + ns, name = el.tag.rsplit("}", 1) + res["tag"] = name + res["namespace"] = ns[1:] + else: + res["tag"] = el.tag + res["attrs"] = {} + for k, v in el.items(): + res["attrs"][k] = v + kids = [] + if el.text and (not skip_whitespaces or el.text.strip() != ''): + kids.append(el.text) + for kid in el: + kids.append(Xml2Json.convert_element(kid)) + if kid.tail and (not skip_whitespaces or kid.tail.strip() != ''): + kids.append(kid.tail) + res["children"] = kids + return res diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 9be0794a8bb..7ca80fbfdec 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +import ast import base64 import csv import glob @@ -9,60 +10,16 @@ import os import re import simplejson import textwrap -import xmlrpclib import time +import xmlrpclib import zlib from xml.etree import ElementTree from cStringIO import StringIO -from babel.messages.pofile import read_po +import babel.messages.pofile -import web.common.dispatch as openerpweb -import web.common.ast -import web.common.nonliterals -import web.common.release -openerpweb.ast = web.common.ast -openerpweb.nonliterals = web.common.nonliterals - - -# Should move to openerpweb.Xml2Json -class Xml2Json: - # xml2json-direct - # Simple and straightforward XML-to-JSON converter in Python - # New BSD Licensed - # - # URL: http://code.google.com/p/xml2json-direct/ - @staticmethod - def convert_to_json(s): - return simplejson.dumps( - Xml2Json.convert_to_structure(s), sort_keys=True, indent=4) - - @staticmethod - def convert_to_structure(s): - root = ElementTree.fromstring(s) - return Xml2Json.convert_element(root) - - @staticmethod - def convert_element(el, skip_whitespaces=True): - res = {} - if el.tag[0] == "{": - ns, name = el.tag.rsplit("}", 1) - res["tag"] = name - res["namespace"] = ns[1:] - else: - res["tag"] = el.tag - res["attrs"] = {} - for k, v in el.items(): - res["attrs"][k] = v - kids = [] - if el.text and (not skip_whitespaces or el.text.strip() != ''): - kids.append(el.text) - for kid in el: - kids.append(Xml2Json.convert_element(kid)) - if kid.tail and (not skip_whitespaces or kid.tail.strip() != ''): - kids.append(kid.tail) - res["children"] = kids - return res +import web.common +openerpweb = web.common.http #---------------------------------------------------------- # OpenERP Web web Controllers @@ -200,7 +157,7 @@ class WebClient(openerpweb.Controller): continue try: with open(f_name) as t_file: - po = read_po(t_file) + po = babel.messages.pofile.read_po(t_file) except: continue for x in po: @@ -358,13 +315,22 @@ class Session(openerpweb.Controller): @openerpweb.jsonrequest def modules(self, req): - # TODO query server for installed web modules - mods = [] - for name, manifest in openerpweb.addons_manifest.items(): - # TODO replace by ir.module.module installed web - if name not in req.config.server_wide_modules and manifest.get('active', True): - mods.append(name) - return mods + # Compute available candidates module + loadable = openerpweb.addons_manifest.iterkeys() + loaded = req.config.server_wide_modules + candidates = [mod for mod in loadable if mod not in loaded] + + # Compute active true modules that might be on the web side only + active = set(name for name in candidates + if openerpweb.addons_manifest[name].get('active')) + + # Retrieve database installed modules + Modules = req.session.model('ir.module.module') + installed = set(module['name'] for module in Modules.search_read( + [('state','=','installed'), ('name','in', candidates)], ['name'])) + + # Merge both + return list(active | installed) @openerpweb.jsonrequest def eval_domain_and_context(self, req, contexts, domains, @@ -399,8 +365,8 @@ class Session(openerpweb.Controller): no group by should be performed) """ context, domain = eval_context_and_domain(req.session, - openerpweb.nonliterals.CompoundContext(*(contexts or [])), - openerpweb.nonliterals.CompoundDomain(*(domains or []))) + web.common.nonliterals.CompoundContext(*(contexts or [])), + web.common.nonliterals.CompoundDomain(*(domains or []))) group_by_sequence = [] for candidate in (group_by_seq or []): @@ -817,7 +783,7 @@ class View(openerpweb.Controller): xml = self.transform_view(arch, session, evaluation_context) else: xml = ElementTree.fromstring(arch) - fvg['arch'] = Xml2Json.convert_element(xml) + fvg['arch'] = web.common.xml2json.Xml2Json.convert_element(xml) for field in fvg['fields'].itervalues(): if field.get('views'): @@ -882,7 +848,7 @@ class View(openerpweb.Controller): def parse_domain(self, domain, session): """ Parses an arbitrary string containing a domain, transforms it - to either a literal domain or a :class:`openerpweb.nonliterals.Domain` + to either a literal domain or a :class:`web.common.nonliterals.Domain` :param domain: the domain to parse, if the domain is not a string it is assumed to be a literal domain and is returned as-is @@ -892,14 +858,14 @@ class View(openerpweb.Controller): if not isinstance(domain, (str, unicode)): return domain try: - return openerpweb.ast.literal_eval(domain) + return ast.literal_eval(domain) except ValueError: # not a literal - return openerpweb.nonliterals.Domain(session, domain) + return web.common.nonliterals.Domain(session, domain) def parse_context(self, context, session): """ Parses an arbitrary string containing a context, transforms it - to either a literal context or a :class:`openerpweb.nonliterals.Context` + to either a literal context or a :class:`web.common.nonliterals.Context` :param context: the context to parse, if the context is not a string it is assumed to be a literal domain and is returned as-is @@ -909,9 +875,9 @@ class View(openerpweb.Controller): if not isinstance(context, (str, unicode)): return context try: - return openerpweb.ast.literal_eval(context) + return ast.literal_eval(context) except ValueError: - return openerpweb.nonliterals.Context(session, context) + return web.common.nonliterals.Context(session, context) def parse_domains_and_contexts(self, elem, session): """ Converts domains and contexts from the view into Python objects, @@ -999,10 +965,10 @@ class SearchView(View): @openerpweb.jsonrequest def save_filter(self, req, model, name, context_to_save, domain): Model = req.session.model("ir.filters") - ctx = openerpweb.nonliterals.CompoundContext(context_to_save) + ctx = web.common.nonliterals.CompoundContext(context_to_save) ctx.session = req.session ctx = ctx.evaluate() - domain = openerpweb.nonliterals.CompoundDomain(domain) + domain = web.common.nonliterals.CompoundDomain(domain) domain.session = req.session domain = domain.evaluate() uid = req.session._uid @@ -1025,16 +991,17 @@ class Binary(openerpweb.Controller): try: if not id: - res = Model.default_get([field], context).get(field, '') + res = Model.default_get([field], context).get(field) else: - res = Model.read([int(id)], [field], context)[0].get(field, '') + res = Model.read([int(id)], [field], context)[0].get(field) image_data = base64.b64decode(res) except (TypeError, xmlrpclib.Fault): image_data = self.placeholder(req) return req.make_response(image_data, [ ('Content-Type', 'image/png'), ('Content-Length', len(image_data))]) def placeholder(self, req): - return open(os.path.join(req.addons_path, 'web', 'static', 'src', 'img', 'placeholder.png'), 'rb').read() + addons_path = openerpweb.addons_manifest['web']['addons_path'] + return open(os.path.join(addons_path, 'web', 'static', 'src', 'img', 'placeholder.png'), 'rb').read() @openerpweb.httprequest def saveas(self, req, model, id, field, fieldname, **kw): @@ -1393,7 +1360,7 @@ class Reports(View): report_srv = req.session.proxy("report") context = req.session.eval_context( - openerpweb.nonliterals.CompoundContext( + web.common.nonliterals.CompoundContext( req.context or {}, action[ "context"])) report_data = {} @@ -1432,7 +1399,6 @@ class Reports(View): ('Content-Length', len(report))], cookies={'fileToken': int(token)}) - class Import(View): _cp_path = "/web/import" diff --git a/addons/web/po/es_EC.po b/addons/web/po/es_EC.po new file mode 100644 index 00000000000..eb2283f6fe5 --- /dev/null +++ b/addons/web/po/es_EC.po @@ -0,0 +1,710 @@ +# Spanish (Ecuador) translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:38+0200\n" +"PO-Revision-Date: 2011-10-07 18:16+0000\n" +"Last-Translator: Cristian Salamea (Gnuthink) \n" +"Language-Team: Spanish (Ecuador) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2011-10-08 05:29+0000\n" +"X-Generator: Launchpad (build 14110)\n" + +#: addons/web/static/src/js/view_form.js:355 +msgid "" +"Warning, the record has been modified, your changes will be discarded." +msgstr "" +"Aviso, el registro ha sido modificado, sus cambios serán descartados." + +#: addons/web/static/src/js/view_form.js:1659 +msgid "   Search More..." +msgstr "   Buscar Más..." + +#: addons/web/static/src/js/view_form.js:1672 +#, python-format +msgid "   Create \"%s\"" +msgstr "   Crear \"%s\"" + +#: addons/web/static/src/js/view_form.js:1678 +msgid "   Create and Edit..." +msgstr "   Crear y Editar..." + +#: addons/web/static/src/js/views.js:568 +msgid "You must choose at least one record." +msgstr "Debe seleccionar al menos un registro." + +#: addons/web/static/src/js/views.js:569 +msgid "Warning" +msgstr "Advertencia" + +#: addons/web/static/src/js/views.js:609 +msgid "Translations" +msgstr "Traducciones" + +#: addons/web/static/src/js/views.js:614 addons/web/static/src/xml/base.xml:0 +msgid "Save" +msgstr "Guardar" + +#: addons/web/static/src/js/views.js:615 +msgid "Close" +msgstr "Cerrar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "x" +msgstr "x" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#{title}" +msgstr "#{title}" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#{text}" +msgstr "#{text}" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Powered by" +msgstr "Powered by" + +#: addons/web/static/src/xml/base.xml:0 +msgid "openerp.com" +msgstr "openerp.com" + +#: addons/web/static/src/xml/base.xml:0 +msgid "." +msgstr "." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Loading..." +msgstr "Cargando..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create" +msgstr "Crear" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Drop" +msgstr "Borrar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Backup" +msgstr "Respaldar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Restore" +msgstr "Restaurar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password" +msgstr "Contraseña" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Back to Login" +msgstr "Regresar a inicio de sesión" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CREATE DATABASE" +msgstr "CREATE DATABASE" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Master password:" +msgstr "Master password:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New database name:" +msgstr "Nuevo nombre de la base de datos:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Load Demonstration data:" +msgstr "Cargar datos de demostración" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Default language:" +msgstr "Lenguaje por defecto:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Admin password:" +msgstr "Admin password:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm password:" +msgstr "Confirmar password:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "DROP DATABASE" +msgstr "DROP DATABASE" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database:" +msgstr "Base de datos:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Master Password:" +msgstr "Master Password:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "BACKUP DATABASE" +msgstr "BACKUP DATABASE" + +#: addons/web/static/src/xml/base.xml:0 +msgid "RESTORE DATABASE" +msgstr "RESTORE DATABASE" + +#: addons/web/static/src/xml/base.xml:0 +msgid "File:" +msgstr "Archivo:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CHANGE MASTER PASSWORD" +msgstr "CHANGE MASTER PASSWORD" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New master password:" +msgstr "New master password:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm new master password:" +msgstr "Confirmar nueva master password:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "User:" +msgstr "Usuario:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password:" +msgstr "Contraseña:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database" +msgstr "Bases de datos" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Login" +msgstr "Iniciar sesión" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Bad username or password" +msgstr "Usuario o contraseña incorrectos" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"We think that daily job activities can be more intuitive, efficient, " +"automated, .. and even fun." +msgstr "" +"Pensamos que el trabajo diario debe ser mas intuitivo, eficiente, " +"automatizado, ... e incluso divertido." + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP's vision to be:" +msgstr "OpenERP's vision to be:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Full featured" +msgstr "Full featured" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Today's enterprise challenges are multiple. We provide one module for each " +"need." +msgstr "" +"Today's enterprise challenges are multiple. We provide one module for each " +"need." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open Source" +msgstr "Open Source" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"To Build a great product, we rely on the knowledge of thousands of " +"contributors." +msgstr "" +"To Build a great product, we rely on the knowledge of thousands of " +"contributors." + +#: addons/web/static/src/xml/base.xml:0 +msgid "User Friendly" +msgstr "User Friendly" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"In order to be productive, people need clean and easy to use interface." +msgstr "" +"Para ser productivo, los usuarios necesitan una interfaz limpia y fácil de " +"usar." + +#: addons/web/static/src/xml/base.xml:0 +msgid "(" +msgstr "(" + +#: addons/web/static/src/xml/base.xml:0 +msgid ")" +msgstr ")" + +#: addons/web/static/src/xml/base.xml:0 +msgid "LOGOUT" +msgstr "LOGOUT" + +#: addons/web/static/src/xml/base.xml:0 +msgid "«" +msgstr "«" + +#: addons/web/static/src/xml/base.xml:0 +msgid "»" +msgstr "»" + +#: addons/web/static/src/xml/base.xml:0 +msgid "oe_secondary_menu_item" +msgstr "oe_secondary_menu_item" + +#: addons/web/static/src/xml/base.xml:0 +msgid "oe_secondary_submenu_item" +msgstr "oe_secondary_submenu_item" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Hide this tip" +msgstr "Ocultar este tip" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Disable all tips" +msgstr "Desactivar todas las sugerencias" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View#" +msgstr "View#" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields" +msgstr "Campos" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View labels" +msgstr "Ver etiquetas" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Sidebar Relates" +msgstr "Columna lateral relacionada" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Field" +msgstr "Campo" + +#: addons/web/static/src/xml/base.xml:0 +msgid ":" +msgstr ":" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate view" +msgstr "Traducir vista" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate sidebar" +msgstr "Traducir Barra lateral" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delete" +msgstr "Eliminar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "First" +msgstr "Primero" + +#: addons/web/static/src/xml/base.xml:0 +msgid "<" +msgstr "<" + +#: addons/web/static/src/xml/base.xml:0 +msgid ">" +msgstr ">" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Last" +msgstr "Último" + +#: addons/web/static/src/xml/base.xml:0 +msgid "♻" +msgstr "♻" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Edit" +msgstr "Grabar & Editar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create & Edit" +msgstr "Crear & Editar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New" +msgstr "Nuevo" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Duplicate" +msgstr "Duplicar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Readonly/Editable" +msgstr "Sólo Lectura/Editable" + +#: addons/web/static/src/xml/base.xml:0 +msgid "<<" +msgstr "<<" + +#: addons/web/static/src/xml/base.xml:0 +msgid "0" +msgstr "0" + +#: addons/web/static/src/xml/base.xml:0 +msgid "/" +msgstr "/" + +#: addons/web/static/src/xml/base.xml:0 +msgid ">>" +msgstr ">>" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add" +msgstr "Agregar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Unhandled widget" +msgstr "Wdiget no controlado" + +#: addons/web/static/src/xml/base.xml:0 +msgid "?" +msgstr "?" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#" +msgstr "#" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Done" +msgstr "Realizado" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open..." +msgstr "Abrir…" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create..." +msgstr "Crear..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Search..." +msgstr "Buscar..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "..." +msgstr "..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Uploading ..." +msgstr "Subiendo..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Select" +msgstr "Seleccionar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save As" +msgstr "Guardar Como" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Clear" +msgstr "Limpiar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Advanced Filter" +msgstr "Filtro Avanzado" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Filters --" +msgstr "-- Filtros --" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Actions --" +msgstr "-- Acciones --" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save Filter" +msgstr "Guardar Filtro" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Manage Filters" +msgstr "Gestionar filtros" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Filter Name:" +msgstr "Nombre del Filtro:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "(Any existing filter with the same name will be replaced)" +msgstr "(Cualquier filtro existente con el mismo nombre será reemplazado)" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Any of the following conditions must match" +msgstr "Cualquiera de las siguientes condiciones debe coincidir" + +#: addons/web/static/src/xml/base.xml:0 +msgid "All the following conditions must match" +msgstr "Todas las siguientes condiciones deben coincidir" + +#: addons/web/static/src/xml/base.xml:0 +msgid "None of the following conditions must match" +msgstr "Ninguna de las siguientes condiciones debe coincidir" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add condition" +msgstr "Agregar condición" + +#: addons/web/static/src/xml/base.xml:0 +msgid "and" +msgstr "y" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Cancel" +msgstr "Cancelar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & New" +msgstr "Grabar & Nuevo" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Close" +msgstr "Grabar & Cerrar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export" +msgstr "Exportar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"This wizard will export all data that matches the current search criteria to " +"a CSV file.\n" +" You can export all data or only the fields that can be " +"reimported after modification." +msgstr "" +"Este asistente exportará todos los datos que coincidan con el criterio de " +"búsqueda actual a un archivo CSV.\n" +" Tu puedes exportar todos los datos o solo los campos que serán " +"reimportados después de la modificación." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Type:" +msgstr "Tipo de Exportación" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Compatible Export" +msgstr "Import Compatible Export" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export all Data" +msgstr "Exportar todos los datos" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Formats" +msgstr "Formato para exportar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Available fields" +msgstr "Campos disponibles" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields to export" +msgstr "Campos a exportar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save fields list" +msgstr "Guardar lista de campos" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove" +msgstr "Eliminar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove All" +msgstr "Borrar todo" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Name" +msgstr "Nombre" + +#: addons/web/static/src/xml/base.xml:0 +msgid " " +msgstr " " + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save as:" +msgstr "Guardar Como:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Ok" +msgstr "Ok" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Saved exports:" +msgstr "Exportaciones guardadas:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Old Password:" +msgstr "Password anterior:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New Password:" +msgstr "Nueva Password:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm Password:" +msgstr "Confirmar Password:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import" +msgstr "Importar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "1. Import a .CSV file" +msgstr "1. Importar a archivo .CSV" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Select a .CSV file to import. If you need a sample of file to import,\n" +" you should use the export tool with the \"Import Compatible\" option." +msgstr "" +"Seleccionar un .archivo CSV para importar. Si necesitas un ejemplo de un " +"archivo para importar,\n" +" you podrías usar la herramienta de exportar con la opción de " +"\"Compatible con Importación\"." + +#: addons/web/static/src/xml/base.xml:0 +msgid "CSV File:" +msgstr "Archivo CSV:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "2. Check your file format" +msgstr "Revisa tu formato de archivo" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Options" +msgstr "Opciones para importar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Does your file have titles?" +msgstr "Tiene tu archivo títulos ?" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Separator:" +msgstr "Separador:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delimiter:" +msgstr "Delimitador:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Encoding:" +msgstr "Codificación:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "UTF-8" +msgstr "UTF-8" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Latin 1" +msgstr "Latin 1" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Lines to skip" +msgstr "Líneas a omitir" + +#: addons/web/static/src/xml/base.xml:0 +msgid "The import failed due to:" +msgstr "La importación falló debido a:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Here is a preview of the file we could not import:" +msgstr "Aquí está una vista preliminar del archivo que no podemos importar:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP Web" +msgstr "OpenERP Web" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Version" +msgstr "Versión" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Copyright © 2011-TODAY OpenERP SA. All Rights Reserved." +msgstr "Copyright © 2011-TODAY OpenERP SA. All Rights Reserved." + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP is a trademark of the" +msgstr "OpenERP es una marca registrada de" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP SA Company" +msgstr "OpenERP SA Company" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Licenced under the terms of" +msgstr "Licenciado bajo los términos de" + +#: addons/web/static/src/xml/base.xml:0 +msgid "GNU Affero General Public License" +msgstr "GNU Affero General Public License" + +#: addons/web/static/src/xml/base.xml:0 +msgid "About OpenERP" +msgstr "Acerca de OpenERP" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP" +msgstr "OpenERP" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"is a free enterprise-scale software system that is designed to boost\n" +" productivity and profit through data integration. It connects, " +"improves and\n" +" manages business processes in areas such as sales, finance, " +"supply chain,\n" +" project management, production, services, CRM, etc..." +msgstr "" +"is a free enterprise-scale software system that is designed to boost\n" +" productivity and profit through data integration. It connects, " +"improves and\n" +" manages business processes in areas such as sales, finance, " +"supply chain,\n" +" project management, production, services, CRM, etc..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"The system is platform-independent, and can be installed on Windows, Mac OS " +"X,\n" +" and various Linux and other Unix-based distributions. Its " +"architecture enables\n" +" new functionality to be rapidly created, modifications to be " +"made to a\n" +" production system and migration to a new version to be " +"straightforward." +msgstr "" +"The system is platform-independent, and can be installed on Windows, Mac OS " +"X,\n" +" and various Linux and other Unix-based distributions. Its " +"architecture enables\n" +" new functionality to be rapidly created, modifications to be " +"made to a\n" +" production system and migration to a new version to be " +"straightforward." + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Depending on your needs, OpenERP is available through a web or application " +"client." +msgstr "" +"Dependiendo de tus necesidades, OpenERP está disponible através de un " +"cliente web o escritorio." diff --git a/addons/web/po/it.po b/addons/web/po/it.po new file mode 100644 index 00000000000..fc53244533b --- /dev/null +++ b/addons/web/po/it.po @@ -0,0 +1,689 @@ +# Italian translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:38+0200\n" +"PO-Revision-Date: 2011-10-08 13:39+0000\n" +"Last-Translator: Nicola Riolini - Micronaet \n" +"Language-Team: Italian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2011-10-09 05:22+0000\n" +"X-Generator: Launchpad (build 14110)\n" + +#: addons/web/static/src/js/view_form.js:355 +msgid "" +"Warning, the record has been modified, your changes will be discarded." +msgstr "" +"Attenzione, il record è stato modificato, i vostri cambiamenti verranno " +"scartati." + +#: addons/web/static/src/js/view_form.js:1659 +msgid "   Search More..." +msgstr "   Cerca ancora..." + +#: addons/web/static/src/js/view_form.js:1672 +#, python-format +msgid "   Create \"%s\"" +msgstr "   Crea \"%s\"" + +#: addons/web/static/src/js/view_form.js:1678 +msgid "   Create and Edit..." +msgstr "   Crea e modifica..." + +#: addons/web/static/src/js/views.js:568 +msgid "You must choose at least one record." +msgstr "E' necessario selezionare almeno un record." + +#: addons/web/static/src/js/views.js:569 +msgid "Warning" +msgstr "Attenzione" + +#: addons/web/static/src/js/views.js:609 +msgid "Translations" +msgstr "Traduzioni" + +#: addons/web/static/src/js/views.js:614 addons/web/static/src/xml/base.xml:0 +msgid "Save" +msgstr "Salva" + +#: addons/web/static/src/js/views.js:615 +msgid "Close" +msgstr "Chiudi" + +#: addons/web/static/src/xml/base.xml:0 +msgid "x" +msgstr "x" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#{title}" +msgstr "#{title}" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#{text}" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Powered by" +msgstr "Powered by" + +#: addons/web/static/src/xml/base.xml:0 +msgid "openerp.com" +msgstr "openerp.com" + +#: addons/web/static/src/xml/base.xml:0 +msgid "." +msgstr "." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Loading..." +msgstr "Caricamento..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create" +msgstr "Crea" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Drop" +msgstr "Elimina" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Backup" +msgstr "Backup" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Restore" +msgstr "Ripristina" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password" +msgstr "Password" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Back to Login" +msgstr "Ritorno al Login" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CREATE DATABASE" +msgstr "CREA DATABASE" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Master password:" +msgstr "Password principale" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New database name:" +msgstr "Nome nuovo database:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Load Demonstration data:" +msgstr "Caricadati dimostrativi:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Default language:" +msgstr "Lingua predefinita:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Admin password:" +msgstr "Password di amministrazione:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm password:" +msgstr "Conferma password:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "DROP DATABASE" +msgstr "ELIMINA DATABASE" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database:" +msgstr "Database:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Master Password:" +msgstr "Password principale" + +#: addons/web/static/src/xml/base.xml:0 +msgid "BACKUP DATABASE" +msgstr "BACKUP DATABASE" + +#: addons/web/static/src/xml/base.xml:0 +msgid "RESTORE DATABASE" +msgstr "RIPRISTINA DATABASE" + +#: addons/web/static/src/xml/base.xml:0 +msgid "File:" +msgstr "File:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CHANGE MASTER PASSWORD" +msgstr "CAMBIA PASSWORD PRINCIPALE" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New master password:" +msgstr "Nuova password principale:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm new master password:" +msgstr "Conferma nuova password principale" + +#: addons/web/static/src/xml/base.xml:0 +msgid "User:" +msgstr "Utente:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password:" +msgstr "Password:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database" +msgstr "Database" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Login" +msgstr "Login" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Bad username or password" +msgstr "Username o password errati" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"We think that daily job activities can be more intuitive, efficient, " +"automated, .. and even fun." +msgstr "" +"Pensiamo che le attività quotidiane possano essere più intuitive, " +"efficienti, automatizzate...e anche più divertenti." + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP's vision to be:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Full featured" +msgstr "Completo" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Today's enterprise challenges are multiple. We provide one module for each " +"need." +msgstr "" +"Le esigenze odierne delle aziende sono molteplici. Noi forniamo un modulo " +"per ogni necessità." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open Source" +msgstr "Open Source" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"To Build a great product, we rely on the knowledge of thousands of " +"contributors." +msgstr "" +"Per creare un buon prodotto, facciamo affidamento sull'esperienza di " +"migliaia di contributori." + +#: addons/web/static/src/xml/base.xml:0 +msgid "User Friendly" +msgstr "User Friendly" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"In order to be productive, people need clean and easy to use interface." +msgstr "" +"Per essere produttive, le persone necessitano di interfacce semplici e " +"pulite." + +#: addons/web/static/src/xml/base.xml:0 +msgid "(" +msgstr "(" + +#: addons/web/static/src/xml/base.xml:0 +msgid ")" +msgstr ")" + +#: addons/web/static/src/xml/base.xml:0 +msgid "LOGOUT" +msgstr "LOGOUT" + +#: addons/web/static/src/xml/base.xml:0 +msgid "«" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "»" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "oe_secondary_menu_item" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "oe_secondary_submenu_item" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Hide this tip" +msgstr "Nascondi questo consiglio" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Disable all tips" +msgstr "Disabilita tutti i consigli" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View#" +msgstr "Vista à" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields" +msgstr "Campi" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View labels" +msgstr "Visualizza etichette" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Sidebar Relates" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Field" +msgstr "Campo" + +#: addons/web/static/src/xml/base.xml:0 +msgid ":" +msgstr ":" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate view" +msgstr "Traduci vista" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate sidebar" +msgstr "Traduci barra laterale" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delete" +msgstr "Elimina" + +#: addons/web/static/src/xml/base.xml:0 +msgid "First" +msgstr "Primo" + +#: addons/web/static/src/xml/base.xml:0 +msgid "<" +msgstr "<" + +#: addons/web/static/src/xml/base.xml:0 +msgid ">" +msgstr ">" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Last" +msgstr "Ultimo" + +#: addons/web/static/src/xml/base.xml:0 +msgid "♻" +msgstr "♻" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Edit" +msgstr "Salva & Modifica" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create & Edit" +msgstr "Crea & Modifica" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New" +msgstr "Nuovo" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Duplicate" +msgstr "Duplica" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Readonly/Editable" +msgstr "Sola lettura / Modificabile" + +#: addons/web/static/src/xml/base.xml:0 +msgid "<<" +msgstr "<<" + +#: addons/web/static/src/xml/base.xml:0 +msgid "0" +msgstr "0" + +#: addons/web/static/src/xml/base.xml:0 +msgid "/" +msgstr "/" + +#: addons/web/static/src/xml/base.xml:0 +msgid ">>" +msgstr ">>" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add" +msgstr "Aggiungi" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Unhandled widget" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "?" +msgstr "?" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#" +msgstr "#" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Done" +msgstr "Completato" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open..." +msgstr "Apri..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create..." +msgstr "Crea..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Search..." +msgstr "Cerca..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "..." +msgstr "..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Uploading ..." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Select" +msgstr "Seleziona" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save As" +msgstr "Salva come" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Clear" +msgstr "Pulisci" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Advanced Filter" +msgstr "Filtro avanzato" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Filters --" +msgstr "-- Filtri --" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Actions --" +msgstr "-- Azioni --" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save Filter" +msgstr "Salva Filtro" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Manage Filters" +msgstr "Gestisci Filtri" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Filter Name:" +msgstr "Nome filtro:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "(Any existing filter with the same name will be replaced)" +msgstr "(Eventuali filtri esistenti con lo stesso nome saranno rimpiazzati)" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Any of the following conditions must match" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "All the following conditions must match" +msgstr "Tutte le seguenti condizioni deve verificarsi" + +#: addons/web/static/src/xml/base.xml:0 +msgid "None of the following conditions must match" +msgstr "Nessuna delle seguenti condizioni deve verificarsi" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add condition" +msgstr "Aggiungi condizione" + +#: addons/web/static/src/xml/base.xml:0 +msgid "and" +msgstr "e" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Cancel" +msgstr "Annulla" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & New" +msgstr "Salva & Nuovo" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Close" +msgstr "Salva & Chiudi" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export" +msgstr "Esporta" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"This wizard will export all data that matches the current search criteria to " +"a CSV file.\n" +" You can export all data or only the fields that can be " +"reimported after modification." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Type:" +msgstr "Tipo di esportazione:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Compatible Export" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export all Data" +msgstr "Esporta tutti i dati" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Formats" +msgstr "Formati esportazione" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Available fields" +msgstr "Campi disponibili" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields to export" +msgstr "Campi da esportare" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save fields list" +msgstr "Salva l'elenco dei campi" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove" +msgstr "Rimuovi" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove All" +msgstr "Rimuovi tutto" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Name" +msgstr "Nome" + +#: addons/web/static/src/xml/base.xml:0 +msgid " " +msgstr " " + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save as:" +msgstr "Salva come:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Ok" +msgstr "Ok" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Saved exports:" +msgstr "Esportazioni salvate:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Old Password:" +msgstr "Vecchia Password:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New Password:" +msgstr "Nuova password:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm Password:" +msgstr "Conferma password:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import" +msgstr "Importa" + +#: addons/web/static/src/xml/base.xml:0 +msgid "1. Import a .CSV file" +msgstr "1. Importa un file .CSV" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Select a .CSV file to import. If you need a sample of file to import,\n" +" you should use the export tool with the \"Import Compatible\" option." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CSV File:" +msgstr "File CSV:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "2. Check your file format" +msgstr "2. Controlla il formato del tuo file" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Options" +msgstr "Opzioni di importazione" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Does your file have titles?" +msgstr "Il vostro file ha i titoli?" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Separator:" +msgstr "Separatore:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delimiter:" +msgstr "Delimitatore:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Encoding:" +msgstr "Codifica:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "UTF-8" +msgstr "UTF-8" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Latin 1" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Lines to skip" +msgstr "Linee da saltare" + +#: addons/web/static/src/xml/base.xml:0 +msgid "The import failed due to:" +msgstr "L'importazione è fallita a causa di:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Here is a preview of the file we could not import:" +msgstr "Ecco un anteprima del file che non si è riuscito ad importare:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP Web" +msgstr "OpenERP Web" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Version" +msgstr "Versione" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Copyright © 2011-TODAY OpenERP SA. All Rights Reserved." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP is a trademark of the" +msgstr "OpenERP è un marchio di" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP SA Company" +msgstr "OpenERP SA Company" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Licenced under the terms of" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "GNU Affero General Public License" +msgstr "GNU Affero General Public License" + +#: addons/web/static/src/xml/base.xml:0 +msgid "About OpenERP" +msgstr "Informazioni su OpenERP" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP" +msgstr "OpenERP" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"is a free enterprise-scale software system that is designed to boost\n" +" productivity and profit through data integration. It connects, " +"improves and\n" +" manages business processes in areas such as sales, finance, " +"supply chain,\n" +" project management, production, services, CRM, etc..." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"The system is platform-independent, and can be installed on Windows, Mac OS " +"X,\n" +" and various Linux and other Unix-based distributions. Its " +"architecture enables\n" +" new functionality to be rapidly created, modifications to be " +"made to a\n" +" production system and migration to a new version to be " +"straightforward." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Depending on your needs, OpenERP is available through a web or application " +"client." +msgstr "" +"In base alle tue esigenze, OpenERP è disponibile tramite un browse web o " +"un'applicazione client." diff --git a/addons/web/po/nl_BE.po b/addons/web/po/nl_BE.po new file mode 100644 index 00000000000..2a2dccb1712 --- /dev/null +++ b/addons/web/po/nl_BE.po @@ -0,0 +1,689 @@ +# Dutch (Belgium) translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:38+0200\n" +"PO-Revision-Date: 2011-10-07 12:50+0000\n" +"Last-Translator: Niels Huylebroeck \n" +"Language-Team: Dutch (Belgium) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2011-10-08 05:29+0000\n" +"X-Generator: Launchpad (build 14110)\n" + +#: addons/web/static/src/js/view_form.js:355 +msgid "" +"Warning, the record has been modified, your changes will be discarded." +msgstr "" +"Opgelet, het record werd gewijzigd, uw veranderingen zullen niet opgeslagen " +"worden." + +#: addons/web/static/src/js/view_form.js:1659 +msgid "   Search More..." +msgstr "   Uitgebreid zoeken..." + +#: addons/web/static/src/js/view_form.js:1672 +#, python-format +msgid "   Create \"%s\"" +msgstr "   Creër \"%s\"" + +#: addons/web/static/src/js/view_form.js:1678 +msgid "   Create and Edit..." +msgstr "   Creër en bewerk..." + +#: addons/web/static/src/js/views.js:568 +msgid "You must choose at least one record." +msgstr "U moet minstens een record selecteren." + +#: addons/web/static/src/js/views.js:569 +msgid "Warning" +msgstr "Waarschuwing" + +#: addons/web/static/src/js/views.js:609 +msgid "Translations" +msgstr "Vertalingen" + +#: addons/web/static/src/js/views.js:614 addons/web/static/src/xml/base.xml:0 +msgid "Save" +msgstr "Opslaan" + +#: addons/web/static/src/js/views.js:615 +msgid "Close" +msgstr "Sluiten" + +#: addons/web/static/src/xml/base.xml:0 +msgid "x" +msgstr "x" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#{title}" +msgstr "#{title}" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#{text}" +msgstr "#{text}" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Powered by" +msgstr "Mogelijk gemaakt door" + +#: addons/web/static/src/xml/base.xml:0 +msgid "openerp.com" +msgstr "openerp.com" + +#: addons/web/static/src/xml/base.xml:0 +msgid "." +msgstr "." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Loading..." +msgstr "Laden..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create" +msgstr "Creër" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Drop" +msgstr "Drop" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Backup" +msgstr "Backup" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Restore" +msgstr "Restore" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password" +msgstr "Wachtwoord" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Back to Login" +msgstr "Terug naar aanmelding" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CREATE DATABASE" +msgstr "CREATE DATABASE" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Master password:" +msgstr "Master wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New database name:" +msgstr "Nieuwe database naam:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Load Demonstration data:" +msgstr "Demonstratie data laden:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Default language:" +msgstr "Standaard taal:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Admin password:" +msgstr "Beheerder wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm password:" +msgstr "Bevestig wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "DROP DATABASE" +msgstr "DROP DATABASE" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database:" +msgstr "Database:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Master Password:" +msgstr "Master wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "BACKUP DATABASE" +msgstr "BACKUP DATABASE" + +#: addons/web/static/src/xml/base.xml:0 +msgid "RESTORE DATABASE" +msgstr "RESTORE DATABASE" + +#: addons/web/static/src/xml/base.xml:0 +msgid "File:" +msgstr "Bestand:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CHANGE MASTER PASSWORD" +msgstr "CHANGE MASTER PASSWORD" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New master password:" +msgstr "Nieuw master wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm new master password:" +msgstr "Bevestig nieuw master wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "User:" +msgstr "Gebruiker:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password:" +msgstr "Wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database" +msgstr "Database" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Login" +msgstr "Login" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Bad username or password" +msgstr "Verkeerde gebruikersnaam of wachtwoord" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"We think that daily job activities can be more intuitive, efficient, " +"automated, .. and even fun." +msgstr "" +"Wij geloven dat je dagelijkse werk intuitiver, efficienter, geautomatiseerd " +"en leuker kan zijn." + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP's vision to be:" +msgstr "OpenERP's visie is:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Full featured" +msgstr "Volledig uitgerust" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Today's enterprise challenges are multiple. We provide one module for each " +"need." +msgstr "" +"Hedendaagse uitdaging voor bedrijven zijn alom. Wij voorzien een module voor " +"elke uitdaging." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open Source" +msgstr "Open Source" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"To Build a great product, we rely on the knowledge of thousands of " +"contributors." +msgstr "" +"Om een geweldig product te maken vertrouwen we op de kennis van duizenden " +"mensen." + +#: addons/web/static/src/xml/base.xml:0 +msgid "User Friendly" +msgstr "Gebruiksvriendelijk" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"In order to be productive, people need clean and easy to use interface." +msgstr "" +"Om productief te kunnen zijn hebben mensen een mooie en gemakkelijke " +"interface nodig." + +#: addons/web/static/src/xml/base.xml:0 +msgid "(" +msgstr "(" + +#: addons/web/static/src/xml/base.xml:0 +msgid ")" +msgstr ")" + +#: addons/web/static/src/xml/base.xml:0 +msgid "LOGOUT" +msgstr "LOGOUT" + +#: addons/web/static/src/xml/base.xml:0 +msgid "«" +msgstr "«" + +#: addons/web/static/src/xml/base.xml:0 +msgid "»" +msgstr "»" + +#: addons/web/static/src/xml/base.xml:0 +msgid "oe_secondary_menu_item" +msgstr "oe_secondary_menu_item" + +#: addons/web/static/src/xml/base.xml:0 +msgid "oe_secondary_submenu_item" +msgstr "oe_secondary_submenu_item" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Hide this tip" +msgstr "Verberg deze tip" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Disable all tips" +msgstr "Verberg alle tips" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View#" +msgstr "View#" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields" +msgstr "Velden" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View labels" +msgstr "Toon labels" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Sidebar Relates" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Field" +msgstr "Veld" + +#: addons/web/static/src/xml/base.xml:0 +msgid ":" +msgstr ":" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate view" +msgstr "Vertaal scherm" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate sidebar" +msgstr "Vertaal balk" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delete" +msgstr "Verwijder" + +#: addons/web/static/src/xml/base.xml:0 +msgid "First" +msgstr "Eerste" + +#: addons/web/static/src/xml/base.xml:0 +msgid "<" +msgstr "<" + +#: addons/web/static/src/xml/base.xml:0 +msgid ">" +msgstr ">" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Last" +msgstr "Laatste" + +#: addons/web/static/src/xml/base.xml:0 +msgid "♻" +msgstr "♻" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Edit" +msgstr "Opslaan & Bewerken" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create & Edit" +msgstr "Creër & Bewerk" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New" +msgstr "Nieuw" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Duplicate" +msgstr "Dupliceer" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Readonly/Editable" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "<<" +msgstr "<<" + +#: addons/web/static/src/xml/base.xml:0 +msgid "0" +msgstr "0" + +#: addons/web/static/src/xml/base.xml:0 +msgid "/" +msgstr "/" + +#: addons/web/static/src/xml/base.xml:0 +msgid ">>" +msgstr ">>" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add" +msgstr "Toevoegen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Unhandled widget" +msgstr "Niet-verwerkbare widget" + +#: addons/web/static/src/xml/base.xml:0 +msgid "?" +msgstr "?" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#" +msgstr "#" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Done" +msgstr "Voltooid" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open..." +msgstr "Open..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create..." +msgstr "Creër..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Search..." +msgstr "Zoeken..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "..." +msgstr "..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Uploading ..." +msgstr "Uploaden ..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Select" +msgstr "Selecteer" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save As" +msgstr "Opslaan als" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Clear" +msgstr "Leegmaken" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Advanced Filter" +msgstr "Geavanceerde filter" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Filters --" +msgstr "-- Filters --" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Actions --" +msgstr "-- Acties --" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save Filter" +msgstr "Filter opslaan" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Manage Filters" +msgstr "Filters beheren" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Filter Name:" +msgstr "Filternaam:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "(Any existing filter with the same name will be replaced)" +msgstr "(Bestaande filters met dezelfde naam worden overschreven)" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Any of the following conditions must match" +msgstr "Een van de volgende voorwaarden moet overeenstemmen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "All the following conditions must match" +msgstr "Elke van de volgende voorwaarden moeten overeenstemmen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "None of the following conditions must match" +msgstr "Geen enkele van de volgende voorwaarden moeten overeenstemmen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add condition" +msgstr "Voorwaarde toevoegen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "and" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Cancel" +msgstr "Annuleren" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & New" +msgstr "Opslaan & Nieuwe" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Close" +msgstr "Opslaan & Sluiten" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export" +msgstr "Exporteren" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"This wizard will export all data that matches the current search criteria to " +"a CSV file.\n" +" You can export all data or only the fields that can be " +"reimported after modification." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Type:" +msgstr "Export Type:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Compatible Export" +msgstr "Exporteren op een compatibele manier" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export all Data" +msgstr "Alles exporteren" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Formats" +msgstr "Export formaten" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Available fields" +msgstr "Beschikbare velden" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields to export" +msgstr "Te exporteren velden" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save fields list" +msgstr "Export definitie opslaan" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove" +msgstr "Verwijderen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove All" +msgstr "Alles verwijderen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Name" +msgstr "Naam" + +#: addons/web/static/src/xml/base.xml:0 +msgid " " +msgstr " " + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save as:" +msgstr "Opslaan als:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Ok" +msgstr "Ok" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Saved exports:" +msgstr "Export definities" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Old Password:" +msgstr "Huidig wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New Password:" +msgstr "Nieuw wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm Password:" +msgstr "Bevestig wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import" +msgstr "Importeren" + +#: addons/web/static/src/xml/base.xml:0 +msgid "1. Import a .CSV file" +msgstr "1. Importeer een .CSV bestand" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Select a .CSV file to import. If you need a sample of file to import,\n" +" you should use the export tool with the \"Import Compatible\" option." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CSV File:" +msgstr "CSV Bestand:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "2. Check your file format" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Options" +msgstr "Import opties" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Does your file have titles?" +msgstr "Heeft uw bestand een hoofding ?" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Separator:" +msgstr "Scheidingsteken" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delimiter:" +msgstr "Veld begrenzing" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Encoding:" +msgstr "Encodering:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "UTF-8" +msgstr "UTF-8" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Latin 1" +msgstr "Latin 1" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Lines to skip" +msgstr "Aantal lijnen overslaan" + +#: addons/web/static/src/xml/base.xml:0 +msgid "The import failed due to:" +msgstr "De import is niet gelukt omdat:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Here is a preview of the file we could not import:" +msgstr "Hier is een voorbeeld van het bestand dat we niet konden importeren:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP Web" +msgstr "OpenERP Web" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Version" +msgstr "Versie" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Copyright © 2011-TODAY OpenERP SA. All Rights Reserved." +msgstr "Copyright © 2011-TODAY OpenERP SA. Alle rechten voorbehouden." + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP is a trademark of the" +msgstr "OpenERP is een handelsmerk van" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP SA Company" +msgstr "OpenERP SA Company" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Licenced under the terms of" +msgstr "Gelicensieërd onder de voorwaarden van" + +#: addons/web/static/src/xml/base.xml:0 +msgid "GNU Affero General Public License" +msgstr "GNU Affero General Public License" + +#: addons/web/static/src/xml/base.xml:0 +msgid "About OpenERP" +msgstr "About OpenERP" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP" +msgstr "OpenERP" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"is a free enterprise-scale software system that is designed to boost\n" +" productivity and profit through data integration. It connects, " +"improves and\n" +" manages business processes in areas such as sales, finance, " +"supply chain,\n" +" project management, production, services, CRM, etc..." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"The system is platform-independent, and can be installed on Windows, Mac OS " +"X,\n" +" and various Linux and other Unix-based distributions. Its " +"architecture enables\n" +" new functionality to be rapidly created, modifications to be " +"made to a\n" +" production system and migration to a new version to be " +"straightforward." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Depending on your needs, OpenERP is available through a web or application " +"client." +msgstr "" +"Afhankelijk van uw behoefte is OpenERP beschikbaar via een web- of desktop-" +"applicatie." diff --git a/addons/web/po/web.pot b/addons/web/po/web.pot index 8d302a41fd7..adfa15066fd 100644 --- a/addons/web/po/web.pot +++ b/addons/web/po/web.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2011-09-06 12:02+0200\n" +"POT-Creation-Date: 2011-10-07 10:38+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,28 +17,40 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 0.9.6\n" -#: addons/web/static/src/js/form.js:1473 +#: addons/web/static/src/js/view_form.js:355 +msgid "Warning, the record has been modified, your changes will be discarded." +msgstr "" + +#: addons/web/static/src/js/view_form.js:1659 msgid "   Search More..." msgstr "" -#: addons/web/static/src/js/form.js:1486 +#: addons/web/static/src/js/view_form.js:1672 #, python-format msgid "   Create \"%s\"" msgstr "" -#: addons/web/static/src/js/form.js:1492 +#: addons/web/static/src/js/view_form.js:1678 msgid "   Create and Edit..." msgstr "" -#: addons/web/static/src/js/views.js:484 +#: addons/web/static/src/js/views.js:568 +msgid "You must choose at least one record." +msgstr "" + +#: addons/web/static/src/js/views.js:569 +msgid "Warning" +msgstr "" + +#: addons/web/static/src/js/views.js:609 msgid "Translations" msgstr "" -#: addons/web/static/src/js/views.js:489 addons/web/static/src/xml/base.xml:0 +#: addons/web/static/src/js/views.js:614 addons/web/static/src/xml/base.xml:0 msgid "Save" msgstr "" -#: addons/web/static/src/js/views.js:490 +#: addons/web/static/src/js/views.js:615 msgid "Close" msgstr "" @@ -229,23 +241,31 @@ msgid "LOGOUT" msgstr "" #: addons/web/static/src/xml/base.xml:0 -msgid "h3" +msgid "«" msgstr "" #: addons/web/static/src/xml/base.xml:0 -msgid "<" +msgid "»" msgstr "" #: addons/web/static/src/xml/base.xml:0 -msgid ">" +msgid "oe_secondary_menu_item" msgstr "" #: addons/web/static/src/xml/base.xml:0 -msgid "" +msgstr "" + #: addons/web/static/src/xml/base.xml:0 msgid "Last" msgstr "" @@ -292,10 +320,6 @@ msgstr "" msgid "♻" msgstr "" -#: addons/web/static/src/xml/base.xml:0 -msgid "View#" -msgstr "" - #: addons/web/static/src/xml/base.xml:0 msgid "Save & Edit" msgstr "" @@ -308,6 +332,14 @@ msgstr "" msgid "New" msgstr "" +#: addons/web/static/src/xml/base.xml:0 +msgid "Duplicate" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Readonly/Editable" +msgstr "" + #: addons/web/static/src/xml/base.xml:0 msgid "<<" msgstr "" @@ -336,6 +368,14 @@ msgstr "" msgid "?" msgstr "" +#: addons/web/static/src/xml/base.xml:0 +msgid "#" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Done" +msgstr "" + #: addons/web/static/src/xml/base.xml:0 msgid "Open..." msgstr "" @@ -508,6 +548,69 @@ msgstr "" msgid "Confirm Password:" msgstr "" +#: addons/web/static/src/xml/base.xml:0 +msgid "Import" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "1. Import a .CSV file" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Select a .CSV file to import. If you need a sample of file to import,\n" +" you should use the export tool with the \"Import Compatible\" " +"option." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CSV File:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "2. Check your file format" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Options" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Does your file have titles?" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Separator:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delimiter:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Encoding:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "UTF-8" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Latin 1" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Lines to skip" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "The import failed due to:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Here is a preview of the file we could not import:" +msgstr "" + #: addons/web/static/src/xml/base.xml:0 msgid "OpenERP Web" msgstr "" diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 7f5b7f5f41b..0e2a4e94e01 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -855,7 +855,7 @@ label.error { cursor: help; } -.openerp .oe_form_field label.oe_label, .openerp .oe_form_field label.oe_label_help { +.openerp .oe_forms label.oe_label, .openerp .oe_forms label.oe_label_help { text-align: right; margin: 3px 0 0 10px; } @@ -943,7 +943,7 @@ label.error { position: relative; } .openerp input.oe-binary-file { - z-index: 2; + z-index: 0; line-height: 0; font-size: 50px; position: absolute; diff --git a/addons/web/static/src/js/formats.js b/addons/web/static/src/js/formats.js index e7feedf26a5..d3d88bc3731 100644 --- a/addons/web/static/src/js/formats.js +++ b/addons/web/static/src/js/formats.js @@ -179,9 +179,13 @@ openerp.web.auto_date_to_str = function(value, type) { * @param {String} [column.string] button label * @param {String} [column.icon] button icon * @param {String} [value_if_empty=''] what to display if the field's value is ``false`` + * @param {Boolean} [process_modifiers=true] should the modifiers be computed ? */ -openerp.web.format_cell = function (row_data, column, value_if_empty) { - var attrs = column.modifiers_for(row_data); +openerp.web.format_cell = function (row_data, column, value_if_empty, process_modifiers) { + var attrs = {}; + if (process_modifiers !== false) { + attrs = column.modifiers_for(row_data); + } if (attrs.invisible) { return ''; } if (column.tag === 'button') { return [ diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index cf253c3d54b..9cab0ade9d0 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -116,8 +116,9 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search */ make_field: function (item, field) { try { - return new (openerp.web.search.fields.get_object(field.type)) - (item, field, this); + return new (openerp.web.search.fields.get_any( + [item.attrs.widget, field.type])) + (item, field, this); } catch (e) { if (! e instanceof openerp.web.KeyNotFound) { throw e; @@ -338,7 +339,7 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search this.notification.notify("Invalid Search", "triggered from search view"); }, do_clear: function () { - this.$element.find('.filter_label').removeClass('enabled'); + this.$element.find('.filter_label, .filter_icon').removeClass('enabled'); this.enabled_filters.splice(0); var string = $('a.searchview_group_string'); _.each(string, function(str){ @@ -759,9 +760,44 @@ openerp.web.search.FloatField = openerp.web.search.NumberField.extend(/** @lends * @extends openerp.web.search.Field */ openerp.web.search.SelectionField = openerp.web.search.Field.extend(/** @lends openerp.web.search.SelectionField# */{ + // This implementation is a basic @@ -784,7 +784,7 @@
@@ -823,7 +823,7 @@ @@ -842,8 +842,8 @@ -
- +
+ @@ -895,8 +896,8 @@ + t-att-id="widget.element_id" + t-attf-class="field_#{widget.type}"/>
@@ -911,7 +912,7 @@ t-att-border="widget.readonly ? 0 : 1" t-att-id="widget.element_id + '_field'" t-att-name="widget.name" - t-attf-class="field_#{widget.type} #{widget.element_class}" + t-attf-class="field_#{widget.type}" t-att-width="widget.node.attrs.img_width || widget.node.attrs.width" t-att-height="widget.node.attrs.img_height || widget.node.attrs.height" /> @@ -959,7 +960,7 @@ @@ -1004,7 +1005,6 @@