From 7d06e2977c953496e3a123fb6e91bbfbab0b0323 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 10 Sep 2012 17:29:41 -0500 Subject: [PATCH 01/80] stream allows for optional headers and fixed a formtyle bug, thanks Anthony --- VERSION | 2 +- gluon/globals.py | 5 +++-- gluon/sqlhtml.py | 15 ++++++++------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/VERSION b/VERSION index a2c32e82..153c3046 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-10 11:34:33) stable +Version 2.0.8 (2012-09-10 17:29:35) stable diff --git a/gluon/globals.py b/gluon/globals.py index 5e94b726..dab102f2 100644 --- a/gluon/globals.py +++ b/gluon/globals.py @@ -278,7 +278,8 @@ class Response(Storage): chunk_size = DEFAULT_CHUNK_SIZE, request=None, attachment=False, - filename=None + filename=None, + headers=None ): """ if a controller function:: @@ -298,7 +299,7 @@ class Response(Storage): default to the last request argument otherwise) """ - headers = self.headers + headers = headers if headers is not None else self.headers # for attachment settings and backward compatibility keys = [item.lower() for item in headers] if attachment: diff --git a/gluon/sqlhtml.py b/gluon/sqlhtml.py index 88c1f5bf..4a7857df 100644 --- a/gluon/sqlhtml.py +++ b/gluon/sqlhtml.py @@ -1105,20 +1105,21 @@ class SQLFORM(FORM): self.components = [table] def createform(self, xfields): - if isinstance(self.formstyle, basestring): - if self.formstyle in SQLFORM.formstyles: - self.formstyle = SQLFORM.formstyles[self.formstyle] + formstyle = self.formstyle + if isinstance(formstyle, basestring): + if formstyle in SQLFORM.formstyles: + formstyle = SQLFORM.formstyles[formstyle] else: raise RuntimeError, 'formstyle not found' - if callable(self.formstyle): + if callable(formstyle): # backward compatibility, 4 argument function is the old style - args, varargs, keywords, defaults = inspect.getargspec(self.formstyle) + args, varargs, keywords, defaults = inspect.getargspec(formstyle) if defaults and len(args) - len(defaults) == 4 or len(args) == 4: table = TABLE() for id,a,b,c in xfields: raw_b = self.field_parent[id] = b - newrows = self.formstyle(id,a,raw_b,c) + newrows = formstyle(id,a,raw_b,c) if type(newrows).__name__ != "tuple": newrows = [newrows] for newrow in newrows: @@ -1126,7 +1127,7 @@ class SQLFORM(FORM): else: for id,a,b,c in xfields: self.field_parent[id] = b - table = self.formstyle(self, xfields) + table = formstyle(self, xfields) else: raise RuntimeError, 'formstyle not supported' return table From 642ae77f73687e8c74c23e72efd153a7585554f8 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 10 Sep 2012 18:26:46 -0500 Subject: [PATCH 02/80] smarter select although join/left ignore common fields --- VERSION | 2 +- gluon/dal.py | 38 +++++++++++++++++++++++--------------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/VERSION b/VERSION index 153c3046..134acbba 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-10 17:29:35) stable +Version 2.0.8 (2012-09-10 18:26:41) stable diff --git a/gluon/dal.py b/gluon/dal.py index 20e8eb8c..4c3192ff 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -185,6 +185,7 @@ SELECT_ARGS = set( ('orderby', 'groupby', 'limitby','required', 'cache', 'left', 'distinct', 'having', 'join','for_update', 'processor','cacheable')) + ogetattr = object.__getattribute__ osetattr = object.__setattr__ exists = os.path.exists @@ -1613,15 +1614,16 @@ class BaseAdapter(ConnectionPool): self.execute(self._count(query, distinct)) return self.cursor.fetchone()[0] - def tables(self, query): + def tables(self, *queries): tables = set() - if isinstance(query, Field): - tables.add(query.tablename) - elif isinstance(query, (Expression, Query)): - if not query.first is None: - tables = tables.union(self.tables(query.first)) - if not query.second is None: - tables = tables.union(self.tables(query.second)) + for query in queries: + if isinstance(query, Field): + tables.add(query.tablename) + elif isinstance(query, (Expression, Query)): + if not query.first is None: + tables = tables.union(self.tables(query.first)) + if not query.second is None: + tables = tables.union(self.tables(query.second)) return list(tables) def commit(self): @@ -4678,9 +4680,7 @@ class CouchDBAdapter(NoSQLAdapter): def _select(self,query,fields,attributes): if not isinstance(query,Query): raise SyntaxError, "Not Supported" - for key in set(attributes.keys())-set(('orderby','groupby','limitby', - 'required','cache','left', - 'distinct', 'having', 'processor')): + for key in set(attributes.keys())-SELECT_ARGS: raise SyntaxError, 'invalid select attribute: %s' % key new_fields=[] for item in fields: @@ -8717,7 +8717,12 @@ class Set(object): def _select(self, *fields, **attributes): adapter = self.db._adapter - fields = adapter.expand_all(fields, adapter.tables(self.query)) + tablenames = adapter.tables(self.query, + attributes.get('join',None), + attributes.get('left',None), + attributes.get('orderby',None), + attributes.get('groupby',None)) + fields = adapter.expand_all(fields, tablenames) return adapter._select(self.query,fields,attributes) def _delete(self): @@ -8749,10 +8754,13 @@ class Set(object): return db._adapter.count(self.query,distinct) def select(self, *fields, **attributes): - if self.query is None:# and fields[0]._table._common_filter != None: - return self(fields[0]._table).select(*fields,**attributes) adapter = self.db._adapter - fields = adapter.expand_all(fields, adapter.tables(self.query)) + tablenames = adapter.tables(self.query, + attributes.get('join',None), + attributes.get('left',None), + attributes.get('orderby',None), + attributes.get('groupby',None)) + fields = adapter.expand_all(fields, tablenames) return adapter.select(self.query,fields,attributes) def nested_select(self,*fields,**attributes): From a5807be01e84b63c5cb6c66162d054e88b6f370d Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 11 Sep 2012 08:24:59 -0500 Subject: [PATCH 03/80] fixed bug in cache minify, thanks Jeremy --- VERSION | 2 +- gluon/globals.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/VERSION b/VERSION index 134acbba..4bd8a558 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-10 18:26:41) stable +Version 2.0.8 (2012-09-11 08:24:53) stable diff --git a/gluon/globals.py b/gluon/globals.py index dab102f2..56a3d437 100644 --- a/gluon/globals.py +++ b/gluon/globals.py @@ -230,7 +230,6 @@ class Response(Storage): def include_files(self): - """ Caching method for writing out files. By default, caches in ram for 5 minutes. To change, @@ -244,8 +243,9 @@ class Response(Storage): if not item in files: files.append(item) if have_minify and (self.optimize_css or self.optimize_js): # cache for 5 minutes by default + key = hashlib.md5(repr(files)).hexdigest() cache = self.cache_includes or (current.cache.ram, 60*5) - def call_minify(): + def call_minify(files=files): return minify.minify(files, URL('static','temp'), current.request.folder, @@ -253,7 +253,7 @@ class Response(Storage): self.optimize_js) if cache: cache_model, time_expire = cache - files = cache_model('response.files.minified', + files = cache_model('response.files.minified/'+key, call_minify, time_expire) else: From bf42dfbb5c4722e5babb034100fd1aa7a96b4b3d Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 11 Sep 2012 08:35:58 -0500 Subject: [PATCH 04/80] markmin improvement thanks Villas and Vladyslav --- VERSION | 2 +- gluon/contrib/markmin/markmin2html.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/VERSION b/VERSION index 4bd8a558..6e68dbc3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-11 08:24:53) stable +Version 2.0.8 (2012-09-11 08:35:54) stable diff --git a/gluon/contrib/markmin/markmin2html.py b/gluon/contrib/markmin/markmin2html.py index 1820c620..78b29748 100755 --- a/gluon/contrib/markmin/markmin2html.py +++ b/gluon/contrib/markmin/markmin2html.py @@ -540,7 +540,7 @@ regex_strong=re.compile(r'\*\*(?P[^\s*]+( +[^\s*]+)*)\*\*') regex_del=re.compile(r'~~(?P[^\s*]+( +[^\s*]+)*)~~') regex_em=re.compile(r"''(?P[^\s']+(?: +[^\s']+)*)''") regex_num=re.compile(r"^\s*[+-]?((\d+(\.\d*)?)|\.\d+)([eE][+-]?[0-9]+)?\s*$") -regex_list=re.compile('^(?:(?:(#{1,6})|(?:(\.+|\++|\-+)(\.)?))\s+)?(.*)$') +regex_list=re.compile('^(?:(?:(#{1,6})|(?:(\.+|\++|\-+)(\.)?))\s*)?(.*)$') regex_bq_headline=re.compile('^(?:(\.+|\++|\-+)(\.)?\s+)?(-{3}-*)$') regex_tq=re.compile('^(-{3}-*)(?::(?P[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P

[a-zA-Z][_a-zA-Z\-\d]*)\])?)?$') regex_proto = re.compile(r'(?/=])(?P

\w+):(?P\w+://[\w\d\-+=?%&/:.]+)', re.M) @@ -1165,17 +1165,17 @@ def render(text, (lev, mtag, lineno)= parse_list(t2, p, ss, 'ol', lev, mtag, lineno) lineno+=1 continue - elif c0 == '-': # unordered list - (lev, mtag, lineno) = parse_list(t2, p, ss, 'ul', lev, mtag, lineno) - lineno+=1 - continue + elif c0 == '-': # unordered list, table or blockquote + if p or ss: + (lev, mtag, lineno) = parse_list(t2, p, ss, 'ul', lev, mtag, lineno) + lineno+=1 + continue + else: + (s, mtag, lineno) = parse_table_or_blockquote(s, mtag, lineno) elif lev>0: # and c0 == '.' # paragraph in lists (lev, mtag, lineno) = parse_point(t2, ss, lev, mtag, lineno) lineno+=1 continue - else: - if c0 == '-': # table or blockquote? - (s, mtag, lineno) = parse_table_or_blockquote(s, mtag, lineno) if lev == 0 and (mtag == 'q' or s == META): # new paragraph From 821184b45a1b9983a6b7b1d55acbd27c13c5aa5d Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 11 Sep 2012 09:25:13 -0500 Subject: [PATCH 05/80] fixed a problem with dal and uploadfields not been created --- VERSION | 2 +- gluon/dal.py | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/VERSION b/VERSION index 6e68dbc3..fbc2a46b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-11 08:35:54) stable +Version 2.0.8 (2012-09-11 09:25:06) stable diff --git a/gluon/dal.py b/gluon/dal.py index 4c3192ff..eea0f9a6 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -7472,13 +7472,14 @@ class Table(object): fields = list(fields) if db and db._adapter.uploads_in_blob==True: + uploadfields = [f.name for f in fields if f.type=='blob'] for field in fields: + fn = field.uploadfield if isinstance(field, Field) and field.type == 'upload'\ - and field.uploadfield is True: - tmp = field.uploadfield = '%s_blob' % field.name - if isinstance(field.uploadfield,str) and \ - not [f for f in fields if f.name==field.uploadfield]: - fields.append(Field(field.uploadfield,'blob',default='')) + and fn is True: + fn = field.uploadfield = '%s_blob' % field.name + if isinstance(fn,str) and not fn in uploadfields: + fields.append(Field(fn,'blob',default='')) lower_fieldnames = set() reserved = dir(Table) + ['fields'] From 2d669d13769415e1f77febf9cfcd79dd0aa7df86 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 11 Sep 2012 09:27:00 -0500 Subject: [PATCH 06/80] fixed a problem with dal and uploadfields not been created, blob fields should hidden --- VERSION | 2 +- gluon/dal.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index fbc2a46b..db3cc7ff 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-11 09:25:06) stable +Version 2.0.8 (2012-09-11 09:26:57) stable diff --git a/gluon/dal.py b/gluon/dal.py index eea0f9a6..89cae33f 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -7479,7 +7479,8 @@ class Table(object): and fn is True: fn = field.uploadfield = '%s_blob' % field.name if isinstance(fn,str) and not fn in uploadfields: - fields.append(Field(fn,'blob',default='')) + fields.append(Field(fn,'blob',default='', + writable=False,readable=False)) lower_fieldnames = set() reserved = dir(Table) + ['fields'] From f8fab83761a9052240f5f49199cb93e175736a93 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 11 Sep 2012 09:39:13 -0500 Subject: [PATCH 07/80] fixed issue 993, thanks Sherdim --- VERSION | 2 +- gluon/sqlhtml.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index db3cc7ff..814b7e64 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-11 09:26:57) stable +Version 2.0.8 (2012-09-11 09:39:06) stable diff --git a/gluon/sqlhtml.py b/gluon/sqlhtml.py index 4a7857df..94a1f887 100644 --- a/gluon/sqlhtml.py +++ b/gluon/sqlhtml.py @@ -1410,7 +1410,7 @@ class SQLFORM(FORM): type(''): ('string', None), type(True): ('boolean', None), type(1): ('integer', IS_INT_IN_RANGE(-1e12,+1e12)), - type(1.0): ('double', IS_INT_IN_RANGE(-1e12,+1e12)), + type(1.0): ('double', IS_FLOAT_IN_RANGE()), type([]): ('list:string', None), type(datetime.date.today()): ('date', IS_DATE()), type(datetime.datetime.today()): ('datetime', IS_DATETIME()) From e5652e36d5b334246a9ca6e5d16674ea90630898 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 11 Sep 2012 09:53:08 -0500 Subject: [PATCH 08/80] fixed issue 996 --- VERSION | 2 +- applications/admin/controllers/default.py | 6 +++--- gluon/sqlhtml.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index 814b7e64..da4d038a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-11 09:39:06) stable +Version 2.0.8 (2012-09-11 09:53:02) stable diff --git a/applications/admin/controllers/default.py b/applications/admin/controllers/default.py index 9b1dbedb..aaf642cf 100644 --- a/applications/admin/controllers/default.py +++ b/applications/admin/controllers/default.py @@ -15,10 +15,10 @@ from gluon.utils import web2py_uuid from glob import glob import shutil import platform -try: - from git import * +try: + from git import * have_git = True -except ImportError: +except ImportError: have_git = False GIT_MISSING = 'requires python-git module, but not installed or incompatible version' diff --git a/gluon/sqlhtml.py b/gluon/sqlhtml.py index 94a1f887..d5a638d7 100644 --- a/gluon/sqlhtml.py +++ b/gluon/sqlhtml.py @@ -2416,7 +2416,7 @@ class SQLTABLE(TABLE): _class = 'odd' if not selectid is None: #new implement - if record[self.id_field_name]==selectid: + if record.get('id') == selectid: _class += ' rowselected' for colname in columns: From 7ae1147df8d28e514b1cb21e985242756dd34f6f Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 11 Sep 2012 09:55:58 -0500 Subject: [PATCH 09/80] better handling of cross-domain urls in parametric router, thanks Jonathan --- VERSION | 2 +- gluon/rewrite.py | 6 ++- gluon/tests/test_router.py | 99 +++++++++++++++++++++++++++++++++++++- 3 files changed, 104 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index da4d038a..654965d0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-11 09:53:02) stable +Version 2.0.8 (2012-09-11 09:55:54) stable diff --git a/gluon/rewrite.py b/gluon/rewrite.py index da876cd7..da9f28f0 100644 --- a/gluon/rewrite.py +++ b/gluon/rewrite.py @@ -895,7 +895,11 @@ class MapUrlIn(object): self.domain_controller = None self.domain_function = None arg0 = self.harg0 - if (self.host, self.port) in base.domains: + if not base.exclusive_domain and base.applications and arg0 in base.applications: + self.application = arg0 + elif not base.exclusive_domain and arg0 and not base.applications: + self.application = arg0 + elif (self.host, self.port) in base.domains: (self.application, self.domain_controller, self.domain_function) = base.domains[(self.host, self.port)] self.env['domain_application'] = self.application self.env['domain_controller'] = self.domain_controller diff --git a/gluon/tests/test_router.py b/gluon/tests/test_router.py index f554f420..3cd75db3 100644 --- a/gluon/tests/test_router.py +++ b/gluon/tests/test_router.py @@ -346,8 +346,13 @@ class TestRouter(unittest.TestCase): self.assertEqual(filter_url('http://domain1.com/abc', app=True), 'app1') self.assertEqual(filter_url('http://www.domain1.com/abc', app=True), 'app1') self.assertEqual(filter_url('http://domain2.com/abc', app=True), 'app2') + self.assertEqual(filter_url('http://domain2.com/admin', app=True), 'admin') + + routers['BASE']['exclusive_domain'] = True + load(rdict=routers) self.assertEqual(filter_url('http://domain2.com/admin', app=True), 'app2') + self.assertEqual(filter_url('http://domain.com/goodapp', app=True), 'goodapp') self.assertRaises(HTTP, filter_url, 'http://domain.com/bad!app', app=True) try: @@ -428,7 +433,7 @@ class TestRouter(unittest.TestCase): self.assertEqual(filter_url('http://domain1.com/abc.html'), '/app1/c1/abc') self.assertEqual(filter_url('http://domain1.com/abc.css'), '/app1/c1/abc.css') self.assertEqual(filter_url('http://domain1.com/index/abc'), "/app1/c1/index ['abc']") - self.assertEqual(filter_url('http://domain2.com/app1'), "/app2a/c2a/app1") + self.assertEqual(filter_url('http://domain2.com/app1'), "/app1/c1/f1") self.assertEqual(filter_url('https://domain1.com/app1/ctr/fcn', domain=('app1',None), out=True), "/ctr/fcn") self.assertEqual(filter_url('https://www.domain1.com/app1/ctr/fcn', domain=('app1',None), out=True), "/ctr/fcn") @@ -475,6 +480,98 @@ class TestRouter(unittest.TestCase): pass self.assertEqual(filter_url('http://domain1.com/app1/c1/f1', domain=('app2b',None), host='domain2.com', out=True), "/app1") + + def test_router_domains_ed(self): + ''' + Test URLs that map domains with exclusive_domain set + ''' + routers = dict( + BASE = dict( + applications = ['app1', 'app2', 'app2A', 'app3', 'app4', 'app5', 'app6'], + exclusive_domain = True, + domains = { + # two domains to the same app + "domain1.com" : "app1", + "www.domain1.com" : "app1", + # same domain, two ports, to two apps + "domain2.com" : "app2a", + "domain2.com:8080" : "app2b", + # two domains, same app, two controllers + "domain3a.com" : "app3/c3a", + "domain3b.com" : "app3/c3b", + # two domains, same app & controller, two functions + "domain4a.com" : "app4/c4/f4a", + "domain4b.com" : "app4/c4/f4b", + # http vs https + "domain6.com:80" : "app6", + "domain6.com:443" : "app6s", + }, + ), + app1 = dict( default_controller = 'c1', default_function = 'f1', controllers = ['c1'], exclusive_domain=True, ), + app2a = dict( default_controller = 'c2a', default_function = 'f2a', controllers = ['c2a'], ), + app2b = dict( default_controller = 'c2b', default_function = 'f2b', controllers = ['c2b'], ), + app3 = dict( controllers = ['c3a', 'c3b'], ), + app4 = dict( default_controller = 'c4', controllers = ['c4']), + app5 = dict( default_controller = 'c5', controllers = ['c5'], domain = 'localhost' ), + app6 = dict( default_controller = 'c6', default_function = 'f6', controllers = ['c6'], ), + app6s = dict( default_controller = 'c6s', default_function = 'f6s', controllers = ['c6s'], ), + ) + + load(rdict=routers) + self.assertEqual(filter_url('http://domain1.com/abc'), '/app1/c1/abc') + self.assertEqual(filter_url('http://domain1.com/c1/abc'), '/app1/c1/abc') + self.assertEqual(filter_url('http://domain1.com/abc.html'), '/app1/c1/abc') + self.assertEqual(filter_url('http://domain1.com/abc.css'), '/app1/c1/abc.css') + self.assertEqual(filter_url('http://domain1.com/index/abc'), "/app1/c1/index ['abc']") + self.assertEqual(filter_url('http://domain2.com/app1'), "/app2a/c2a/app1") + + self.assertEqual(filter_url('https://domain1.com/app1/ctr/fcn', domain=('app1',None), out=True), "/ctr/fcn") + self.assertEqual(filter_url('https://www.domain1.com/app1/ctr/fcn', domain=('app1',None), out=True), "/ctr/fcn") + + self.assertEqual(filter_url('http://domain2.com/abc'), '/app2a/c2a/abc') + self.assertEqual(filter_url('http://domain2.com:8080/abc'), '/app2b/c2b/abc') + + self.assertEqual(filter_url('http://domain2.com/app2a/ctr/fcn', domain=('app2a',None), out=True), "/ctr/fcn") + self.assertEqual(filter_url('http://domain2.com/app2a/ctr/f2a', domain=('app2a',None), out=True), "/ctr") + self.assertEqual(filter_url('http://domain2.com/app2a/c2a/f2a', domain=('app2a',None), out=True), "/") + self.assertEqual(filter_url('http://domain2.com/app2a/c2a/fcn', domain=('app2a',None), out=True), "/fcn") + + self.assertRaises(SyntaxError, filter_url, 'http://domain2.com/app2a/ctr/fcn', domain=('app2b',None), out=True) + self.assertRaises(SyntaxError, filter_url, 'http://domain2.com/app2a/ctr/f2a', domain=('app2b',None), out=True) + self.assertRaises(SyntaxError, filter_url, 'http://domain2.com/app2a/c2a/f2a', domain=('app2b',None), out=True) + + self.assertEqual(filter_url('http://domain3a.com/'), '/app3/c3a/index') + self.assertEqual(filter_url('http://domain3a.com/abc'), '/app3/c3a/abc') + self.assertEqual(filter_url('http://domain3a.com/c3b'), '/app3/c3b/index') + self.assertEqual(filter_url('http://domain3b.com/abc'), '/app3/c3b/abc') + + self.assertEqual(filter_url('http://domain3a.com/app3/c3a/fcn', domain=('app3','c3a'), out=True), "/fcn") + self.assertEqual(filter_url('http://domain3a.com/app3/c3a/fcn', domain=('app3','c3b'), out=True), "/c3a/fcn") + + self.assertRaises(SyntaxError, filter_url, 'http://domain3a.com/app3/c3a/fcn', domain=('app1',None), out=True) + + self.assertEqual(filter_url('http://domain4a.com/abc'), '/app4/c4/abc') + self.assertEqual(filter_url('https://domain4a.com/app4/c4/fcn', domain=('app4',None), out=True), "/fcn") + + self.assertEqual(filter_url('http://domain4a.com'), '/app4/c4/f4a') + self.assertEqual(filter_url('http://domain4b.com'), '/app4/c4/f4b') + + self.assertEqual(filter_url('http://localhost/abc'), '/app5/c5/abc') + self.assertEqual(filter_url('http:///abc'), '/app5/c5/abc') # test null host => localhost + self.assertEqual(filter_url('https://localhost/app5/c5/fcn', domain=('app5',None), out=True), "/fcn") + + self.assertEqual(filter_url('http://domain6.com'), '/app6/c6/f6') + self.assertEqual(filter_url('https://domain6.com'), '/app6s/c6s/f6s') + + self.assertRaises(SyntaxError, filter_url, 'http://domain2.com/app3/c3a/f3', domain=('app2b',None), out=True) + self.assertRaises(SyntaxError, filter_url, 'http://domain1.com/app1/c1/f1', domain=('app2b',None), out=True) + try: + # 2.7+ only + self.assertRaisesRegexp(SyntaxError, 'cross-domain conflict', filter_url, 'http://domain1.com/app1/c1/f1', domain=('app2b',None), out=True) + except AttributeError: + pass + self.assertEqual(filter_url('http://domain1.com/app1/c1/f1', domain=('app2b',None), host='domain2.com', out=True), "/app1") + def test_router_raise(self): ''' Test URLs that raise exceptions From 95a4f8e4d5e8c205bd751b7cc1f42ba40e51cdf5 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 11 Sep 2012 10:25:56 -0500 Subject: [PATCH 10/80] auth.wiki(restrict_search=True) authors can only search their own pages --- VERSION | 2 +- gluon/tools.py | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/VERSION b/VERSION index 654965d0..702419be 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-11 09:55:54) stable +Version 2.0.8 (2012-09-11 10:25:49) stable diff --git a/gluon/tools.py b/gluon/tools.py index 29edb6d2..bf4503e7 100644 --- a/gluon/tools.py +++ b/gluon/tools.py @@ -3157,12 +3157,15 @@ class Auth(object): env=None, render=None, manage_permissions=False, - force_prefix='', + force_prefix='', + restrict_search=False, resolve=True): if not hasattr(self,'_wiki'): self._wiki = Wiki(self,render=render, manage_permissions=manage_permissions, - force_prefix=force_prefix,env=env) + force_prefix=force_prefix, + restrict_search=restrict_search, + env=env) else: self._wiki.env.update(env or {}) # if resolve is set to True, process request as wiki call @@ -4506,7 +4509,8 @@ class Wiki(object): controller, function, args = items[0], items[1], items[2:] return LOAD(controller, function, args=args, ajax=True).xml() def __init__(self,auth,env=None,render='markmin', - manage_permissions=False,force_prefix=''): + manage_permissions=False,force_prefix='', + restrict_search=False): self.env = env or {} self.env['component'] = Wiki.component if render == 'markmin': render=self.markmin_render @@ -4518,6 +4522,7 @@ class Wiki(object): self.force_prefix = force_prefix self.host = current.request.env.http_host perms = self.manage_permissions = manage_permissions + self.restrict_search = restrict_search db = auth.db table_definitions = { 'wiki_page':{ @@ -4826,9 +4831,8 @@ class Wiki(object): URL(controller,function,args=('_pages')))) submenu.append((current.T('Edit Menu'),None, URL(controller,function,args=('_edit','wiki-menu')))) - # if self.can_search(): - submenu.append((current.T('Search Pages'),None, - URL(controller,function,args=('_search')))) + submenu.append((current.T('Search Pages'),None, + URL(controller,function,args=('_search')))) return menu def search(self,tags=None,query=None,cloud=True,preview=True, @@ -4857,6 +4861,8 @@ class Wiki(object): query = (db.wiki_page.id==db.wiki_tag.wiki_page)&\ (db.wiki_tag.name.belongs(tags)) query = query|db.wiki_page.title.startswith(request.vars.q) + if self.restrict_search and not self.manage(): + query = query&(db.wiki_page.created_by==self.auth.user_id) pages = db(query).select( *fields,**dict(orderby=orderby or ~count, groupby=db.wiki_page.id, From 2fb6138ed25cf3392e5cfd9b59f5733bd739318b Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 11 Sep 2012 10:28:31 -0500 Subject: [PATCH 11/80] menu has empty components --- VERSION | 2 +- gluon/html.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 702419be..1091597f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-11 10:25:49) stable +Version 2.0.8 (2012-09-11 10:28:27) stable diff --git a/gluon/html.py b/gluon/html.py index 2d6b8131..b267d951 100644 --- a/gluon/html.py +++ b/gluon/html.py @@ -2227,6 +2227,7 @@ class MENU(DIV): def __init__(self, data, **args): self.data = data self.attributes = args + self.components = [] if not '_class' in self.attributes: self['_class'] = 'web2py-menu web2py-menu-vertical' if not 'ul_class' in self.attributes: From 9466389cd6e1b775bce39a2b179ff8003158ae66 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 11 Sep 2012 12:53:44 -0500 Subject: [PATCH 12/80] possible fix for default response haders --- VERSION | 2 +- gluon/main.py | 57 ++++++++++++++++++++++++++------------------------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/VERSION b/VERSION index 1091597f..8a099e85 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-11 10:28:27) stable +Version 2.0.8 (2012-09-11 12:53:40) stable diff --git a/gluon/main.py b/gluon/main.py index 0d77c8e8..c0ef850e 100644 --- a/gluon/main.py +++ b/gluon/main.py @@ -488,19 +488,6 @@ def wsgibase(environ, responder): if not env.web2py_disable_session: session.connect(request, response) - # ################################################## - # set no-cache headers - # ################################################## - - headers = response.headers - headers['Content-Type'] = \ - contenttype('.'+request.extension) - headers['Cache-Control'] = \ - 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0' - headers['Expires'] = \ - time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime()) - headers['Pragma'] = 'no-cache' - # ################################################## # run controller # ################################################## @@ -513,10 +500,10 @@ def wsgibase(environ, responder): serve_controller(request, response, session) except HTTP, http_response: + if static_file: return http_response.to(responder,env=env) - if request.body: request.body.close() @@ -545,28 +532,42 @@ def wsgibase(environ, responder): session._try_store_on_disk(request, response) + # ################################################## + # set default headers it not set + # ################################################## + + rheaders = http_response.headers + + default_headers = [ + ('Content-Type', contenttype('.'+request.extension)), + ('Cache-Control','no-store, no-cache, must-revalidate, post-check=0, pre-check=0'), + ('Expires', time.strftime('%a, %d %b %Y %H:%M:%S GMT', + time.gmtime())), + ('Pragma', 'no-cache')] + + if request.cid: + if response.flash: + default_headers.append( + ('web2py-component-flash', + urllib2.quote(xmlescape(response.flash).replace('\n','')))) + if response.js: + default_headers.append( + ('web2py-component-command', + response.js.replace('\n',''))) + + for key,value in default_headers: + if not key in rheaders: + rheaders[key] = value + # ################################################## # store cookies in headers # ################################################## - if request.cid: - rheaders = http_response.headers - if response.flash and \ - not 'web2py-component-flash' in rheaders: - rheaders['web2py-component-flash'] = \ - urllib2.quote(xmlescape(response.flash)\ - .replace('\n','')) - if response.js and \ - not 'web2py-component-command' in rheaders: - rheaders['web2py-component-command'] = \ - response.js.replace('\n','') rcookies = response.cookies - if session._forget and \ - response.session_id_name in response.cookies: + if session._forget and response.session_id_name in rcookies: del rcookies[response.session_id_name] elif session._secure: rcookies[response.session_id_name]['secure'] = True - http_response.cookies2headers(rcookies) ticket=None From 130a843605bce6b700c8076ee89bebab7c1a221c Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 11 Sep 2012 12:59:45 -0500 Subject: [PATCH 13/80] allow removal of headers with response.headers[key]=None --- VERSION | 2 +- gluon/http.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 8a099e85..5a418e63 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-11 12:53:40) stable +Version 2.0.8 (2012-09-11 12:59:42) stable diff --git a/gluon/http.py b/gluon/http.py index 05330a22..9cae6ac7 100644 --- a/gluon/http.py +++ b/gluon/http.py @@ -103,7 +103,7 @@ class HTTP(BaseException): for k, v in headers.iteritems(): if isinstance(v, list): rheaders += [(k, str(item)) for item in v] - else: + elif not v is None: rheaders.append((k, str(v))) responder(status, rheaders) if env.get('request_method','')=='HEAD': From cc3a8fc3a20ae9b5a80130e91989e49dcbe42cdb Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 11 Sep 2012 13:37:16 -0500 Subject: [PATCH 14/80] better languages.py, thanks Vladyslav --- VERSION | 2 +- applications/admin/controllers/default.py | 38 +- applications/admin/languages/uk.py | 3 + applications/admin/views/default/design.html | 29 +- applications/welcome/languages/cs.py | 134 +++-- applications/welcome/languages/es.py | 312 ++++++----- applications/welcome/languages/fr-ca.py | 111 ++-- applications/welcome/languages/fr.py | 25 +- applications/welcome/languages/hi.py | 148 +++-- applications/welcome/languages/hu.py | 170 ++++-- applications/welcome/languages/it.py | 8 + applications/welcome/languages/nl.py | 6 +- applications/welcome/languages/pl.py | 186 ++++--- applications/welcome/languages/pt-br.py | 98 ++-- applications/welcome/languages/pt.py | 175 ++++-- applications/welcome/languages/ro.py | 18 +- applications/welcome/languages/ru.py | 24 +- applications/welcome/languages/sk.py | 127 +++-- applications/welcome/languages/uk.py | 10 +- applications/welcome/languages/zh.py | 153 ++++-- gluon/cfs.py | 4 +- gluon/languages.py | 541 ++++++++++--------- 22 files changed, 1474 insertions(+), 848 deletions(-) diff --git a/VERSION b/VERSION index 5a418e63..c6d062b9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-11 12:59:42) stable +Version 2.0.8 (2012-09-11 13:37:13) stable diff --git a/applications/admin/controllers/default.py b/applications/admin/controllers/default.py index aaf642cf..cd1153c9 100644 --- a/applications/admin/controllers/default.py +++ b/applications/admin/controllers/default.py @@ -22,10 +22,8 @@ except ImportError: have_git = False GIT_MISSING = 'requires python-git module, but not installed or incompatible version' -from gluon.languages import (regex_language, read_possible_languages, - lang_sampling, - read_dict, write_dict, read_plural_dict, - write_plural_dict, PLURAL_RULES) +from gluon.languages import (read_possible_languages, read_dict, write_dict, + read_plural_dict, write_plural_dict) if DEMO_MODE and request.function in ['change_password','pack','pack_plugin','upgrade_web2py','uninstall','cleanup','compile_app','remove_compiled_app','delete','delete_plugin','create_file','upload_file','update_languages','reload_routes','git_push','git_pull']: @@ -812,7 +810,6 @@ def edit_language(): def edit_plurals(): """ Edit plurals file """ - #import ipdb; ipdb.set_trace() app = get_app() filename = '/'.join(request.args) plurals = read_plural_dict(apath(filename, r=request)) # plural forms dictionary @@ -949,30 +946,11 @@ def design(): statics.sort() # Get all languages - all_languages=dict([(lang+'.py',info[0]) for lang,info - in read_possible_languages(apath(app, r=request)).iteritems() - if info[2]!=0]) # info[2] is langfile_mtime: - # get only existed files - languages = sorted(all_languages) - - plural_rules = {} - all_plurals = PLURAL_RULES - for langfile,lang in all_languages.iteritems(): - lang=lang.strip() - match_language = regex_language.match(lang) - if match_language: - match_language = tuple(part - for part in match_language.groups() - if part) - plang = lang_sampling(match_language, all_plurals.keys()) - if plang: - plural=all_plurals[plang] - plural_rules[langfile]=(plural[0],plang,plural[4],plural[3]) - else: - plural_rules[langfile]=(0,lang,'plural_rules-%s.py'%lang,'') - - plurals = listdir(apath('%s/languages/' % app, r=request), - '^plural-[\w-]+\.py$') + languages=dict([(lang,info) for lang,info + in read_possible_languages( + apath(app, r=request)).iteritems() + if info[2]!=0]) # info[2] is langfile_mtime: + # get only existed files #Get crontab cronfolder = apath('%s/cron' % app, r=request) @@ -1000,8 +978,6 @@ def design(): privates=filter_plugins(privates,plugins), statics=filter_plugins(statics,plugins), languages=languages, - plurals=plurals, - plural_rules=plural_rules, crontab=crontab, plugins=plugins) diff --git a/applications/admin/languages/uk.py b/applications/admin/languages/uk.py index 461a4370..b70f3a8c 100644 --- a/applications/admin/languages/uk.py +++ b/applications/admin/languages/uk.py @@ -14,6 +14,7 @@ '%Y-%m-%d %H:%M:%S': '%Y/%m/%d %H:%M:%S', '(requires internet access)': '(потрібно мати доступ в інтернет)', '(something like "it-it")': '(щось схоже на "uk-ua")', +'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(не існує файлу **gluon/contrib/plural_rules/%s.py**)', '@markmin\x01Searching: **%s** %%{file}': 'Знайдено: **%s** %%{файл}', 'Abort': 'Припинити', 'About': 'Про', @@ -405,6 +406,7 @@ 'ticket': 'позначка', 'Ticket': 'Позначка (Ticket)', 'Ticket ID': 'Ід.позначки (Ticket ID)', +'Ticket Missing': 'Позначка (ticket) відсутня', 'tickets': 'позначки (tickets)', 'Time in Cache (h:m:s)': 'Час в кеші (г:хв:сек)', 'to previous version.': 'до попередньої версії.', @@ -412,6 +414,7 @@ 'To emulate a breakpoint programatically, write:': 'Для встановлення точки зупинки програмним чином напишіть:', 'to use the debugger!': 'щоб активувати ладнач!', 'toggle breakpoint': '+/- точку зупинки', +'Toggle Fullscreen': 'Перемкнути на весь екран', 'Traceback': 'Стек викликів (Traceback)', 'Translation strings for the application': 'Пари рядків <оригінал>:<переклад> для вибраної мови', 'try something like': 'спробуйте щось схоже на', diff --git a/applications/admin/views/default/design.html b/applications/admin/views/default/design.html index 1934fc1d..27f12512 100644 --- a/applications/admin/views/default/design.html +++ b/applications/admin/views/default/design.html @@ -187,8 +187,9 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi {{if not languages:}}

{{=T("There are no translators, only default language is supported")}}

{{pass}} - {{for file in languages:}} - {{id="languages__"+file.replace('.','__')}} + {{for lang in sorted(languages): + file = lang+'.py' + id = "languages__"+file.replace('.','__')}} {{pass}}
@@ -203,24 +204,17 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi   ( {{=T("Plural-Forms:")}} - {{p=plural_rules[file]}} - {{if p[0] == 0:}} - {{=T("rules are not defined")}}, - - {{=button(URL('create_file', vars=dict(filename=p[2], location='gluon/contrib/rules/', sender=URL('design', args=app), id=id, app=app, token=session.token)), T('Create rules'))}} - + {{p=languages[lang][3:7]}} + {{if p[2] == 'default':}} + {{=T("rules are not defined")}} {{=T.M("(file **gluon/contrib/plural_rules/%s.py** is not found)",lang[:2])}} {{else:}} - {{if p[0] == 1:}} - {{if p[3] == 'ok':}} - {{=B(T("are not used"))}}, - {{else:}} - {{=B(T("rules parsed with errors"))}}, - {{pass}} + {{if p[3] == 1:}} + {{=B(T("are not used"))}} {{else:}} - {{pfile='plural-%s.py'%p[1]}} - {{if pfile in plurals:}} + {{pfile=p[0]}} + {{if p[1]!=0:}} - {{=editpluralsfile('languages',pfile,dict(nplurals=p[0]))}} + {{=editpluralsfile('languages',pfile,dict(nplurals=p[3]))}} {{=peekfile('languages',pfile,dict(id=id))}} @@ -235,6 +229,7 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
+ {{pass}}
{{=file_create_form('%s/languages/' % app, 'languages')}}{{=T('(something like "it-it")')}}
diff --git a/applications/welcome/languages/cs.py b/applications/welcome/languages/cs.py index 85c72dce..33e58479 100644 --- a/applications/welcome/languages/cs.py +++ b/applications/welcome/languages/cs.py @@ -3,65 +3,139 @@ '!langcode!': 'cs-cz', '!langname!': 'Český', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" je voliteľný výraz ako "field1=\'newvalue\'". Nemôžete upravovať alebo zmazať výsledky JOINu', -'%Y-%m-%d': '%d.%m.%Y', -'%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S', '%s %%{row} deleted': '%s zmazaných záznamů', '%s %%{row} updated': '%s upravených záznamů', '%s selected': '%s označených', +'%Y-%m-%d': '%d.%m.%Y', +'%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S', +'About': 'About', +'Access Control': 'Access Control', +'Administrative Interface': 'Administrative Interface', 'Administrative interface': 'pro administrátorské rozhranie kliknite sem', +'Ajax Recipes': 'Ajax Recipes', +'appadmin is disabled because insecure channel': 'appadmin je zakázaný bez zabezpečeného spojení', 'Are you sure you want to delete this object?': 'Opravdu chceš odstranit tento objekt?', 'Available Databases and Tables': 'Dostupné databáze a tabuľky', +'Buy this book': 'Buy this book', +'cache': 'cache', +'Cache': 'Cache', +'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Nemůže být prázdné', 'Change password': 'Změna hesla', 'Check to delete': 'Označit ke smazání', 'Check to delete:': 'Check to delete:', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'Client IP': 'Client IP', +'Community': 'Community', +'Components and Plugins': 'Components and Plugins', 'Controller': 'Controller', 'Copyright': 'Copyright', 'Current request': 'Aktuální požadavek', 'Current response': 'Aktuální odpověď', 'Current session': 'Aktuální session', +'customize me!': 'uprav mě!', +'data uploaded': 'data nahrána', +'Database': 'databáze', +'Database %s select': 'databáze %s výber', +'db': 'db', 'DB Model': 'DB Model', -'Database': 'Databáze', 'Delete:': 'Smazat:', +'Demo': 'Demo', +'Deployment Recipes': 'Deployment Recipes', 'Description': 'Popis', +'design': 'návrh', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', 'Documentation': 'Dokumentáce', +"Don't know what to do?": "Don't know what to do?", +'done!': 'hotovo!', +'Download': 'Download', 'E-mail': 'E-mail', 'Edit': 'Upravit', -'Edit Profile': 'Upravit profil', 'Edit current record': 'Upravit aktuální záznam', +'Edit Profile': 'Upravit profil', +'Email and SMS': 'Email and SMS', +'enter a number between %(min)g and %(max)g': 'zadej číslo mezi %(min)g a %(max)g', +'enter an integer between %(min)g and %(max)g': 'zadej celé číslo mezi %(min)g a %(max)g', +'Errors': 'Errors', +'export as csv file': 'exportovat do csv souboru', +'FAQ': 'FAQ', 'First name': 'Křestní jméno', +'forgot username?': 'neznáš svúj nick?', +'Forms and Validators': 'Forms and Validators', +'Free Applications': 'Free Applications', 'Group %(group_id)s created': 'Skupina %(group_id)s vytvořena', 'Group ID': 'ID skupiny', +'Groups': 'Groups', 'Hello World': 'Ahoj světe', +'Home': 'Home', +'How did you get here?': 'How did you get here?', +'import': 'import', 'Import/Export': 'Import/Export', 'Index': 'Index', +'insert new': 'vložit nový záznam ', +'insert new %s': 'vložit nový záznam %s', 'Internal State': 'Vnitřní stav', -'Invalid Query': 'Neplatná dotaz', +'Introduction': 'Introduction', 'Invalid email': 'Neplatný email', 'Invalid password': 'Nesprávné heslo', +'Invalid Query': 'Neplatná dotaz', +'invalid request': 'Neplatný požadavek', +'Key': 'Key', 'Last name': 'Příjmení', 'Layout': 'Layout', +'Layout Plugins': 'Layout Plugins', +'Layouts': 'Layouts', +'Live Chat': 'Live Chat', 'Logged in': 'Přihlášení úspěšné', 'Logged out': 'Odhlášení úspěšné', +'login': 'prihlásit', 'Login': 'Login', +'logout': 'odhlásit', 'Lost Password': 'Ztracené heslo?', +'lost password?': 'neznáš heslo?', +'Manage Cache': 'Manage Cache', 'Menu Model': 'Menu Model', +'My Sites': 'My Sites', 'Name': 'Jméno', -'New Record': 'Nový záznam', 'New password': 'Nové heslo', +'New Record': 'Nový záznam', +'new record inserted': 'nový záznam byl vložen', +'next 100 rows': 'dalších 100 řádků', 'No databases in this application': 'V této aplikáci nejsou databáze', 'Object or table name': 'Objekt či tabulka', 'Old password': 'Staré heslo', 'Online examples': 'pro online příklady klikněte sem', +'or import from csv file': 'a nebo naimportovat z csv souboru', 'Origin': 'Púvod', +'Other Plugins': 'Other Plugins', +'Other Recipes': 'Other Recipes', +'Overview': 'Overview', +'password': 'heslo', 'Password': 'Heslo', "Password fields don't match": 'Hesla se neshodují', +'Plugins': 'Plugins', 'Powered by': 'Powered by', +'Preface': 'Preface', +'previous 100 rows': 'předchádzajících 100 řádků', +'profile': 'profil', +'Python': 'Python', 'Query:': 'Dotaz:', +'Quick Examples': 'Quick Examples', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', 'Readme': 'Nápověda', +'Recipes': 'Recipes', +'Record': 'záznam', +'record does not exist': 'záznam neexistuje', 'Record ID': 'ID záznamu', +'Record id': 'id záznamu', 'Register': 'Zaregistrovat se', +'register': 'registrovat', 'Registration identifier': 'Registrační identifikátor', 'Registration key': 'Registrační kľíč', 'Remember me (for 30 days)': 'Zapamatuj si mne (na 30 dní)', @@ -70,14 +144,28 @@ 'Role': 'Role', 'Rows in Table': 'řádků v tabulce', 'Rows selected': 'označených řádků', +'Semantic': 'Semantic', +'Services': 'Services', +'Size of cache:': 'Size of cache:', +'state': 'stav', +'Statistics': 'Statistics', 'Stylesheet': 'CSS', +'submit': 'submit', 'Submit': 'Odeslat', +'Support': 'Support', 'Sure you want to delete this object?': 'Opravdu chceš smazat tento objekt?', +'Table': 'tabulka', 'Table name': 'Název tabulky', 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"query" je podmínka jako "db.table1.field1==\'value\'". Něco jako "db.table1.field1==db.table2.field2" má za výsledek SQL JOIN.', +'The Core': 'The Core', 'The output of the file is a dictionary that was rendered by the view %s': 'Výstup zo souboru je slovník, ktorý byl zobrazený ve view %s', +'The Views': 'The Views', +'This App': 'This App', 'This is a copy of the scaffolding application': 'Toto je kopie skeletu aplikace', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'Časové razítko', +'Twitter': 'Twitter', +'unable to parse csv file': 'nedá sa zpracovat csv soubor', 'Update:': 'Upravit:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Použijte (...)&(...) pro AND, (...)|(...) pro OR a ~(...) pro NOT na poskládaní komplexnejších dotazů.', 'User %(id)s Logged-in': 'Uživatel %(id)s prihlásen', @@ -89,43 +177,13 @@ 'User ID': 'ID uživatele', 'Username': 'Nick', 'Verify Password': 'Zopakuj heslo', +'Videos': 'Videos', 'View': 'Zobrazit', 'Welcome': 'Vítej', 'Welcome to web2py': 'Vitejte ve web2py', +'Welcome to web2py!': 'Welcome to web2py!', 'Which called the function %s located in the file %s': 'Ktorý zavolal funkci %s v souboru %s', 'You are successfully running web2py': 'Úspešně jste spustili web2py', 'You can modify this application and adapt it to your needs': 'Můžete upravit tuto aplikáci a prispôsobit ji svojim potřebám', 'You visited the url %s': 'Navštívili jste URL %s', -'appadmin is disabled because insecure channel': 'appadmin je zakázaný bez zabezpečeného spojení', -'cache': 'cache', -'customize me!': 'uprav mě!', -'data uploaded': 'data nahrána', -'Database': 'databáze', -'Database %s select': 'databáze %s výber', -'db': 'db', -'design': 'návrh', -'done!': 'hotovo!', -'enter a number between %(min)g and %(max)g': 'zadej číslo mezi %(min)g a %(max)g', -'enter an integer between %(min)g and %(max)g': 'zadej celé číslo mezi %(min)g a %(max)g', -'export as csv file': 'exportovat do csv souboru', -'forgot username?': 'neznáš svúj nick?', -'insert new': 'vložit nový záznam ', -'insert new %s': 'vložit nový záznam %s', -'invalid request': 'Neplatný požadavek', -'login': 'prihlásit', -'logout': 'odhlásit', -'lost password?': 'neznáš heslo?', -'new record inserted': 'nový záznam byl vložen', -'next 100 rows': 'dalších 100 řádků', -'or import from csv file': 'a nebo naimportovat z csv souboru', -'password': 'heslo', -'previous 100 rows': 'předchádzajících 100 řádků', -'profile': 'profil', -'Record': 'záznam', -'record does not exist': 'záznam neexistuje', -'Record id': 'id záznamu', -'register': 'registrovat', -'state': 'stav', -'Table': 'tabulka', -'unable to parse csv file': 'nedá sa zpracovat csv soubor', } diff --git a/applications/welcome/languages/es.py b/applications/welcome/languages/es.py index 1780400c..3fef6254 100644 --- a/applications/welcome/languages/es.py +++ b/applications/welcome/languages/es.py @@ -3,144 +3,28 @@ '!langcode!': 'es', '!langname!': 'Español', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"actualice" es una expresión opcional como "campo1=\'nuevo_valor\'". No se puede actualizar o eliminar resultados de un JOIN', -'%Y-%m-%d': '%Y-%m-%d', -'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '%s %%{row} deleted': '%s filas eliminadas', '%s %%{row} updated': '%s filas actualizadas', '%s selected': '%s seleccionado(s)', +'%Y-%m-%d': '%Y-%m-%d', +'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '(something like "it-it")': '(algo como "it-it")', 'A new version of web2py is available': 'Hay una nueva versión de web2py disponible', 'A new version of web2py is available: %s': 'Hay una nueva versión de web2py disponible: %s', -'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENCION: Inicio de sesión requiere una conexión segura (HTTPS) o localhost.', -'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENCION: NO EJECUTE VARIAS PRUEBAS SIMULTANEAMENTE, NO SON THREAD SAFE.', -'ATTENTION: you cannot edit the running application!': 'ATENCION: no puede modificar la aplicación que se ejecuta!', +'about': 'acerca de', 'About': 'Acerca de', 'About application': 'Acerca de la aplicación', -'Admin is disabled because insecure channel': 'Admin deshabilitado, el canal no es seguro', -'Admin is disabled because unsecure channel': 'Admin deshabilitado, el canal no es seguro', -'Administrative interface': 'Interfaz administrativa', -'Administrator Password:': 'Contraseña del Administrador:', -'Are you sure you want to delete file "%s"?': '¿Está seguro que desea eliminar el archivo "%s"?', -'Are you sure you want to uninstall application "%s"': '¿Está seguro que desea desinstalar la aplicación "%s"', -'Are you sure you want to uninstall application "%s"?': '¿Está seguro que desea desinstalar la aplicación "%s"?', -'Authentication': 'Autenticación', -'Available Databases and Tables': 'Bases de datos y tablas disponibles', -'Cannot be empty': 'No puede estar vacío', -'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'No se puede compilar: hay errores en su aplicación. Depure, corrija errores y vuelva a intentarlo.', -'Change Password': 'Cambie Contraseña', -'Check to delete': 'Marque para eliminar', -'Client IP': 'IP del Cliente', -'Controller': 'Controlador', -'Controllers': 'Controladores', -'Copyright': 'Derechos de autor', -'Create new application': 'Cree una nueva aplicación', -'Current request': 'Solicitud en curso', -'Current response': 'Respuesta en curso', -'Current session': 'Sesión en curso', -'DB Model': 'Modelo "db"', -'DESIGN': 'DISEÑO', -'Database': 'Base de datos', -'Date and Time': 'Fecha y Hora', -'Delete': 'Elimine', -'Delete:': 'Elimine:', -'Deploy on Google App Engine': 'Instale en Google App Engine', -'Description': 'Descripción', -'Design for': 'Diseño para', -'Documentation': 'Documentación', -'E-mail': 'Correo electrónico', -'EDIT': 'EDITAR', -'Edit': 'Editar', -'Edit Profile': 'Editar Perfil', -'Edit This App': 'Edite esta App', -'Edit application': 'Editar aplicación', -'Edit current record': 'Edite el registro actual', -'Editing file': 'Editando archivo', -'Editing file "%s"': 'Editando archivo "%s"', -'Error logs for "%(app)s"': 'Bitácora de errores en "%(app)s"', -'First name': 'Nombre', -'Functions with no doctests will result in [passed] tests.': 'Funciones sin doctests equivalen a pruebas [aceptadas].', -'Group ID': 'ID de Grupo', -'Hello World': 'Hola Mundo', -'Import/Export': 'Importar/Exportar', -'Index': 'Indice', -'Installed applications': 'Aplicaciones instaladas', -'Internal State': 'Estado Interno', -'Invalid Query': 'Consulta inválida', -'Invalid action': 'Acción inválida', -'Invalid email': 'Correo inválido', -'Language files (static strings) updated': 'Archivos de lenguaje (cadenas estáticas) actualizados', -'Languages': 'Lenguajes', -'Last name': 'Apellido', -'Last saved on:': 'Guardado en:', -'Layout': 'Diseño de página', -'License for': 'Licencia para', -'Login': 'Inicio de sesión', -'Login to the Administrative Interface': 'Inicio de sesión para la Interfaz Administrativa', -'Logout': 'Fin de sesión', -'Lost Password': 'Contraseña perdida', -'Main Menu': 'Menú principal', -'Menu Model': 'Modelo "menu"', -'Models': 'Modelos', -'Modules': 'Módulos', -'NO': 'NO', -'Name': 'Nombre', -'New Record': 'Registro nuevo', -'No databases in this application': 'No hay bases de datos en esta aplicación', -'Online examples': 'Ejemplos en línea', -'Origin': 'Origen', -'Original/Translation': 'Original/Traducción', -'Password': 'Contraseña', -'Peeking at file': 'Visualizando archivo', -'Powered by': 'Este sitio usa', -'Query:': 'Consulta:', -'Record ID': 'ID de Registro', -'Register': 'Registrese', -'Registration key': 'Contraseña de Registro', -'Reset Password key': 'Reset Password key', -'Resolve Conflict file': 'archivo Resolución de Conflicto', -'Role': 'Rol', -'Rows in Table': 'Filas en la tabla', -'Rows selected': 'Filas seleccionadas', -'Saved file hash:': 'Hash del archivo guardado:', -'Static files': 'Archivos estáticos', -'Stylesheet': 'Hoja de estilo', -'Sure you want to delete this object?': '¿Está seguro que desea eliminar este objeto?', -'Table name': 'Nombre de la tabla', -'Testing application': 'Probando aplicación', -'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'La "consulta" es una condición como "db.tabla1.campo1==\'valor\'". Algo como "db.tabla1.campo1==db.tabla2.campo2" resulta en un JOIN SQL.', -'The output of the file is a dictionary that was rendered by the view %s': 'La salida del archivo es un diccionario escenificado por la vista %s', -'There are no controllers': 'No hay controladores', -'There are no models': 'No hay modelos', -'There are no modules': 'No hay módulos', -'There are no static files': 'No hay archivos estáticos', -'There are no translators, only default language is supported': 'No hay traductores, sólo el lenguaje por defecto es soportado', -'There are no views': 'No hay vistas', -'This is a copy of the scaffolding application': 'Esta es una copia de la aplicación de andamiaje', -'This is the %(filename)s template': 'Esta es la plantilla %(filename)s', -'Ticket': 'Tiquete', -'Timestamp': 'Timestamp', -'Unable to check for upgrades': 'No es posible verificar la existencia de actualizaciones', -'Unable to download': 'No es posible la descarga', -'Unable to download app': 'No es posible descarga la aplicación', -'Update:': 'Actualice:', -'Upload existing application': 'Suba esta aplicación', -'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) para AND, (...)|(...) para OR, y ~(...) para NOT, para crear consultas más complejas.', -'User ID': 'ID de Usuario', -'View': 'Vista', -'Views': 'Vistas', -'Welcome': 'Welcome', -'Welcome %s': 'Bienvenido %s', -'Welcome to web2py': 'Bienvenido a web2py', -'Which called the function %s located in the file %s': 'La cual llamó la función %s localizada en el archivo %s', -'YES': 'SI', -'You are successfully running web2py': 'Usted está ejecutando web2py exitosamente', -'You can modify this application and adapt it to your needs': 'Usted puede modificar esta aplicación y adaptarla a sus necesidades', -'You visited the url %s': 'Usted visitó la url %s', -'about': 'acerca de', +'Access Control': 'Access Control', 'additional code for your application': 'código adicional para su aplicación', 'admin disabled because no admin password': ' por falta de contraseña', 'admin disabled because not supported on google app engine': 'admin deshabilitado, no es soportado en GAE', 'admin disabled because unable to access password file': 'admin deshabilitado, imposible acceder al archivo con la contraseña', +'Admin is disabled because insecure channel': 'Admin deshabilitado, el canal no es seguro', +'Admin is disabled because unsecure channel': 'Admin deshabilitado, el canal no es seguro', +'Administrative Interface': 'Administrative Interface', +'Administrative interface': 'Interfaz administrativa', +'Administrator Password:': 'Contraseña del Administrador:', +'Ajax Recipes': 'Ajax Recipes', 'and rename it (required):': 'y renombrela (requerido):', 'and rename it:': ' y renombrelo:', 'appadmin': 'appadmin', @@ -148,40 +32,98 @@ 'application "%s" uninstalled': 'aplicación "%s" desinstalada', 'application compiled': 'aplicación compilada', 'application is compiled and cannot be designed': 'la aplicación está compilada y no puede ser modificada', +'Are you sure you want to delete file "%s"?': '¿Está seguro que desea eliminar el archivo "%s"?', +'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', +'Are you sure you want to uninstall application "%s"': '¿Está seguro que desea desinstalar la aplicación "%s"', +'Are you sure you want to uninstall application "%s"?': '¿Está seguro que desea desinstalar la aplicación "%s"?', +'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENCION: Inicio de sesión requiere una conexión segura (HTTPS) o localhost.', +'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENCION: NO EJECUTE VARIAS PRUEBAS SIMULTANEAMENTE, NO SON THREAD SAFE.', +'ATTENTION: you cannot edit the running application!': 'ATENCION: no puede modificar la aplicación que se ejecuta!', +'Authentication': 'Autenticación', +'Available Databases and Tables': 'Bases de datos y tablas disponibles', +'Buy this book': 'Buy this book', 'cache': 'cache', +'Cache': 'Cache', +'Cache Keys': 'Cache Keys', 'cache, errors and sessions cleaned': 'cache, errores y sesiones eliminados', +'Cannot be empty': 'No puede estar vacío', +'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'No se puede compilar: hay errores en su aplicación. Depure, corrija errores y vuelva a intentarlo.', 'cannot create file': 'no es posible crear archivo', 'cannot upload file "%(filename)s"': 'no es posible subir archivo "%(filename)s"', +'Change Password': 'Cambie Contraseña', 'change password': 'cambie contraseña', 'check all': 'marcar todos', +'Check to delete': 'Marque para eliminar', 'clean': 'limpiar', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'click to check for upgrades': 'haga clic para buscar actualizaciones', +'Client IP': 'IP del Cliente', +'Community': 'Community', 'compile': 'compilar', 'compiled application removed': 'aplicación compilada removida', +'Components and Plugins': 'Components and Plugins', +'Controller': 'Controlador', +'Controllers': 'Controladores', 'controllers': 'controladores', +'Copyright': 'Derechos de autor', 'create file with filename:': 'cree archivo con nombre:', +'Create new application': 'Cree una nueva aplicación', 'create new application:': 'nombre de la nueva aplicación:', 'crontab': 'crontab', +'Current request': 'Solicitud en curso', +'Current response': 'Respuesta en curso', +'Current session': 'Sesión en curso', 'currently saved or': 'actualmente guardado o', 'customize me!': 'Adaptame!', 'data uploaded': 'datos subidos', 'Database': 'base de datos', 'Database %s select': 'selección en base de datos %s', 'database administration': 'administración base de datos', +'Date and Time': 'Fecha y Hora', 'db': 'db', +'DB Model': 'Modelo "db"', 'defines tables': 'define tablas', +'Delete': 'Elimine', 'delete': 'eliminar', 'delete all checked': 'eliminar marcados', +'Delete:': 'Elimine:', +'Demo': 'Demo', +'Deploy on Google App Engine': 'Instale en Google App Engine', +'Deployment Recipes': 'Deployment Recipes', +'Description': 'Descripción', +'DESIGN': 'DISEÑO', 'design': 'modificar', +'Design for': 'Diseño para', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Documentation': 'Documentación', +"Don't know what to do?": "Don't know what to do?", 'done!': 'listo!', +'Download': 'Download', +'E-mail': 'Correo electrónico', +'EDIT': 'EDITAR', 'edit': 'editar', +'Edit': 'Editar', +'Edit application': 'Editar aplicación', 'edit controller': 'editar controlador', +'Edit current record': 'Edite el registro actual', 'edit profile': 'editar perfil', +'Edit Profile': 'Editar Perfil', +'Edit This App': 'Edite esta App', +'Editing file': 'Editando archivo', +'Editing file "%s"': 'Editando archivo "%s"', +'Email and SMS': 'Email and SMS', +'Error logs for "%(app)s"': 'Bitácora de errores en "%(app)s"', +'Errors': 'Errors', 'errors': 'errores', 'export as csv file': 'exportar como archivo CSV', 'exposes': 'expone', 'extends': 'extiende', 'failed to reload module': 'recarga del módulo ha fallado', +'FAQ': 'FAQ', 'file "%(filename)s" created': 'archivo "%(filename)s" creado', 'file "%(filename)s" deleted': 'archivo "%(filename)s" eliminado', 'file "%(filename)s" uploaded': 'archivo "%(filename)s" subido', @@ -191,70 +133,186 @@ 'file does not exist': 'archivo no existe', 'file saved on %(time)s': 'archivo guardado %(time)s', 'file saved on %s': 'archivo guardado %s', +'First name': 'Nombre', +'Forms and Validators': 'Forms and Validators', +'Free Applications': 'Free Applications', +'Functions with no doctests will result in [passed] tests.': 'Funciones sin doctests equivalen a pruebas [aceptadas].', +'Group ID': 'ID de Grupo', +'Groups': 'Groups', +'Hello World': 'Hola Mundo', 'help': 'ayuda', +'Home': 'Home', +'How did you get here?': 'How did you get here?', 'htmledit': 'htmledit', +'import': 'import', +'Import/Export': 'Importar/Exportar', 'includes': 'incluye', +'Index': 'Indice', 'insert new': 'inserte nuevo', 'insert new %s': 'inserte nuevo %s', +'Installed applications': 'Aplicaciones instaladas', 'internal error': 'error interno', +'Internal State': 'Estado Interno', +'Introduction': 'Introduction', +'Invalid action': 'Acción inválida', +'Invalid email': 'Correo inválido', 'invalid password': 'contraseña inválida', +'Invalid Query': 'Consulta inválida', 'invalid request': 'solicitud inválida', 'invalid ticket': 'tiquete inválido', +'Key': 'Key', 'language file "%(filename)s" created/updated': 'archivo de lenguaje "%(filename)s" creado/actualizado', +'Language files (static strings) updated': 'Archivos de lenguaje (cadenas estáticas) actualizados', 'languages': 'lenguajes', +'Languages': 'Lenguajes', 'languages updated': 'lenguajes actualizados', +'Last name': 'Apellido', +'Last saved on:': 'Guardado en:', +'Layout': 'Diseño de página', +'Layout Plugins': 'Layout Plugins', +'Layouts': 'Layouts', +'License for': 'Licencia para', +'Live Chat': 'Live Chat', 'loading...': 'cargando...', 'login': 'inicio de sesión', +'Login': 'Inicio de sesión', +'Login to the Administrative Interface': 'Inicio de sesión para la Interfaz Administrativa', 'logout': 'fin de sesión', +'Logout': 'Fin de sesión', +'Lost Password': 'Contraseña perdida', 'lost password?': '¿olvido la contraseña?', +'Main Menu': 'Menú principal', +'Manage Cache': 'Manage Cache', +'Menu Model': 'Modelo "menu"', 'merge': 'combinar', +'Models': 'Modelos', 'models': 'modelos', +'Modules': 'Módulos', 'modules': 'módulos', +'My Sites': 'My Sites', +'Name': 'Nombre', 'new application "%s" created': 'nueva aplicación "%s" creada', +'New Record': 'Registro nuevo', 'new record inserted': 'nuevo registro insertado', 'next 100 rows': '100 filas siguientes', +'NO': 'NO', +'No databases in this application': 'No hay bases de datos en esta aplicación', +'Online examples': 'Ejemplos en línea', 'or import from csv file': 'o importar desde archivo CSV', 'or provide application url:': 'o provea URL de la aplicación:', +'Origin': 'Origen', +'Original/Translation': 'Original/Traducción', +'Other Plugins': 'Other Plugins', +'Other Recipes': 'Other Recipes', +'Overview': 'Overview', 'pack all': 'empaquetar todo', 'pack compiled': 'empaquete compiladas', +'Password': 'Contraseña', +'Peeking at file': 'Visualizando archivo', +'Plugins': 'Plugins', +'Powered by': 'Este sitio usa', +'Preface': 'Preface', 'previous 100 rows': '100 filas anteriores', +'Python': 'Python', +'Query:': 'Consulta:', +'Quick Examples': 'Quick Examples', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'Recipes': 'Recipes', 'Record': 'registro', 'record does not exist': 'el registro no existe', +'Record ID': 'ID de Registro', 'Record id': 'id de registro', +'Register': 'Registrese', 'register': 'registrese', +'Registration key': 'Contraseña de Registro', 'remove compiled': 'eliminar compiladas', +'Reset Password key': 'Reset Password key', +'Resolve Conflict file': 'archivo Resolución de Conflicto', 'restore': 'restaurar', 'revert': 'revertir', +'Role': 'Rol', +'Rows in Table': 'Filas en la tabla', +'Rows selected': 'Filas seleccionadas', 'save': 'guardar', +'Saved file hash:': 'Hash del archivo guardado:', +'Semantic': 'Semantic', +'Services': 'Services', 'session expired': 'sesión expirada', 'shell': 'shell', 'site': 'sitio', +'Size of cache:': 'Size of cache:', 'some files could not be removed': 'algunos archivos no pudieron ser removidos', 'state': 'estado', 'static': 'estáticos', +'Static files': 'Archivos estáticos', +'Statistics': 'Statistics', +'Stylesheet': 'Hoja de estilo', +'submit': 'submit', +'Support': 'Support', +'Sure you want to delete this object?': '¿Está seguro que desea eliminar este objeto?', 'Table': 'tabla', +'Table name': 'Nombre de la tabla', 'test': 'probar', +'Testing application': 'Probando aplicación', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'La "consulta" es una condición como "db.tabla1.campo1==\'valor\'". Algo como "db.tabla1.campo1==db.tabla2.campo2" resulta en un JOIN SQL.', 'the application logic, each URL path is mapped in one exposed function in the controller': 'la lógica de la aplicación, cada ruta URL se mapea en una función expuesta en el controlador', +'The Core': 'The Core', 'the data representation, define database tables and sets': 'la representación de datos, define tablas y conjuntos de base de datos', +'The output of the file is a dictionary that was rendered by the view %s': 'La salida del archivo es un diccionario escenificado por la vista %s', 'the presentations layer, views are also known as templates': 'la capa de presentación, las vistas también son llamadas plantillas', +'The Views': 'The Views', +'There are no controllers': 'No hay controladores', +'There are no models': 'No hay modelos', +'There are no modules': 'No hay módulos', +'There are no static files': 'No hay archivos estáticos', +'There are no translators, only default language is supported': 'No hay traductores, sólo el lenguaje por defecto es soportado', +'There are no views': 'No hay vistas', 'these files are served without processing, your images go here': 'estos archivos son servidos sin procesar, sus imágenes van aquí', +'This App': 'This App', +'This is a copy of the scaffolding application': 'Esta es una copia de la aplicación de andamiaje', +'This is the %(filename)s template': 'Esta es la plantilla %(filename)s', +'Ticket': 'Tiquete', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', +'Timestamp': 'Timestamp', 'to previous version.': 'a la versión previa.', 'translation strings for the application': 'cadenas de caracteres de traducción para la aplicación', 'try': 'intente', 'try something like': 'intente algo como', +'Twitter': 'Twitter', +'Unable to check for upgrades': 'No es posible verificar la existencia de actualizaciones', 'unable to create application "%s"': 'no es posible crear la aplicación "%s"', 'unable to delete file "%(filename)s"': 'no es posible eliminar el archivo "%(filename)s"', +'Unable to download': 'No es posible la descarga', +'Unable to download app': 'No es posible descarga la aplicación', 'unable to parse csv file': 'no es posible analizar el archivo CSV', 'unable to uninstall "%s"': 'no es posible instalar "%s"', 'uncheck all': 'desmarcar todos', 'uninstall': 'desinstalar', 'update': 'actualizar', 'update all languages': 'actualizar todos los lenguajes', +'Update:': 'Actualice:', 'upload application:': 'subir aplicación:', +'Upload existing application': 'Suba esta aplicación', 'upload file:': 'suba archivo:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) para AND, (...)|(...) para OR, y ~(...) para NOT, para crear consultas más complejas.', +'User ID': 'ID de Usuario', 'versioning': 'versiones', +'Videos': 'Videos', 'view': 'vista', +'View': 'Vista', +'Views': 'Vistas', 'views': 'vistas', -'web2py Recent Tweets': 'Tweets Recientes de web2py', 'web2py is up to date': 'web2py está actualizado', +'web2py Recent Tweets': 'Tweets Recientes de web2py', +'Welcome': 'Welcome', +'Welcome %s': 'Bienvenido %s', +'Welcome to web2py': 'Bienvenido a web2py', +'Welcome to web2py!': 'Welcome to web2py!', +'Which called the function %s located in the file %s': 'La cual llamó la función %s localizada en el archivo %s', +'YES': 'SI', +'You are successfully running web2py': 'Usted está ejecutando web2py exitosamente', +'You can modify this application and adapt it to your needs': 'Usted puede modificar esta aplicación y adaptarla a sus necesidades', +'You visited the url %s': 'Usted visitó la url %s', } diff --git a/applications/welcome/languages/fr-ca.py b/applications/welcome/languages/fr-ca.py index 2491a9ea..7693d5b4 100644 --- a/applications/welcome/languages/fr-ca.py +++ b/applications/welcome/languages/fr-ca.py @@ -3,42 +3,67 @@ '!langcode!': 'fr-ca', '!langname!': 'Français (Canadien)', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" est une expression optionnelle comme "champ1=\'nouvellevaleur\'". Vous ne pouvez mettre à jour ou supprimer les résultats d\'un JOIN', -'%Y-%m-%d': '%Y-%m-%d', -'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '%s %%{row} deleted': '%s rangées supprimées', '%s %%{row} updated': '%s rangées mises à jour', '%s selected': '%s sélectionné', +'%Y-%m-%d': '%Y-%m-%d', +'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'about': 'à propos', 'About': 'À propos', 'Access Control': "Contrôle d'accès", +'Administrative Interface': 'Administrative Interface', 'Administrative interface': "Interface d'administration", 'Ajax Recipes': 'Recettes Ajax', +'appadmin is disabled because insecure channel': "appadmin est désactivée parce que le canal n'est pas sécurisé", 'Are you sure you want to delete this object?': 'Êtes-vous sûr de vouloir supprimer cet objet?', 'Authentication': 'Authentification', 'Available Databases and Tables': 'Bases de données et tables disponibles', 'Buy this book': 'Acheter ce livre', +'cache': 'cache', +'Cache': 'Cache', +'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Ne peut pas être vide', +'change password': 'changer le mot de passe', 'Check to delete': 'Cliquez pour supprimer', 'Check to delete:': 'Cliquez pour supprimer:', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'Client IP': 'IP client', 'Community': 'Communauté', +'Components and Plugins': 'Components and Plugins', 'Controller': 'Contrôleur', 'Copyright': "Droit d'auteur", 'Current request': 'Demande actuelle', 'Current response': 'Réponse actuelle', 'Current session': 'Session en cours', +'customize me!': 'personnalisez-moi!', +'data uploaded': 'données téléchargées', +'Database': 'base de données', +'Database %s select': 'base de données %s select', +'db': 'db', 'DB Model': 'Modèle DB', -'Database': 'Base de données', 'Delete:': 'Supprimer:', 'Demo': 'Démo', 'Deployment Recipes': 'Recettes de déploiement ', 'Description': 'Descriptif', +'design': 'design', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', 'Documentation': 'Documentation', +"Don't know what to do?": "Don't know what to do?", +'done!': 'fait!', 'Download': 'Téléchargement', 'E-mail': 'Courriel', 'Edit': 'Éditer', -'Edit This App': 'Modifier cette application', 'Edit current record': "Modifier l'enregistrement courant", +'edit profile': 'modifier le profil', +'Edit This App': 'Modifier cette application', +'Email and SMS': 'Email and SMS', +'enter an integer between %(min)g and %(max)g': 'entrer un entier compris entre %(min)g et %(max)g', 'Errors': 'Erreurs', +'export as csv file': 'exporter sous forme de fichier csv', 'FAQ': 'faq', 'First name': 'Prénom', 'Forms and Validators': 'Formulaires et Validateurs', @@ -50,44 +75,73 @@ 'Groups': 'Groupes', 'Hello World': 'Bonjour le monde', 'Home': 'Accueil', +'How did you get here?': 'How did you get here?', +'import': 'import', 'Import/Export': 'Importer/Exporter', 'Index': 'Index', +'insert new': 'insérer un nouveau', +'insert new %s': 'insérer un nouveau %s', 'Internal State': 'État interne', 'Introduction': 'Présentation', -'Invalid Query': 'Requête Invalide', 'Invalid email': 'Courriel invalide', +'Invalid Query': 'Requête Invalide', +'invalid request': 'requête invalide', +'Key': 'Key', 'Last name': 'Nom', 'Layout': 'Mise en page', +'Layout Plugins': 'Layout Plugins', 'Layouts': 'layouts', 'Live chat': 'Clavardage en direct', +'Live Chat': 'Live Chat', 'Logged in': 'Connecté', +'login': 'connectez-vous', 'Login': 'Connectez-vous', +'logout': 'déconnectez-vous', +'lost password': 'mot de passe perdu', 'Lost Password': 'Mot de passe perdu', +'lost password?': 'mot de passe perdu?', 'Main Menu': 'Menu principal', +'Manage Cache': 'Manage Cache', 'Menu Model': 'Menu modèle', +'My Sites': 'My Sites', 'Name': 'Nom', 'New Record': 'Nouvel enregistrement', +'new record inserted': 'nouvel enregistrement inséré', +'next 100 rows': '100 prochaines lignes', 'No databases in this application': "Cette application n'a pas de bases de données", 'Online examples': 'Exemples en ligne', +'or import from csv file': "ou importer d'un fichier CSV", 'Origin': 'Origine', +'Other Plugins': 'Other Plugins', 'Other Recipes': 'Autres recettes', 'Overview': 'Présentation', +'password': 'mot de passe', 'Password': 'Mot de passe', "Password fields don't match": 'Les mots de passe ne correspondent pas', +'please input your password again': "S'il vous plaît entrer votre mot de passe", 'Plugins': 'Plugiciels', 'Powered by': 'Alimenté par', 'Preface': 'Préface', +'previous 100 rows': '100 lignes précédentes', +'profile': 'profile', 'Python': 'Python', 'Query:': 'Requête:', 'Quick Examples': 'Examples Rapides', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', 'Readme': 'Lisez-moi', 'Recipes': 'Recettes', +'Record': 'enregistrement', 'Record %(id)s created': 'Record %(id)s created', 'Record %(id)s updated': 'Record %(id)s updated', 'Record Created': 'Record Created', +'record does not exist': "l'archive n'existe pas", 'Record ID': "ID d'enregistrement", +'Record id': "id d'enregistrement", 'Record Updated': 'Record Updated', 'Register': "S'inscrire", +'register': "s'inscrire", 'Registration key': "Clé d'enregistrement", 'Registration successful': 'Inscription réussie', 'Remember me (for 30 days)': 'Se souvenir de moi (pendant 30 jours)', @@ -99,25 +153,33 @@ 'Rows selected': 'Lignes sélectionnées', 'Semantic': 'Sémantique', 'Services': 'Services', +'Size of cache:': 'Size of cache:', +'state': 'état', +'Statistics': 'Statistics', 'Stylesheet': 'Feuille de style', +'submit': 'submit', 'Submit': 'Soumettre', 'Support': 'Soutien', 'Sure you want to delete this object?': 'Êtes-vous sûr de vouloir supprimer cet objet?', +'Table': 'tableau', 'Table name': 'Nom du tableau', 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'La "query" est une condition comme "db.table1.champ1==\'valeur\'". Quelque chose comme "db.table1.champ1==db.table2.champ2" résulte en un JOIN SQL.', 'The Core': 'Le noyau', -'The Views': 'Les Vues', 'The output of the file is a dictionary that was rendered by the view %s': 'La sortie de ce fichier est un dictionnaire qui été restitué par la vue %s', +'The Views': 'Les Vues', 'This App': 'Cette Appli', 'This is a copy of the scaffolding application': "Ceci est une copie de l'application échafaudage", +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'Horodatage', 'Twitter': 'Twitter', +'unable to parse csv file': "incapable d'analyser le fichier cvs", 'Update:': 'Mise à jour:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Employez (...)&(...) pour AND, (...)|(...) pour OR, and ~(...) pour NOT pour construire des requêtes plus complexes.', 'User %(id)s Logged-in': 'Utilisateur %(id)s connecté', 'User %(id)s Registered': 'Utilisateur %(id)s enregistré', 'User ID': 'ID utilisateur', 'User Voice': 'User Voice', +'value already in database or empty': 'valeur déjà dans la base ou vide', 'Verify Password': 'Vérifiez le mot de passe', 'Videos': 'Vidéos', 'View': 'Présentation', @@ -125,44 +187,9 @@ 'Welcome': 'Bienvenu', 'Welcome %s': 'Bienvenue %s', 'Welcome to web2py': 'Bienvenue à web2py', +'Welcome to web2py!': 'Welcome to web2py!', 'Which called the function %s located in the file %s': 'Qui a appelé la fonction %s se trouvant dans le fichier %s', 'You are successfully running web2py': 'Vous roulez avec succès web2py', 'You can modify this application and adapt it to your needs': "Vous pouvez modifier cette application et l'adapter à vos besoins", 'You visited the url %s': "Vous avez visité l'URL %s", -'about': 'à propos', -'appadmin is disabled because insecure channel': "appadmin est désactivée parce que le canal n'est pas sécurisé", -'cache': 'cache', -'change password': 'changer le mot de passe', -'customize me!': 'personnalisez-moi!', -'data uploaded': 'données téléchargées', -'Database': 'base de données', -'Database %s select': 'base de données %s select', -'db': 'db', -'design': 'design', -'done!': 'fait!', -'edit profile': 'modifier le profil', -'enter an integer between %(min)g and %(max)g': 'entrer un entier compris entre %(min)g et %(max)g', -'export as csv file': 'exporter sous forme de fichier csv', -'insert new': 'insérer un nouveau', -'insert new %s': 'insérer un nouveau %s', -'invalid request': 'requête invalide', -'login': 'connectez-vous', -'logout': 'déconnectez-vous', -'lost password': 'mot de passe perdu', -'lost password?': 'mot de passe perdu?', -'new record inserted': 'nouvel enregistrement inséré', -'next 100 rows': '100 prochaines lignes', -'or import from csv file': "ou importer d'un fichier CSV", -'password': 'mot de passe', -'please input your password again': "S'il vous plaît entrer votre mot de passe", -'previous 100 rows': '100 lignes précédentes', -'profile': 'profile', -'Record': 'enregistrement', -'record does not exist': "l'archive n'existe pas", -'Record id': "id d'enregistrement", -'register': "s'inscrire", -'state': 'état', -'Table': 'tableau', -'unable to parse csv file': "incapable d'analyser le fichier cvs", -'value already in database or empty': 'valeur déjà dans la base ou vide', } diff --git a/applications/welcome/languages/fr.py b/applications/welcome/languages/fr.py index f7893576..d3ff3d92 100644 --- a/applications/welcome/languages/fr.py +++ b/applications/welcome/languages/fr.py @@ -19,10 +19,15 @@ 'Available Databases and Tables': 'Bases de données et tables disponibles', 'Buy this book': 'Acheter ce livre', 'cache': 'cache', +'Cache': 'Cache', +'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Ne peut pas être vide', 'change password': 'changer le mot de passe', 'Check to delete': 'Cliquez pour supprimer', 'Check to delete:': 'Cliquez pour supprimer:', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'Client IP': 'IP client', 'Community': 'Communauté', 'Components and Plugins': 'Components and Plugins', @@ -33,7 +38,6 @@ 'Current session': 'Session en cours', 'customize me!': 'personnalisez-moi!', 'data uploaded': 'données téléchargées', -'Database': 'Base de données', 'Database': 'base de données', 'Database %s select': 'base de données %s select', 'db': 'db', @@ -43,6 +47,9 @@ 'Deployment Recipes': 'Recettes de déploiement', 'Description': 'Description', 'design': 'design', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', 'Documentation': 'Documentation', "Don't know what to do?": "Don't know what to do?", 'done!': 'fait!', @@ -66,6 +73,7 @@ 'Hello World': 'Bonjour le monde', 'Home': 'Accueil', 'How did you get here?': 'How did you get here?', +'import': 'import', 'Import/Export': 'Importer/Exporter', 'Index': 'Index', 'insert new': 'insérer un nouveau', @@ -75,20 +83,22 @@ 'Invalid email': 'E-mail invalide', 'Invalid Query': 'Requête Invalide', 'invalid request': 'requête invalide', +'Key': 'Key', 'Last name': 'Nom', 'Layout': 'Mise en page', 'Layout Plugins': 'Layout Plugins', 'Layouts': 'Layouts', 'Live chat': 'Chat live', 'Live Chat': 'Live Chat', -'Login': 'Connectez-vous', 'login': 'connectez-vous', +'Login': 'Connectez-vous', 'logout': 'déconnectez-vous', 'lost password': 'mot de passe perdu', 'Lost Password': 'Mot de passe perdu', -'lost password?': 'mot de passe perdu?', 'Lost password?': 'Lost password?', +'lost password?': 'mot de passe perdu?', 'Main Menu': 'Menu principal', +'Manage Cache': 'Manage Cache', 'Menu Model': 'Menu modèle', 'My Sites': 'My Sites', 'Name': 'Nom', @@ -112,12 +122,15 @@ 'Python': 'Python', 'Query:': 'Requête:', 'Quick Examples': 'Examples Rapides', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', 'Readme': 'Lisez-moi', 'Recipes': 'Recettes', 'Record': 'enregistrement', 'record does not exist': "l'archive n'existe pas", -'Record id': "id d'enregistrement", 'Record ID': "ID d'enregistrement", +'Record id': "id d'enregistrement", 'Register': "S'inscrire", 'register': "s'inscrire", 'Registration identifier': 'Registration identifier', @@ -131,8 +144,11 @@ 'Rows selected': 'Lignes sélectionnées', 'Semantic': 'Sémantique', 'Services': 'Services', +'Size of cache:': 'Size of cache:', 'state': 'état', +'Statistics': 'Statistics', 'Stylesheet': 'Feuille de style', +'submit': 'submit', 'Submit': 'Soumettre', 'Support': 'Support', 'Sure you want to delete this object?': 'Êtes-vous sûr de vouloir supprimer cet objet?', @@ -144,6 +160,7 @@ 'The Views': 'Les Vues', 'This App': 'Cette Appli', 'This is a copy of the scaffolding application': "Ceci est une copie de l'application échafaudage", +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'Horodatage', 'Twitter': 'Twitter', 'unable to parse csv file': "incapable d'analyser le fichier cvs", diff --git a/applications/welcome/languages/hi.py b/applications/welcome/languages/hi.py index 8dc9f19f..46a47e86 100644 --- a/applications/welcome/languages/hi.py +++ b/applications/welcome/languages/hi.py @@ -3,85 +3,147 @@ '!langcode!': 'hi-in', '!langname!': 'हिन्दी', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN', -'%Y-%m-%d': '%Y-%m-%d', -'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '%s %%{row} deleted': '%s पंक्तियाँ मिटाएँ', '%s %%{row} updated': '%s पंक्तियाँ अद्यतन', '%s selected': '%s चुना हुआ', +'%Y-%m-%d': '%Y-%m-%d', +'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'About': 'About', +'Access Control': 'Access Control', +'Administrative Interface': 'Administrative Interface', 'Administrative interface': 'प्रशासनिक इंटरफेस के लिए यहाँ क्लिक करें', +'Ajax Recipes': 'Ajax Recipes', +'appadmin is disabled because insecure channel': 'अप आडमिन (appadmin) अक्षम है क्योंकि असुरक्षित चैनल', +'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 'Available Databases and Tables': 'उपलब्ध डेटाबेस और तालिका', +'Buy this book': 'Buy this book', +'cache': 'cache', +'Cache': 'Cache', +'Cache Keys': 'Cache Keys', 'Cannot be empty': 'खाली नहीं हो सकता', 'Change Password': 'पासवर्ड बदलें', +'change password': 'change password', 'Check to delete': 'हटाने के लिए चुनें', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', +'Community': 'Community', +'Components and Plugins': 'Components and Plugins', 'Controller': 'Controller', 'Copyright': 'Copyright', 'Current request': 'वर्तमान अनुरोध', 'Current response': 'वर्तमान प्रतिक्रिया', 'Current session': 'वर्तमान सेशन', -'DB Model': 'DB Model', -'Database': 'Database', -'Delete:': 'मिटाना:', -'Edit': 'Edit', -'Edit Profile': 'प्रोफ़ाइल संपादित करें', -'Edit This App': 'Edit This App', -'Edit current record': 'वर्तमान रेकॉर्ड संपादित करें ', -'Hello World': 'Hello World', -'Hello from MyApp': 'Hello from MyApp', -'Import/Export': 'आयात / निर्यात', -'Index': 'Index', -'Internal State': 'आंतरिक स्थिति', -'Invalid Query': 'अमान्य प्रश्न', -'Layout': 'Layout', -'Login': 'लॉग इन', -'Logout': 'लॉग आउट', -'Lost Password': 'पासवर्ड खो गया', -'Main Menu': 'Main Menu', -'Menu Model': 'Menu Model', -'New Record': 'नया रेकॉर्ड', -'No databases in this application': 'इस अनुप्रयोग में कोई डेटाबेस नहीं हैं', -'Online examples': 'ऑनलाइन उदाहरण के लिए यहाँ क्लिक करें', -'Powered by': 'Powered by', -'Query:': 'प्रश्न:', -'Register': 'पंजीकृत (रजिस्टर) करना ', -'Rows in Table': 'तालिका में पंक्तियाँ ', -'Rows selected': 'चयनित (चुने गये) पंक्तियाँ ', -'Stylesheet': 'Stylesheet', -'Sure you want to delete this object?': 'सुनिश्चित हैं कि आप इस वस्तु को हटाना चाहते हैं?', -'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.', -'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s', -'Update:': 'अद्यतन करना:', -'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', -'View': 'View', -'Welcome %s': 'Welcome %s', -'Welcome to web2py': 'वेब२पाइ (web2py) में आपका स्वागत है', -'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', -'You visited the url %s': 'You visited the url %s', -'appadmin is disabled because insecure channel': 'अप आडमिन (appadmin) अक्षम है क्योंकि असुरक्षित चैनल', -'cache': 'cache', -'change password': 'change password', 'customize me!': 'मुझे अनुकूलित (कस्टमाइज़) करें!', 'data uploaded': 'डाटा अपलोड सम्पन्न ', 'Database': 'डेटाबेस', 'Database %s select': 'डेटाबेस %s चुनी हुई', 'db': 'db', +'DB Model': 'DB Model', +'Delete:': 'मिटाना:', +'Demo': 'Demo', +'Deployment Recipes': 'Deployment Recipes', 'design': 'रचना करें', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Documentation': 'Documentation', +"Don't know what to do?": "Don't know what to do?", 'done!': 'हो गया!', +'Download': 'Download', +'Edit': 'Edit', +'Edit current record': 'वर्तमान रेकॉर्ड संपादित करें ', 'edit profile': 'edit profile', +'Edit Profile': 'प्रोफ़ाइल संपादित करें', +'Edit This App': 'Edit This App', +'Email and SMS': 'Email and SMS', +'Errors': 'Errors', 'export as csv file': 'csv फ़ाइल के रूप में निर्यात', +'FAQ': 'FAQ', +'Forms and Validators': 'Forms and Validators', +'Free Applications': 'Free Applications', +'Groups': 'Groups', +'Hello from MyApp': 'Hello from MyApp', +'Hello World': 'Hello World', +'Home': 'Home', +'How did you get here?': 'How did you get here?', +'import': 'import', +'Import/Export': 'आयात / निर्यात', +'Index': 'Index', 'insert new': 'नया डालें', 'insert new %s': 'नया %s डालें', +'Internal State': 'आंतरिक स्थिति', +'Introduction': 'Introduction', +'Invalid Query': 'अमान्य प्रश्न', 'invalid request': 'अवैध अनुरोध', +'Key': 'Key', +'Layout': 'Layout', +'Layout Plugins': 'Layout Plugins', +'Layouts': 'Layouts', +'Live Chat': 'Live Chat', 'login': 'login', +'Login': 'लॉग इन', 'logout': 'logout', +'Logout': 'लॉग आउट', +'Lost Password': 'पासवर्ड खो गया', +'Main Menu': 'Main Menu', +'Manage Cache': 'Manage Cache', +'Menu Model': 'Menu Model', +'My Sites': 'My Sites', +'New Record': 'नया रेकॉर्ड', 'new record inserted': 'नया रेकॉर्ड डाला', 'next 100 rows': 'अगले 100 पंक्तियाँ', +'No databases in this application': 'इस अनुप्रयोग में कोई डेटाबेस नहीं हैं', +'Online examples': 'ऑनलाइन उदाहरण के लिए यहाँ क्लिक करें', 'or import from csv file': 'या csv फ़ाइल से आयात', +'Other Plugins': 'Other Plugins', +'Other Recipes': 'Other Recipes', +'Overview': 'Overview', +'Plugins': 'Plugins', +'Powered by': 'Powered by', +'Preface': 'Preface', 'previous 100 rows': 'पिछले 100 पंक्तियाँ', +'Python': 'Python', +'Query:': 'प्रश्न:', +'Quick Examples': 'Quick Examples', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'Recipes': 'Recipes', 'Record': 'Record', 'record does not exist': 'रिकॉर्ड मौजूद नहीं है', 'Record id': 'रिकॉर्ड पहचानकर्ता (आईडी)', +'Register': 'पंजीकृत (रजिस्टर) करना ', 'register': 'register', +'Rows in Table': 'तालिका में पंक्तियाँ ', +'Rows selected': 'चयनित (चुने गये) पंक्तियाँ ', +'Semantic': 'Semantic', +'Services': 'Services', +'Size of cache:': 'Size of cache:', 'state': 'स्थिति', +'Statistics': 'Statistics', +'Stylesheet': 'Stylesheet', +'submit': 'submit', +'Support': 'Support', +'Sure you want to delete this object?': 'सुनिश्चित हैं कि आप इस वस्तु को हटाना चाहते हैं?', 'Table': 'तालिका', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.', +'The Core': 'The Core', +'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s', +'The Views': 'The Views', +'This App': 'This App', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', +'Twitter': 'Twitter', 'unable to parse csv file': 'csv फ़ाइल पार्स करने में असमर्थ', +'Update:': 'अद्यतन करना:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', +'Videos': 'Videos', +'View': 'View', +'Welcome %s': 'Welcome %s', +'Welcome to web2py': 'वेब२पाइ (web2py) में आपका स्वागत है', +'Welcome to web2py!': 'Welcome to web2py!', +'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', +'You are successfully running web2py': 'You are successfully running web2py', +'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', +'You visited the url %s': 'You visited the url %s', } diff --git a/applications/welcome/languages/hu.py b/applications/welcome/languages/hu.py index bd996f66..bc32c8dd 100644 --- a/applications/welcome/languages/hu.py +++ b/applications/welcome/languages/hu.py @@ -3,96 +3,160 @@ '!langcode!': 'hu', '!langname!': 'Magyar', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN', -'%Y-%m-%d': '%Y.%m.%d.', -'%Y-%m-%d %H:%M:%S': '%Y.%m.%d. %H:%M:%S', '%s %%{row} deleted': '%s sorok törlődtek', '%s %%{row} updated': '%s sorok frissítődtek', '%s selected': '%s kiválasztott', +'%Y-%m-%d': '%Y.%m.%d.', +'%Y-%m-%d %H:%M:%S': '%Y.%m.%d. %H:%M:%S', +'About': 'About', +'Access Control': 'Access Control', +'Administrative Interface': 'Administrative Interface', 'Administrative interface': 'az adminisztrációs felületért kattints ide', +'Ajax Recipes': 'Ajax Recipes', +'appadmin is disabled because insecure channel': 'az appadmin a biztonságtalan csatorna miatt letiltva', +'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 'Available Databases and Tables': 'Elérhető adatbázisok és táblák', +'Buy this book': 'Buy this book', +'cache': 'gyorsítótár', +'Cache': 'Cache', +'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Nem lehet üres', +'change password': 'jelszó megváltoztatása', 'Check to delete': 'Törléshez válaszd ki', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'Client IP': 'Client IP', +'Community': 'Community', +'Components and Plugins': 'Components and Plugins', 'Controller': 'Controller', 'Copyright': 'Copyright', 'Current request': 'Jelenlegi lekérdezés', 'Current response': 'Jelenlegi válasz', 'Current session': 'Jelenlegi folyamat', -'DB Model': 'DB Model', -'Database': 'Adatbázis', -'Delete:': 'Töröl:', -'Description': 'Description', -'E-mail': 'E-mail', -'Edit': 'Szerkeszt', -'Edit This App': 'Alkalmazást szerkeszt', -'Edit current record': 'Aktuális bejegyzés szerkesztése', -'First name': 'First name', -'Group ID': 'Group ID', -'Hello World': 'Hello Világ', -'Import/Export': 'Import/Export', -'Index': 'Index', -'Internal State': 'Internal State', -'Invalid Query': 'Hibás lekérdezés', -'Invalid email': 'Invalid email', -'Last name': 'Last name', -'Layout': 'Szerkezet', -'Main Menu': 'Főmenü', -'Menu Model': 'Menü model', -'Name': 'Name', -'New Record': 'Új bejegyzés', -'No databases in this application': 'Nincs adatbázis ebben az alkalmazásban', -'Online examples': 'online példákért kattints ide', -'Origin': 'Origin', -'Password': 'Password', -'Powered by': 'Powered by', -'Query:': 'Lekérdezés:', -'Record ID': 'Record ID', -'Registration key': 'Registration key', -'Reset Password key': 'Reset Password key', -'Role': 'Role', -'Rows in Table': 'Sorok a táblában', -'Rows selected': 'Kiválasztott sorok', -'Stylesheet': 'Stylesheet', -'Sure you want to delete this object?': 'Biztos törli ezt az objektumot?', -'Table name': 'Table name', -'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.', -'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s', -'Timestamp': 'Timestamp', -'Update:': 'Frissít:', -'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', -'User ID': 'User ID', -'View': 'Nézet', -'Welcome %s': 'Welcome %s', -'Welcome to web2py': 'Isten hozott a web2py-ban', -'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', -'You visited the url %s': 'You visited the url %s', -'appadmin is disabled because insecure channel': 'az appadmin a biztonságtalan csatorna miatt letiltva', -'cache': 'gyorsítótár', -'change password': 'jelszó megváltoztatása', 'customize me!': 'változtass meg!', 'data uploaded': 'adat feltöltve', 'Database': 'adatbázis', 'Database %s select': 'adatbázis %s kiválasztás', 'db': 'db', +'DB Model': 'DB Model', +'Delete:': 'Töröl:', +'Demo': 'Demo', +'Deployment Recipes': 'Deployment Recipes', +'Description': 'Description', 'design': 'design', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Documentation': 'Documentation', +"Don't know what to do?": "Don't know what to do?", 'done!': 'kész!', +'Download': 'Download', +'E-mail': 'E-mail', +'Edit': 'Szerkeszt', +'Edit current record': 'Aktuális bejegyzés szerkesztése', 'edit profile': 'profil szerkesztése', +'Edit This App': 'Alkalmazást szerkeszt', +'Email and SMS': 'Email and SMS', +'Errors': 'Errors', 'export as csv file': 'exportál csv fájlba', +'FAQ': 'FAQ', +'First name': 'First name', +'Forms and Validators': 'Forms and Validators', +'Free Applications': 'Free Applications', +'Group ID': 'Group ID', +'Groups': 'Groups', +'Hello World': 'Hello Világ', +'Home': 'Home', +'How did you get here?': 'How did you get here?', +'import': 'import', +'Import/Export': 'Import/Export', +'Index': 'Index', 'insert new': 'új beillesztése', 'insert new %s': 'új beillesztése %s', +'Internal State': 'Internal State', +'Introduction': 'Introduction', +'Invalid email': 'Invalid email', +'Invalid Query': 'Hibás lekérdezés', 'invalid request': 'hibás kérés', +'Key': 'Key', +'Last name': 'Last name', +'Layout': 'Szerkezet', +'Layout Plugins': 'Layout Plugins', +'Layouts': 'Layouts', +'Live Chat': 'Live Chat', 'login': 'belép', 'logout': 'kilép', 'lost password': 'elveszett jelszó', +'Lost Password': 'Lost Password', +'Main Menu': 'Főmenü', +'Manage Cache': 'Manage Cache', +'Menu Model': 'Menü model', +'My Sites': 'My Sites', +'Name': 'Name', +'New Record': 'Új bejegyzés', 'new record inserted': 'új bejegyzés felvéve', 'next 100 rows': 'következő 100 sor', +'No databases in this application': 'Nincs adatbázis ebben az alkalmazásban', +'Online examples': 'online példákért kattints ide', 'or import from csv file': 'vagy betöltés csv fájlból', +'Origin': 'Origin', +'Other Plugins': 'Other Plugins', +'Other Recipes': 'Other Recipes', +'Overview': 'Overview', +'Password': 'Password', +'Plugins': 'Plugins', +'Powered by': 'Powered by', +'Preface': 'Preface', 'previous 100 rows': 'előző 100 sor', +'Python': 'Python', +'Query:': 'Lekérdezés:', +'Quick Examples': 'Quick Examples', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'Recipes': 'Recipes', 'Record': 'bejegyzés', 'record does not exist': 'bejegyzés nem létezik', +'Record ID': 'Record ID', 'Record id': 'bejegyzés id', +'Register': 'Register', 'register': 'regisztráció', +'Registration key': 'Registration key', +'Reset Password key': 'Reset Password key', +'Role': 'Role', +'Rows in Table': 'Sorok a táblában', +'Rows selected': 'Kiválasztott sorok', +'Semantic': 'Semantic', +'Services': 'Services', +'Size of cache:': 'Size of cache:', 'state': 'állapot', +'Statistics': 'Statistics', +'Stylesheet': 'Stylesheet', +'submit': 'submit', +'Support': 'Support', +'Sure you want to delete this object?': 'Biztos törli ezt az objektumot?', 'Table': 'tábla', +'Table name': 'Table name', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.', +'The Core': 'The Core', +'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s', +'The Views': 'The Views', +'This App': 'This App', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', +'Timestamp': 'Timestamp', +'Twitter': 'Twitter', 'unable to parse csv file': 'nem lehet a csv fájlt beolvasni', +'Update:': 'Frissít:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', +'User ID': 'User ID', +'Videos': 'Videos', +'View': 'Nézet', +'Welcome %s': 'Welcome %s', +'Welcome to web2py': 'Isten hozott a web2py-ban', +'Welcome to web2py!': 'Welcome to web2py!', +'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', +'You are successfully running web2py': 'You are successfully running web2py', +'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', +'You visited the url %s': 'You visited the url %s', } diff --git a/applications/welcome/languages/it.py b/applications/welcome/languages/it.py index 90f5d3e1..516852d0 100644 --- a/applications/welcome/languages/it.py +++ b/applications/welcome/languages/it.py @@ -20,6 +20,8 @@ 'Available Databases and Tables': 'Database e tabelle disponibili', 'Buy this book': 'Buy this book', 'cache': 'cache', +'Cache': 'Cache', +'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Non può essere vuoto', 'change password': 'Cambia password', 'Check to delete': 'Seleziona per cancellare', @@ -49,6 +51,7 @@ 'Description': 'Descrizione', 'design': 'progetta', 'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', 'Documentation': 'Documentazione', "Don't know what to do?": "Don't know what to do?", @@ -90,6 +93,7 @@ 'Invalid Query': 'Richiesta (query) non valida', 'invalid request': 'richiesta non valida', 'Is Active': 'Is Active', +'Key': 'Key', 'Last name': 'Cognome', 'Layout': 'Layout', 'Layout Plugins': 'Layout Plugins', @@ -136,6 +140,7 @@ 'Query:': 'Richiesta (query):', 'Quick Examples': 'Quick Examples', 'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Cleared', 'Recipes': 'Recipes', 'Record': 'Record', @@ -154,7 +159,9 @@ 'Rows selected': 'Righe selezionate', 'Semantic': 'Semantic', 'Services': 'Services', +'Size of cache:': 'Size of cache:', 'state': 'stato', +'Statistics': 'Statistics', 'Stylesheet': 'Foglio di stile (stylesheet)', 'submit': 'submit', 'Submit': 'Submit', @@ -168,6 +175,7 @@ 'The Views': 'The Views', 'This App': 'This App', 'This is a copy of the scaffolding application': "Questa è una copia dell'applicazione di base (scaffold)", +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'Ora (timestamp)', 'too short': 'too short', 'Twitter': 'Twitter', diff --git a/applications/welcome/languages/nl.py b/applications/welcome/languages/nl.py index 33a06002..39892e52 100644 --- a/applications/welcome/languages/nl.py +++ b/applications/welcome/languages/nl.py @@ -2,6 +2,7 @@ { '!langcode!': 'nl', '!langname!': 'Nederlands', +'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN', '%(nrows)s records found': '%(nrows)s records gevonden', '%d days ago': '%d dagen geleden', '%d weeks ago': '%d weken gelden', @@ -95,7 +96,6 @@ 'customize me!': 'pas me aan!', 'data uploaded': 'data geupload', 'Database': 'Database', -'Database': 'Database', 'Database %s select': 'Database %s select', 'database administration': 'database administratie', 'Date and Time': 'Datum en Tijd', @@ -181,8 +181,8 @@ 'Introduction': 'Introductie', 'Invalid action': 'Ongeldige actie', 'Invalid email': 'Ongeldig emailadres', -'Invalid password': 'Ongeldig wachtwoord', 'invalid password': 'ongeldig wachtwoord', +'Invalid password': 'Ongeldig wachtwoord', 'Invalid Query': 'Ongeldige Query', 'invalid request': 'ongeldige request', 'invalid ticket': 'ongeldige ticket', @@ -262,8 +262,8 @@ 'Recipes': 'Recepten', 'Record': 'Record', 'record does not exist': 'record bestaat niet', -'Record id': 'Record id', 'Record ID': 'Record ID', +'Record id': 'Record id', 'register': 'registreer', 'Register': 'Registreer', 'Registration identifier': 'Registratie identifier', diff --git a/applications/welcome/languages/pl.py b/applications/welcome/languages/pl.py index a94ec312..aa1e5701 100644 --- a/applications/welcome/languages/pl.py +++ b/applications/welcome/languages/pl.py @@ -3,107 +3,169 @@ '!langcode!': 'pl', '!langname!': 'Polska', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"Uaktualnij" jest dodatkowym wyrażeniem postaci "pole1=\'nowawartość\'". Nie możesz uaktualnić lub usunąć wyników z JOIN:', -'%Y-%m-%d': '%Y-%m-%d', -'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '%s %%{row} deleted': 'Wierszy usuniętych: %s', '%s %%{row} updated': 'Wierszy uaktualnionych: %s', '%s selected': '%s wybranych', +'%Y-%m-%d': '%Y-%m-%d', +'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'About': 'About', +'Access Control': 'Access Control', +'Administrative Interface': 'Administrative Interface', 'Administrative interface': 'Kliknij aby przejść do panelu administracyjnego', +'Ajax Recipes': 'Ajax Recipes', +'appadmin is disabled because insecure channel': 'administracja aplikacji wyłączona z powodu braku bezpiecznego połączenia', +'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 'Authentication': 'Uwierzytelnienie', 'Available Databases and Tables': 'Dostępne bazy danych i tabele', +'Buy this book': 'Buy this book', +'cache': 'cache', +'Cache': 'Cache', +'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Nie może być puste', 'Change Password': 'Zmień hasło', +'change password': 'change password', 'Check to delete': 'Zaznacz aby usunąć', 'Check to delete:': 'Zaznacz aby usunąć:', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'Client IP': 'IP klienta', +'Community': 'Community', +'Components and Plugins': 'Components and Plugins', 'Controller': 'Kontroler', 'Copyright': 'Copyright', 'Current request': 'Aktualne żądanie', 'Current response': 'Aktualna odpowiedź', 'Current session': 'Aktualna sesja', -'DB Model': 'Model bazy danych', -'Database': 'Baza danych', -'Delete:': 'Usuń:', -'Description': 'Opis', -'E-mail': 'Adres e-mail', -'Edit': 'Edycja', -'Edit Profile': 'Edytuj profil', -'Edit This App': 'Edytuj tę aplikację', -'Edit current record': 'Edytuj obecny rekord', -'First name': 'Imię', -'Function disabled': 'Funkcja wyłączona', -'Group ID': 'ID grupy', -'Hello World': 'Witaj Świecie', -'Import/Export': 'Importuj/eksportuj', -'Index': 'Indeks', -'Internal State': 'Stan wewnętrzny', -'Invalid Query': 'Błędne zapytanie', -'Invalid email': 'Błędny adres email', -'Last name': 'Nazwisko', -'Layout': 'Układ', -'Login': 'Zaloguj', -'Logout': 'Wyloguj', -'Lost Password': 'Przypomnij hasło', -'Main Menu': 'Menu główne', -'Menu Model': 'Model menu', -'Name': 'Nazwa', -'New Record': 'Nowy rekord', -'No databases in this application': 'Brak baz danych w tej aplikacji', -'Online examples': 'Kliknij aby przejść do interaktywnych przykładów', -'Origin': 'Źródło', -'Password': 'Hasło', -"Password fields don't match": 'Pola hasła nie są zgodne ze sobą', -'Powered by': 'Zasilane przez', -'Query:': 'Zapytanie:', -'Record ID': 'ID rekordu', -'Register': 'Zarejestruj', -'Registration key': 'Klucz rejestracji', -'Role': 'Rola', -'Rows in Table': 'Wiersze w tabeli', -'Rows selected': 'Wybrane wiersze', -'Stylesheet': 'Arkusz stylów', -'Submit': 'Wyślij', -'Sure you want to delete this object?': 'Czy na pewno chcesz usunąć ten obiekt?', -'Table name': 'Nazwa tabeli', -'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Zapytanie" jest warunkiem postaci "db.tabela1.pole1==\'wartość\'". Takie coś jak "db.tabela1.pole1==db.tabela2.pole2" oznacza SQL JOIN.', -'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s', -'Timestamp': 'Znacznik czasu', -'Update:': 'Uaktualnij:', -'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Użyj (...)&(...) jako AND, (...)|(...) jako OR oraz ~(...) jako NOT do tworzenia bardziej skomplikowanych zapytań.', -'User %(id)s Registered': 'Użytkownik %(id)s został zarejestrowany', -'User ID': 'ID użytkownika', -'Verify Password': 'Potwierdź hasło', -'View': 'Widok', -'Welcome %s': 'Welcome %s', -'Welcome to web2py': 'Witaj w web2py', -'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', -'You visited the url %s': 'You visited the url %s', -'appadmin is disabled because insecure channel': 'administracja aplikacji wyłączona z powodu braku bezpiecznego połączenia', -'cache': 'cache', -'change password': 'change password', 'customize me!': 'dostosuj mnie!', 'data uploaded': 'dane wysłane', 'Database': 'baza danych', 'Database %s select': 'wybór z bazy danych %s', 'db': 'baza danych', +'DB Model': 'Model bazy danych', +'Delete:': 'Usuń:', +'Demo': 'Demo', +'Deployment Recipes': 'Deployment Recipes', +'Description': 'Opis', 'design': 'projektuj', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Documentation': 'Documentation', +"Don't know what to do?": "Don't know what to do?", 'done!': 'zrobione!', +'Download': 'Download', +'E-mail': 'Adres e-mail', +'Edit': 'Edycja', +'Edit current record': 'Edytuj obecny rekord', 'edit profile': 'edit profile', +'Edit Profile': 'Edytuj profil', +'Edit This App': 'Edytuj tę aplikację', +'Email and SMS': 'Email and SMS', +'Errors': 'Errors', 'export as csv file': 'eksportuj jako plik csv', +'FAQ': 'FAQ', +'First name': 'Imię', +'Forms and Validators': 'Forms and Validators', +'Free Applications': 'Free Applications', +'Function disabled': 'Funkcja wyłączona', +'Group ID': 'ID grupy', +'Groups': 'Groups', +'Hello World': 'Witaj Świecie', +'Home': 'Home', +'How did you get here?': 'How did you get here?', +'import': 'import', +'Import/Export': 'Importuj/eksportuj', +'Index': 'Indeks', 'insert new': 'wstaw nowy rekord tabeli', 'insert new %s': 'wstaw nowy rekord do tabeli %s', +'Internal State': 'Stan wewnętrzny', +'Introduction': 'Introduction', +'Invalid email': 'Błędny adres email', +'Invalid Query': 'Błędne zapytanie', 'invalid request': 'Błędne żądanie', +'Key': 'Key', +'Last name': 'Nazwisko', +'Layout': 'Układ', +'Layout Plugins': 'Layout Plugins', +'Layouts': 'Layouts', +'Live Chat': 'Live Chat', 'login': 'login', +'Login': 'Zaloguj', 'logout': 'logout', +'Logout': 'Wyloguj', +'Lost Password': 'Przypomnij hasło', +'Main Menu': 'Menu główne', +'Manage Cache': 'Manage Cache', +'Menu Model': 'Model menu', +'My Sites': 'My Sites', +'Name': 'Nazwa', +'New Record': 'Nowy rekord', 'new record inserted': 'nowy rekord został wstawiony', 'next 100 rows': 'następne 100 wierszy', +'No databases in this application': 'Brak baz danych w tej aplikacji', +'Online examples': 'Kliknij aby przejść do interaktywnych przykładów', 'or import from csv file': 'lub zaimportuj z pliku csv', +'Origin': 'Źródło', +'Other Plugins': 'Other Plugins', +'Other Recipes': 'Other Recipes', +'Overview': 'Overview', +'Password': 'Hasło', +"Password fields don't match": 'Pola hasła nie są zgodne ze sobą', +'Plugins': 'Plugins', +'Powered by': 'Zasilane przez', +'Preface': 'Preface', 'previous 100 rows': 'poprzednie 100 wierszy', +'Python': 'Python', +'Query:': 'Zapytanie:', +'Quick Examples': 'Quick Examples', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'Recipes': 'Recipes', 'Record': 'rekord', 'record does not exist': 'rekord nie istnieje', +'Record ID': 'ID rekordu', 'Record id': 'id rekordu', +'Register': 'Zarejestruj', 'register': 'register', +'Registration key': 'Klucz rejestracji', +'Role': 'Rola', +'Rows in Table': 'Wiersze w tabeli', +'Rows selected': 'Wybrane wiersze', +'Semantic': 'Semantic', +'Services': 'Services', +'Size of cache:': 'Size of cache:', 'state': 'stan', +'Statistics': 'Statistics', +'Stylesheet': 'Arkusz stylów', +'submit': 'submit', +'Submit': 'Wyślij', +'Support': 'Support', +'Sure you want to delete this object?': 'Czy na pewno chcesz usunąć ten obiekt?', 'Table': 'tabela', +'Table name': 'Nazwa tabeli', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Zapytanie" jest warunkiem postaci "db.tabela1.pole1==\'wartość\'". Takie coś jak "db.tabela1.pole1==db.tabela2.pole2" oznacza SQL JOIN.', +'The Core': 'The Core', +'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s', +'The Views': 'The Views', +'This App': 'This App', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', +'Timestamp': 'Znacznik czasu', +'Twitter': 'Twitter', 'unable to parse csv file': 'nie można sparsować pliku csv', +'Update:': 'Uaktualnij:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Użyj (...)&(...) jako AND, (...)|(...) jako OR oraz ~(...) jako NOT do tworzenia bardziej skomplikowanych zapytań.', +'User %(id)s Registered': 'Użytkownik %(id)s został zarejestrowany', +'User ID': 'ID użytkownika', +'Verify Password': 'Potwierdź hasło', +'Videos': 'Videos', +'View': 'Widok', +'Welcome %s': 'Welcome %s', +'Welcome to web2py': 'Witaj w web2py', +'Welcome to web2py!': 'Welcome to web2py!', +'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', +'You are successfully running web2py': 'You are successfully running web2py', +'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', +'You visited the url %s': 'You visited the url %s', } diff --git a/applications/welcome/languages/pt-br.py b/applications/welcome/languages/pt-br.py index ecdfba3f..9e9048dc 100644 --- a/applications/welcome/languages/pt-br.py +++ b/applications/welcome/languages/pt-br.py @@ -3,39 +3,63 @@ '!langcode!': 'pt-br', '!langname!': 'Português (do Brasil)', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" é uma expressão opcional como "campo1=\'novovalor\'". Você não pode atualizar ou apagar os resultados de um JOIN', -'%Y-%m-%d': '%d-%m-%Y', -'%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S', '%s %%{row} deleted': '%s linhas apagadas', '%s %%{row} updated': '%s linhas atualizadas', '%s selected': '%s selecionado', +'%Y-%m-%d': '%d-%m-%Y', +'%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S', 'About': 'About', 'Access Control': 'Access Control', +'Administrative Interface': 'Administrative Interface', 'Administrative interface': 'Interface administrativa', 'Ajax Recipes': 'Ajax Recipes', +'appadmin is disabled because insecure channel': 'Administração desativada devido ao canal inseguro', +'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 'Available Databases and Tables': 'Bancos de dados e tabelas disponíveis', 'Buy this book': 'Buy this book', +'cache': 'cache', +'Cache': 'Cache', +'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Não pode ser vazio', +'change password': 'modificar senha', 'Check to delete': 'Marque para apagar', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'Client IP': 'Client IP', 'Community': 'Community', +'Components and Plugins': 'Components and Plugins', 'Controller': 'Controlador', 'Copyright': 'Copyright', 'Current request': 'Requisição atual', 'Current response': 'Resposta atual', 'Current session': 'Sessão atual', +'customize me!': 'Personalize-me!', +'data uploaded': 'dados enviados', +'Database': 'banco de dados', +'Database %s select': 'Selecionar banco de dados %s', +'db': 'bd', 'DB Model': 'Modelo BD', -'Database': 'Banco de dados', 'Delete:': 'Apagar:', 'Demo': 'Demo', 'Deployment Recipes': 'Deployment Recipes', 'Description': 'Description', +'design': 'design', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', 'Documentation': 'Documentation', +"Don't know what to do?": "Don't know what to do?", +'done!': 'concluído!', 'Download': 'Download', 'E-mail': 'E-mail', 'Edit': 'Editar', -'Edit This App': 'Edit This App', 'Edit current record': 'Editar o registro atual', +'edit profile': 'editar perfil', +'Edit This App': 'Edit This App', +'Email and SMS': 'Email and SMS', 'Errors': 'Errors', +'export as csv file': 'exportar como um arquivo csv', 'FAQ': 'FAQ', 'First name': 'First name', 'Forms and Validators': 'Forms and Validators', @@ -44,37 +68,62 @@ 'Groups': 'Groups', 'Hello World': 'Olá Mundo', 'Home': 'Home', +'How did you get here?': 'How did you get here?', +'import': 'import', 'Import/Export': 'Importar/Exportar', 'Index': 'Início', +'insert new': 'inserir novo', +'insert new %s': 'inserir novo %s', 'Internal State': 'Estado Interno', 'Introduction': 'Introduction', -'Invalid Query': 'Consulta Inválida', 'Invalid email': 'Invalid email', +'Invalid Query': 'Consulta Inválida', +'invalid request': 'requisição inválida', +'Key': 'Key', 'Last name': 'Last name', 'Layout': 'Layout', +'Layout Plugins': 'Layout Plugins', 'Layouts': 'Layouts', 'Live chat': 'Live chat', +'Live Chat': 'Live Chat', +'login': 'Entrar', 'Login': 'Autentique-se', +'logout': 'Sair', 'Lost Password': 'Esqueceu sua senha?', +'lost password?': 'lost password?', 'Main Menu': 'Menu Principal', +'Manage Cache': 'Manage Cache', 'Menu Model': 'Modelo de Menu', +'My Sites': 'My Sites', 'Name': 'Name', 'New Record': 'Novo Registro', +'new record inserted': 'novo registro inserido', +'next 100 rows': 'próximas 100 linhas', 'No databases in this application': 'Sem bancos de dados nesta aplicação', 'Online examples': 'Alguns exemplos', +'or import from csv file': 'ou importar de um arquivo csv', 'Origin': 'Origin', +'Other Plugins': 'Other Plugins', 'Other Recipes': 'Other Recipes', 'Overview': 'Overview', 'Password': 'Password', 'Plugins': 'Plugins', 'Powered by': 'Powered by', 'Preface': 'Preface', +'previous 100 rows': '100 linhas anteriores', 'Python': 'Python', 'Query:': 'Consulta:', 'Quick Examples': 'Quick Examples', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', 'Recipes': 'Recipes', +'Record': 'registro', +'record does not exist': 'registro não existe', 'Record ID': 'Record ID', +'Record id': 'id do registro', 'Register': 'Registre-se', +'register': 'Registre-se', 'Registration key': 'Registration key', 'Reset Password key': 'Reset Password key', 'Resources': 'Resources', @@ -83,18 +132,25 @@ 'Rows selected': 'Linhas selecionadas', 'Semantic': 'Semantic', 'Services': 'Services', +'Size of cache:': 'Size of cache:', +'state': 'estado', +'Statistics': 'Statistics', 'Stylesheet': 'Stylesheet', +'submit': 'submit', 'Support': 'Support', 'Sure you want to delete this object?': 'Está certo(a) que deseja apagar esse objeto ?', +'Table': 'tabela', 'Table name': 'Table name', 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'Uma "consulta" é uma condição como "db.tabela1.campo1==\'valor\'". Expressões como "db.tabela1.campo1==db.tabela2.campo2" resultam em um JOIN SQL.', 'The Core': 'The Core', -'The Views': 'The Views', 'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s', +'The Views': 'The Views', 'This App': 'This App', 'This is a copy of the scaffolding application': 'This is a copy of the scaffolding application', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'Timestamp', 'Twitter': 'Twitter', +'unable to parse csv file': 'não foi possível analisar arquivo csv', 'Update:': 'Atualizar:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) para AND, (...)|(...) para OR, e ~(...) para NOT para construir consultas mais complexas.', 'User ID': 'User ID', @@ -105,38 +161,10 @@ 'Welcome': 'Welcome', 'Welcome %s': 'Vem vindo %s', 'Welcome to web2py': 'Bem vindo ao web2py', +'Welcome to web2py!': 'Welcome to web2py!', 'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', 'You are successfully running web2py': 'You are successfully running web2py', 'You are successfully running web2py.': 'You are successfully running web2py.', 'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', 'You visited the url %s': 'You visited the url %s', -'appadmin is disabled because insecure channel': 'Administração desativada devido ao canal inseguro', -'cache': 'cache', -'change password': 'modificar senha', -'customize me!': 'Personalize-me!', -'data uploaded': 'dados enviados', -'Database': 'banco de dados', -'Database %s select': 'Selecionar banco de dados %s', -'db': 'bd', -'design': 'design', -'done!': 'concluído!', -'edit profile': 'editar perfil', -'export as csv file': 'exportar como um arquivo csv', -'insert new': 'inserir novo', -'insert new %s': 'inserir novo %s', -'invalid request': 'requisição inválida', -'login': 'Entrar', -'logout': 'Sair', -'lost password?': 'lost password?', -'new record inserted': 'novo registro inserido', -'next 100 rows': 'próximas 100 linhas', -'or import from csv file': 'ou importar de um arquivo csv', -'previous 100 rows': '100 linhas anteriores', -'Record': 'registro', -'record does not exist': 'registro não existe', -'Record id': 'id do registro', -'register': 'Registre-se', -'state': 'estado', -'Table': 'tabela', -'unable to parse csv file': 'não foi possível analisar arquivo csv', } diff --git a/applications/welcome/languages/pt.py b/applications/welcome/languages/pt.py index 8b0c633f..8d36be6f 100644 --- a/applications/welcome/languages/pt.py +++ b/applications/welcome/languages/pt.py @@ -3,119 +3,182 @@ '!langcode!': 'pt', '!langname!': 'Português', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" é uma expressão opcional como "field1=\'newvalue\'". Não pode actualizar ou eliminar os resultados de um JOIN', -'%Y-%m-%d': '%Y-%m-%d', -'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '%s %%{row} deleted': '%s linhas eliminadas', '%s %%{row} updated': '%s linhas actualizadas', '%s selected': '%s seleccionado(s)', +'%Y-%m-%d': '%Y-%m-%d', +'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', 'About': 'About', +'Access Control': 'Access Control', +'Administrative Interface': 'Administrative Interface', 'Administrative interface': 'Painel administrativo', +'Ajax Recipes': 'Ajax Recipes', +'appadmin is disabled because insecure channel': 'appadmin está desactivada pois o canal é inseguro', +'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 'Author Reference Auth User': 'Author Reference Auth User', 'Author Reference Auth User.username': 'Author Reference Auth User.username', 'Available Databases and Tables': 'bases de dados e tabelas disponíveis', +'Buy this book': 'Buy this book', +'cache': 'cache', +'Cache': 'Cache', +'Cache Keys': 'Cache Keys', 'Cannot be empty': 'não pode ser vazio', 'Category Create': 'Category Create', 'Category Select': 'Category Select', +'change password': 'alterar palavra-chave', 'Check to delete': 'seleccione para eliminar', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'Comment Create': 'Comment Create', 'Comment Select': 'Comment Select', +'Community': 'Community', +'Components and Plugins': 'Components and Plugins', 'Content': 'Content', 'Controller': 'Controlador', 'Copyright': 'Direitos de cópia', +'create new category': 'create new category', +'create new comment': 'create new comment', +'create new post': 'create new post', 'Created By': 'Created By', 'Created On': 'Created On', 'Current request': 'pedido currente', 'Current response': 'resposta currente', 'Current session': 'sessão currente', -'DB Model': 'Modelo de BD', -'Database': 'Base de dados', -'Delete:': 'Eliminar:', -'Edit': 'Editar', -'Edit This App': 'Edite esta aplicação', -'Edit current record': 'Edição de registo currente', -'Email': 'Email', -'First Name': 'First Name', -'For %s #%s': 'For %s #%s', -'Hello World': 'Olá Mundo', -'Import/Export': 'Importar/Exportar', -'Index': 'Índice', -'Internal State': 'Estado interno', -'Invalid Query': 'Consulta Inválida', -'Last Name': 'Last Name', -'Layout': 'Esboço', -'Main Menu': 'Menu Principal', -'Menu Model': 'Menu do Modelo', -'Modified By': 'Modified By', -'Modified On': 'Modified On', -'Name': 'Name', -'New Record': 'Novo Registo', -'No Data': 'No Data', -'No databases in this application': 'Não há bases de dados nesta aplicação', -'Online examples': 'Exemplos online', -'Password': 'Password', -'Post Create': 'Post Create', -'Post Select': 'Post Select', -'Powered by': 'Suportado por', -'Query:': 'Interrogação:', -'Replyto Reference Post': 'Replyto Reference Post', -'Rows in Table': 'Linhas numa tabela', -'Rows selected': 'Linhas seleccionadas', -'Stylesheet': 'Folha de estilo', -'Sure you want to delete this object?': 'Tem a certeza que deseja eliminar este objecto?', -'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'A "query" é uma condição do tipo "db.table1.field1==\'value\'". Algo como "db.table1.field1==db.table2.field2" resultaria num SQL JOIN.', -'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s', -'Title': 'Title', -'Update:': 'Actualização:', -'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Utilize (...)&(...) para AND, (...)|(...) para OR, e ~(...) para NOT para construir interrogações mais complexas.', -'Username': 'Username', -'View': 'Vista', -'Welcome %s': 'Bem-vindo(a) %s', -'Welcome to Gluonization': 'Bem vindo ao Web2py', -'Welcome to web2py': 'Bem-vindo(a) ao web2py', -'When': 'When', -'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', -'You visited the url %s': 'You visited the url %s', -'appadmin is disabled because insecure channel': 'appadmin está desactivada pois o canal é inseguro', -'cache': 'cache', -'change password': 'alterar palavra-chave', -'create new category': 'create new category', -'create new comment': 'create new comment', -'create new post': 'create new post', 'customize me!': 'Personaliza-me!', 'data uploaded': 'informação enviada', 'Database': 'base de dados', 'Database %s select': 'selecção de base de dados %s', 'db': 'bd', +'DB Model': 'Modelo de BD', +'Delete:': 'Eliminar:', +'Demo': 'Demo', +'Deployment Recipes': 'Deployment Recipes', 'design': 'design', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Documentation': 'Documentation', +"Don't know what to do?": "Don't know what to do?", 'done!': 'concluído!', +'Download': 'Download', +'Edit': 'Editar', 'edit category': 'edit category', 'edit comment': 'edit comment', +'Edit current record': 'Edição de registo currente', 'edit post': 'edit post', 'edit profile': 'Editar perfil', +'Edit This App': 'Edite esta aplicação', +'Email': 'Email', +'Email and SMS': 'Email and SMS', +'Errors': 'Errors', 'export as csv file': 'exportar como ficheiro csv', +'FAQ': 'FAQ', +'First Name': 'First Name', +'For %s #%s': 'For %s #%s', +'Forms and Validators': 'Forms and Validators', +'Free Applications': 'Free Applications', +'Groups': 'Groups', +'Hello World': 'Olá Mundo', +'Home': 'Home', +'How did you get here?': 'How did you get here?', +'import': 'import', +'Import/Export': 'Importar/Exportar', +'Index': 'Índice', 'insert new': 'inserir novo', 'insert new %s': 'inserir novo %s', +'Internal State': 'Estado interno', +'Introduction': 'Introduction', +'Invalid Query': 'Consulta Inválida', 'invalid request': 'Pedido Inválido', +'Key': 'Key', +'Last Name': 'Last Name', +'Layout': 'Esboço', +'Layout Plugins': 'Layout Plugins', +'Layouts': 'Layouts', +'Live Chat': 'Live Chat', 'login': 'login', 'logout': 'logout', +'Lost Password': 'Lost Password', +'Main Menu': 'Menu Principal', +'Manage Cache': 'Manage Cache', +'Menu Model': 'Menu do Modelo', +'Modified By': 'Modified By', +'Modified On': 'Modified On', +'My Sites': 'My Sites', +'Name': 'Name', +'New Record': 'Novo Registo', 'new record inserted': 'novo registo inserido', 'next 100 rows': 'próximas 100 linhas', +'No Data': 'No Data', +'No databases in this application': 'Não há bases de dados nesta aplicação', +'Online examples': 'Exemplos online', 'or import from csv file': 'ou importe a partir de ficheiro csv', +'Other Plugins': 'Other Plugins', +'Other Recipes': 'Other Recipes', +'Overview': 'Overview', +'Password': 'Password', +'Plugins': 'Plugins', +'Post Create': 'Post Create', +'Post Select': 'Post Select', +'Powered by': 'Suportado por', +'Preface': 'Preface', 'previous 100 rows': '100 linhas anteriores', +'Python': 'Python', +'Query:': 'Interrogação:', +'Quick Examples': 'Quick Examples', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'Recipes': 'Recipes', 'Record': 'registo', 'record does not exist': 'registo inexistente', 'Record id': 'id de registo', +'Register': 'Register', 'register': 'register', +'Replyto Reference Post': 'Replyto Reference Post', +'Rows in Table': 'Linhas numa tabela', +'Rows selected': 'Linhas seleccionadas', 'search category': 'search category', 'search comment': 'search comment', 'search post': 'search post', 'select category': 'select category', 'select comment': 'select comment', 'select post': 'select post', +'Semantic': 'Semantic', +'Services': 'Services', 'show category': 'show category', 'show comment': 'show comment', 'show post': 'show post', +'Size of cache:': 'Size of cache:', 'state': 'estado', +'Statistics': 'Statistics', +'Stylesheet': 'Folha de estilo', +'submit': 'submit', +'Support': 'Support', +'Sure you want to delete this object?': 'Tem a certeza que deseja eliminar este objecto?', 'Table': 'tabela', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'A "query" é uma condição do tipo "db.table1.field1==\'value\'". Algo como "db.table1.field1==db.table2.field2" resultaria num SQL JOIN.', +'The Core': 'The Core', +'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s', +'The Views': 'The Views', +'This App': 'This App', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', +'Title': 'Title', +'Twitter': 'Twitter', 'unable to parse csv file': 'não foi possível carregar ficheiro csv', +'Update:': 'Actualização:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Utilize (...)&(...) para AND, (...)|(...) para OR, e ~(...) para NOT para construir interrogações mais complexas.', +'Username': 'Username', +'Videos': 'Videos', +'View': 'Vista', +'Welcome %s': 'Bem-vindo(a) %s', +'Welcome to Gluonization': 'Bem vindo ao Web2py', +'Welcome to web2py': 'Bem-vindo(a) ao web2py', +'Welcome to web2py!': 'Welcome to web2py!', +'When': 'When', +'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', +'You are successfully running web2py': 'You are successfully running web2py', +'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', +'You visited the url %s': 'You visited the url %s', } diff --git a/applications/welcome/languages/ro.py b/applications/welcome/languages/ro.py index 1352c26e..0f830e3d 100644 --- a/applications/welcome/languages/ro.py +++ b/applications/welcome/languages/ro.py @@ -56,6 +56,7 @@ 'Available Databases and Tables': 'Baze de date și tabele disponibile', 'Back': 'Înapoi', 'Buy this book': 'Cumpără această carte', +'Cache': 'Cache', 'cache': 'cache', 'Cache Keys': 'Chei cache', 'cache, errors and sessions cleaned': 'cache, erori și sesiuni golite', @@ -70,6 +71,9 @@ 'Check to delete': 'Coșați pentru a șterge', 'clean': 'golire', 'Clear': 'Golește', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'click to check for upgrades': 'Clic pentru a verifica dacă există upgrade-uri', 'Client IP': 'IP client', 'Community': 'Comunitate', @@ -91,7 +95,6 @@ 'currently saved or': 'în prezent salvat sau', 'customize me!': 'Personalizează-mă!', 'data uploaded': 'date încărcate', -'Database': 'Baza de date', 'Database': 'bază de date', 'Database %s select': 'selectare bază de date %s', 'database administration': 'administrare bază de date', @@ -110,7 +113,9 @@ 'design': 'design', 'DESIGN': 'DESIGN', 'Design for': 'Design pentru', +'DISK': 'DISK', 'Disk Cache Keys': 'Chei cache de disc', +'Disk Cleared': 'Disk Cleared', 'Documentation': 'Documentație', "Don't know what to do?": 'Nu știți ce să faceți?', 'done!': 'gata!', @@ -164,6 +169,7 @@ 'Home': 'Acasă', 'How did you get here?': 'Cum ați ajuns aici?', 'htmledit': 'editare html', +'import': 'import', 'Import/Export': 'Import/Export', 'includes': 'include', 'Index': 'Index', @@ -180,6 +186,7 @@ 'Invalid Query': 'Interogare invalidă', 'invalid request': 'cerere invalidă', 'invalid ticket': 'tichet invalid', +'Key': 'Key', 'language file "%(filename)s" created/updated': 'fișier de limbă "%(filename)s" creat/actualizat', 'Language files (static strings) updated': 'Fișierele de limbă (șirurile statice de caractere) actualizate', 'languages': 'limbi', @@ -203,6 +210,7 @@ 'Lost Password': 'Parolă pierdută', 'Lost password?': 'Parolă pierdută?', 'Main Menu': 'Meniu principal', +'Manage Cache': 'Manage Cache', 'Menu Model': 'Model meniu', 'merge': 'unește', 'Models': 'Modele', @@ -245,12 +253,14 @@ 'Query': 'Interogare', 'Query:': 'Interogare:', 'Quick Examples': 'Exemple rapide', +'RAM': 'RAM', 'RAM Cache Keys': 'Chei cache RAM', +'Ram Cleared': 'Ram Cleared', 'Recipes': 'Rețete', 'Record': 'înregistrare', 'record does not exist': 'înregistrare inexistentă', -'Record id': 'id înregistrare', 'Record ID': 'ID înregistrare', +'Record id': 'id înregistrare', 'register': 'înregistrare', 'Register': 'Înregistrare', 'Registration identifier': 'Identificator de autentificare', @@ -275,13 +285,16 @@ 'session expired': 'sesiune expirată', 'shell': 'line de commandă', 'site': 'site', +'Size of cache:': 'Size of cache:', 'some files could not be removed': 'anumite fișiere n-au putut fi șterse', 'starts with': 'începe cu', 'state': 'stare', 'static': 'static', 'Static files': 'Fișiere statice', +'Statistics': 'Statistics', 'Stylesheet': 'Foaie de stiluri', 'Submit': 'Înregistrează', +'submit': 'submit', 'Support': 'Suport', 'Sure you want to delete this object?': 'Sigur ștergeți acest obiect?', 'Table': 'tabel', @@ -306,6 +319,7 @@ 'This is a copy of the scaffolding application': 'Aceasta este o copie a aplicației schelet', 'This is the %(filename)s template': 'Aceasta este șablonul fișierului %(filename)s', 'Ticket': 'Tichet', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'Moment în timp (timestamp)', 'to previous version.': 'la versiunea anterioară.', 'too short': 'prea scurt', diff --git a/applications/welcome/languages/ru.py b/applications/welcome/languages/ru.py index ce632207..85644ea2 100644 --- a/applications/welcome/languages/ru.py +++ b/applications/welcome/languages/ru.py @@ -27,14 +27,20 @@ 'Administrative Interface': 'Administrative Interface', 'Administrative interface': 'административный интерфейс', 'Ajax Recipes': 'Ajax Recipes', +'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', 'Are you sure you want to delete this object?': 'Вы уверены, что хотите удалить этот объект?', 'Available Databases and Tables': 'Базы данных и таблицы', 'Buy this book': 'Buy this book', 'cache': 'cache', +'Cache': 'Cache', +'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Пустое значение недопустимо', 'Change Password': 'Смените пароль', 'Check to delete': 'Удалить', 'Check to delete:': 'Удалить:', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'Client IP': 'Client IP', 'Community': 'Community', 'Components and Plugins': 'Components and Plugins', @@ -45,7 +51,6 @@ 'Current session': 'Текущая сессия', 'customize me!': 'настройте внешний вид!', 'data uploaded': 'данные загружены', -'Database': 'база данных', 'Database': 'Database', 'Database %s select': 'выбор базы данных %s', 'db': 'БД', @@ -55,6 +60,9 @@ 'Deployment Recipes': 'Deployment Recipes', 'Description': 'Описание', 'design': 'дизайн', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', 'Documentation': 'Documentation', "Don't know what to do?": "Don't know what to do?", 'done!': 'готово!', @@ -86,6 +94,7 @@ 'Invalid password': 'Неверный пароль', 'Invalid Query': 'Неверный запрос', 'invalid request': 'неверный запрос', +'Key': 'Key', 'Last name': 'Фамилия', 'Layout': 'Layout', 'Layout Plugins': 'Layout Plugins', @@ -99,6 +108,7 @@ 'Logout': 'Выход', 'Lost Password': 'Забыли пароль?', 'Lost password?': 'Lost password?', +'Manage Cache': 'Manage Cache', 'Menu Model': 'Menu Model', 'My Sites': 'My Sites', 'Name': 'Name', @@ -116,8 +126,8 @@ 'Other Plugins': 'Other Plugins', 'Other Recipes': 'Other Recipes', 'Overview': 'Overview', -'password': 'пароль', 'Password': 'Пароль', +'password': 'пароль', "Password fields don't match": 'Пароли не совпадают', 'Plugins': 'Plugins', 'Powered by': 'Powered by', @@ -127,10 +137,14 @@ 'Python': 'Python', 'Query:': 'Запрос:', 'Quick Examples': 'Quick Examples', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', 'Recipes': 'Recipes', +'Record': 'Record', 'record does not exist': 'запись не найдена', -'Record id': 'id записи', 'Record ID': 'ID записи', +'Record id': 'id записи', 'Register': 'Зарегистрироваться', 'Registration identifier': 'Registration identifier', 'Registration key': 'Ключ регистрации', @@ -141,8 +155,11 @@ 'Rows selected': 'Выделено строк', 'Semantic': 'Semantic', 'Services': 'Services', +'Size of cache:': 'Size of cache:', 'state': 'состояние', +'Statistics': 'Statistics', 'Stylesheet': 'Stylesheet', +'submit': 'submit', 'Submit': 'Отправить', 'Support': 'Support', 'Sure you want to delete this object?': 'Подтвердите удаление объекта', @@ -153,6 +170,7 @@ 'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s', 'The Views': 'The Views', 'This App': 'This App', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'Отметка времени', 'Twitter': 'Twitter', 'unable to parse csv file': 'нечитаемый csv-файл', diff --git a/applications/welcome/languages/sk.py b/applications/welcome/languages/sk.py index 34d34e63..88f8343f 100644 --- a/applications/welcome/languages/sk.py +++ b/applications/welcome/languages/sk.py @@ -3,69 +3,154 @@ '!langcode!': 'sk', '!langname!': 'Slovenský', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" je voliteľný výraz ako "field1=\'newvalue\'". Nemôžete upravovať alebo zmazať výsledky JOINu', -'%Y-%m-%d': '%d.%m.%Y', -'%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S', '%s %%{row} deleted': '%s zmazaných záznamov', '%s %%{row} updated': '%s upravených záznamov', '%s selected': '%s označených', +'%Y-%m-%d': '%d.%m.%Y', +'%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S', +'About': 'About', +'Access Control': 'Access Control', +'Administrative Interface': 'Administrative Interface', 'Administrative interface': 'pre administrátorské rozhranie kliknite sem', +'Ajax Recipes': 'Ajax Recipes', +'appadmin is disabled because insecure channel': 'appadmin je zakázaný bez zabezpečeného spojenia', +'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 'Available Databases and Tables': 'Dostupné databázy a tabuľky', +'Buy this book': 'Buy this book', +'cache': 'cache', +'Cache': 'Cache', +'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Nemôže byť prázdne', 'Check to delete': 'Označiť na zmazanie', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', +'Community': 'Community', +'Components and Plugins': 'Components and Plugins', 'Controller': 'Controller', 'Copyright': 'Copyright', 'Current request': 'Aktuálna požiadavka', 'Current response': 'Aktuálna odpoveď', 'Current session': 'Aktuálne sedenie', +'customize me!': 'prispôsob ma!', +'data uploaded': 'údaje naplnené', +'Database': 'databáza', +'Database %s select': 'databáza %s výber', +'db': 'db', 'DB Model': 'DB Model', -'Database': 'Databáza', 'Delete:': 'Zmazať:', +'Demo': 'Demo', +'Deployment Recipes': 'Deployment Recipes', 'Description': 'Popis', +'design': 'návrh', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', 'Documentation': 'Dokumentácia', +"Don't know what to do?": "Don't know what to do?", +'done!': 'hotovo!', +'Download': 'Download', 'Edit': 'Upraviť', -'Edit Profile': 'Upraviť profil', 'Edit current record': 'Upraviť aktuálny záznam', +'Edit Profile': 'Upraviť profil', +'Email and SMS': 'Email and SMS', +'Errors': 'Errors', +'export as csv file': 'exportovať do csv súboru', +'FAQ': 'FAQ', 'First name': 'Krstné meno', +'Forms and Validators': 'Forms and Validators', +'Free Applications': 'Free Applications', 'Group ID': 'ID skupiny', +'Groups': 'Groups', 'Hello World': 'Ahoj svet', +'Home': 'Home', +'How did you get here?': 'How did you get here?', +'import': 'import', 'Import/Export': 'Import/Export', 'Index': 'Index', +'insert new': 'vložiť nový záznam ', +'insert new %s': 'vložiť nový záznam %s', 'Internal State': 'Vnútorný stav', -'Invalid Query': 'Neplatná otázka', +'Introduction': 'Introduction', 'Invalid email': 'Neplatný email', 'Invalid password': 'Nesprávne heslo', +'Invalid Query': 'Neplatná otázka', +'invalid request': 'Neplatná požiadavka', +'Key': 'Key', 'Last name': 'Priezvisko', 'Layout': 'Layout', +'Layout Plugins': 'Layout Plugins', +'Layouts': 'Layouts', +'Live Chat': 'Live Chat', 'Logged in': 'Prihlásený', 'Logged out': 'Odhlásený', +'login': 'prihlásiť', +'logout': 'odhlásiť', 'Lost Password': 'Stratené heslo?', +'lost password?': 'stratené heslo?', +'Manage Cache': 'Manage Cache', 'Menu Model': 'Menu Model', +'My Sites': 'My Sites', 'Name': 'Meno', -'New Record': 'Nový záznam', 'New password': 'Nové heslo', +'New Record': 'Nový záznam', +'new record inserted': 'nový záznam bol vložený', +'next 100 rows': 'ďalších 100 riadkov', 'No databases in this application': 'V tejto aplikácii nie sú databázy', 'Old password': 'Staré heslo', 'Online examples': 'pre online príklady kliknite sem', +'or import from csv file': 'alebo naimportovať z csv súboru', 'Origin': 'Pôvod', +'Other Plugins': 'Other Plugins', +'Other Recipes': 'Other Recipes', +'Overview': 'Overview', +'password': 'heslo', 'Password': 'Heslo', +'Plugins': 'Plugins', 'Powered by': 'Powered by', +'Preface': 'Preface', +'previous 100 rows': 'predchádzajúcich 100 riadkov', +'Python': 'Python', 'Query:': 'Otázka:', +'Quick Examples': 'Quick Examples', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'Recipes': 'Recipes', +'Record': 'záznam', +'record does not exist': 'záznam neexistuje', 'Record ID': 'ID záznamu', +'Record id': 'id záznamu', 'Register': 'Zaregistrovať sa', +'register': 'registrovať', 'Registration key': 'Registračný kľúč', 'Remember me (for 30 days)': 'Zapamätaj si ma (na 30 dní)', 'Reset Password key': 'Nastaviť registračný kľúč', 'Role': 'Rola', 'Rows in Table': 'riadkov v tabuľke', 'Rows selected': 'označených riadkov', +'Semantic': 'Semantic', +'Services': 'Services', +'Size of cache:': 'Size of cache:', +'state': 'stav', +'Statistics': 'Statistics', 'Stylesheet': 'Stylesheet', +'submit': 'submit', 'Submit': 'Odoslať', +'Support': 'Support', 'Sure you want to delete this object?': 'Ste si istí, že chcete zmazať tento objekt?', +'Table': 'tabuľka', 'Table name': 'Názov tabuľky', 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"query" je podmienka ako "db.table1.field1==\'value\'". Niečo ako "db.table1.field1==db.table2.field2" má za výsledok SQL JOIN.', +'The Core': 'The Core', 'The output of the file is a dictionary that was rendered by the view %s': 'Výstup zo súboru je slovník, ktorý bol zobrazený vo view %s', +'The Views': 'The Views', +'This App': 'This App', 'This is a copy of the scaffolding application': 'Toto je kópia skeletu aplikácie', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'Časová pečiatka', +'Twitter': 'Twitter', +'unable to parse csv file': 'nedá sa načítať csv súbor', 'Update:': 'Upraviť:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Použite (...)&(...) pre AND, (...)|(...) pre OR a ~(...) pre NOT na poskladanie komplexnejších otázok.', 'User %(id)s Logged-in': 'Používateľ %(id)s prihlásený', @@ -75,38 +160,12 @@ 'User %(id)s Registered': 'Používateľ %(id)s sa zaregistroval', 'User ID': 'ID používateľa', 'Verify Password': 'Zopakujte heslo', +'Videos': 'Videos', 'View': 'Zobraziť', 'Welcome to web2py': 'Vitajte vo web2py', +'Welcome to web2py!': 'Welcome to web2py!', 'Which called the function %s located in the file %s': 'Ktorý zavolal funkciu %s nachádzajúci sa v súbore %s', 'You are successfully running web2py': 'Úspešne ste spustili web2py', 'You can modify this application and adapt it to your needs': 'Môžete upraviť túto aplikáciu a prispôsobiť ju svojim potrebám', 'You visited the url %s': 'Navštívili ste URL %s', -'appadmin is disabled because insecure channel': 'appadmin je zakázaný bez zabezpečeného spojenia', -'cache': 'cache', -'customize me!': 'prispôsob ma!', -'data uploaded': 'údaje naplnené', -'Database': 'databáza', -'Database %s select': 'databáza %s výber', -'db': 'db', -'design': 'návrh', -'done!': 'hotovo!', -'export as csv file': 'exportovať do csv súboru', -'insert new': 'vložiť nový záznam ', -'insert new %s': 'vložiť nový záznam %s', -'invalid request': 'Neplatná požiadavka', -'login': 'prihlásiť', -'logout': 'odhlásiť', -'lost password?': 'stratené heslo?', -'new record inserted': 'nový záznam bol vložený', -'next 100 rows': 'ďalších 100 riadkov', -'or import from csv file': 'alebo naimportovať z csv súboru', -'password': 'heslo', -'previous 100 rows': 'predchádzajúcich 100 riadkov', -'Record': 'záznam', -'record does not exist': 'záznam neexistuje', -'Record id': 'id záznamu', -'register': 'registrovať', -'state': 'stav', -'Table': 'tabuľka', -'unable to parse csv file': 'nedá sa načítať csv súbor', } diff --git a/applications/welcome/languages/uk.py b/applications/welcome/languages/uk.py index 4561f5cd..453745c9 100644 --- a/applications/welcome/languages/uk.py +++ b/applications/welcome/languages/uk.py @@ -53,12 +53,13 @@ 'Components and Plugins': 'Компоненти та втулки', 'Controller': 'Контролер', 'Copyright': 'Правовласник', +'Created By': 'Створив(ла)', +'Created On': 'Створено в', 'Current request': 'Поточний запит (current request)', 'Current response': 'Поточна відповідь (current response)', 'Current session': 'Поточна сесія (current session)', 'customize me!': 'причепуріть мене!', 'data uploaded': 'дані завантажено', -'Database': 'база даних', 'Database': 'База даних', 'Database %s select': 'Вибірка з бази даних %s', 'db': 'база даних', @@ -108,6 +109,7 @@ 'Invalid password': 'Невірний пароль', 'Invalid Query': 'Помилковий запит', 'invalid request': 'хибний запит', +'Is Active': 'Активна', 'Key': 'Ключ', 'Last name': 'Прізвище', 'Layout': 'Макет (Layout)', @@ -122,6 +124,8 @@ 'Lost password?': 'Забули пароль?', 'Manage Cache': 'Управління кешем', 'Menu Model': 'Модель меню', +'Modified By': 'Зміни провадив(ла)', +'Modified On': 'Змінено в', 'My Sites': 'Сайт (усі додатки)', 'Name': "Ім'я", 'New password': 'Новий пароль', @@ -160,8 +164,8 @@ 'Record': 'запис', 'Record %(id)s updated': 'Запис %(id)s змінено', 'record does not exist': 'запису не існує', -'Record id': 'ід. запису', 'Record ID': 'Ід.запису', +'Record id': 'ід. запису', 'Record Updated': 'Запис змінено', 'Register': 'Реєстрація', 'Registration identifier': 'Реєстраційний ідентифікатор', @@ -180,7 +184,7 @@ 'state': 'стан', 'Statistics': 'Статистика', 'Stylesheet': 'CSS-стилі', -'submit': 'submit', +'submit': 'застосувати', 'Submit': 'Застосувати', 'Support': 'Підтримка', 'Table': 'Таблиця', diff --git a/applications/welcome/languages/zh.py b/applications/welcome/languages/zh.py index 30c8a575..8d62a30e 100644 --- a/applications/welcome/languages/zh.py +++ b/applications/welcome/languages/zh.py @@ -3,34 +3,50 @@ '!langcode!': 'zh-cn', '!langname!': '中文', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"更新" 是選擇性的條件式, 格式就像 "欄位1=\'值\'". 但是 JOIN 的資料不可以使用 update 或是 delete"', -'%Y-%m-%d': '%Y-%m-%d', -'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '%s %%{row} deleted': '已刪除 %s 筆', '%s %%{row} updated': '已更新 %s 筆', '%s selected': '%s 已選擇', +'%Y-%m-%d': '%Y-%m-%d', +'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '(something like "it-it")': '(格式類似 "zh-tw")', 'A new version of web2py is available': '新版的 web2py 已發行', 'A new version of web2py is available: %s': '新版的 web2py 已發行: %s', +'about': '關於', +'About': '關於', +'About application': '關於本應用程式', +'Access Control': 'Access Control', +'Admin is disabled because insecure channel': '管理功能(Admin)在不安全連線環境下自動關閉', +'Admin is disabled because unsecure channel': '管理功能(Admin)在不安全連線環境下自動關閉', +'Administrative Interface': 'Administrative Interface', +'Administrative interface': '點此處進入管理介面', +'Administrator Password:': '管理員密碼:', +'Ajax Recipes': 'Ajax Recipes', +'appadmin is disabled because insecure channel': '因為來自非安全通道,管理介面關閉', +'Are you sure you want to delete file "%s"?': '確定要刪除檔案"%s"?', +'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', +'Are you sure you want to uninstall application "%s"': '確定要移除應用程式 "%s"', +'Are you sure you want to uninstall application "%s"?': '確定要移除應用程式 "%s"', 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': '注意: 登入管理帳號需要安全連線(HTTPS)或是在本機連線(localhost).', 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': '注意: 因為在測試模式不保證多執行緒安全性,也就是說不可以同時執行多個測試案例', 'ATTENTION: you cannot edit the running application!': '注意:不可編輯正在執行的應用程式!', -'About': '關於', -'About application': '關於本應用程式', -'Admin is disabled because insecure channel': '管理功能(Admin)在不安全連線環境下自動關閉', -'Admin is disabled because unsecure channel': '管理功能(Admin)在不安全連線環境下自動關閉', -'Administrative interface': '點此處進入管理介面', -'Administrator Password:': '管理員密碼:', -'Are you sure you want to delete file "%s"?': '確定要刪除檔案"%s"?', -'Are you sure you want to uninstall application "%s"': '確定要移除應用程式 "%s"', -'Are you sure you want to uninstall application "%s"?': '確定要移除應用程式 "%s"', 'Authentication': '驗證', 'Available Databases and Tables': '可提供的資料庫和資料表', +'Buy this book': 'Buy this book', +'cache': '快取記憶體', +'Cache': 'Cache', +'Cache Keys': 'Cache Keys', 'Cannot be empty': '不可空白', 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': '無法編譯:應用程式中含有錯誤,請除錯後再試一次.', 'Change Password': '變更密碼', +'change password': '變更密碼', 'Check to delete': '打勾代表刪除', 'Check to delete:': '點選以示刪除:', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'Client IP': '客戶端網址(IP)', +'Community': 'Community', +'Components and Plugins': 'Components and Plugins', 'Controller': '控件', 'Controllers': '控件', 'Copyright': '版權所有', @@ -38,64 +54,120 @@ 'Current request': '目前網路資料要求(request)', 'Current response': '目前網路資料回應(response)', 'Current session': '目前網路連線資訊(session)', -'DB Model': '資料庫模組', -'DESIGN': '設計', +'customize me!': '請調整我!', +'data uploaded': '資料已上傳', 'Database': '資料庫', +'Database %s select': '已選擇 %s 資料庫', 'Date and Time': '日期和時間', +'db': 'db', +'DB Model': '資料庫模組', 'Delete': '刪除', 'Delete:': '刪除:', +'Demo': 'Demo', 'Deploy on Google App Engine': '配置到 Google App Engine', +'Deployment Recipes': 'Deployment Recipes', 'Description': '描述', +'DESIGN': '設計', +'design': '設計', 'Design for': '設計為了', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Documentation': 'Documentation', +"Don't know what to do?": "Don't know what to do?", +'done!': '完成!', +'Download': 'Download', 'E-mail': '電子郵件', 'EDIT': '編輯', 'Edit': '編輯', -'Edit Profile': '編輯設定檔', -'Edit This App': '編輯本應用程式', 'Edit application': '編輯應用程式', 'Edit current record': '編輯當前紀錄', +'edit profile': '編輯設定檔', +'Edit Profile': '編輯設定檔', +'Edit This App': '編輯本應用程式', 'Editing file': '編輯檔案', 'Editing file "%s"': '編輯檔案"%s"', +'Email and SMS': 'Email and SMS', 'Error logs for "%(app)s"': '"%(app)s"的錯誤紀錄', +'Errors': 'Errors', +'export as csv file': '以逗號分隔檔(csv)格式匯出', +'FAQ': 'FAQ', 'First name': '名', +'Forms and Validators': 'Forms and Validators', +'Free Applications': 'Free Applications', 'Functions with no doctests will result in [passed] tests.': '沒有 doctests 的函式會顯示 [passed].', 'Group ID': '群組編號', +'Groups': 'Groups', 'Hello World': '嗨! 世界', +'Home': 'Home', +'How did you get here?': 'How did you get here?', +'import': 'import', 'Import/Export': '匯入/匯出', 'Index': '索引', +'insert new': '插入新資料', +'insert new %s': '插入新資料 %s', 'Installed applications': '已安裝應用程式', 'Internal State': '內部狀態', -'Invalid Query': '不合法的查詢', +'Introduction': 'Introduction', 'Invalid action': '不合法的動作(action)', 'Invalid email': '不合法的電子郵件', +'Invalid Query': '不合法的查詢', +'invalid request': '不合法的網路要求(request)', +'Key': 'Key', 'Language files (static strings) updated': '語言檔已更新', 'Languages': '各國語言', 'Last name': '姓', 'Last saved on:': '最後儲存時間:', 'Layout': '網頁配置', +'Layout Plugins': 'Layout Plugins', +'Layouts': 'Layouts', 'License for': '軟體版權為', +'Live Chat': 'Live Chat', +'login': '登入', 'Login': '登入', 'Login to the Administrative Interface': '登入到管理員介面', +'logout': '登出', 'Logout': '登出', 'Lost Password': '密碼遺忘', 'Main Menu': '主選單', +'Manage Cache': 'Manage Cache', 'Menu Model': '選單模組(menu)', 'Models': '資料模組', 'Modules': '程式模組', -'NO': '否', +'My Sites': 'My Sites', 'Name': '名字', 'New Record': '新紀錄', +'new record inserted': '已插入新紀錄', +'next 100 rows': '往後 100 筆', +'NO': '否', 'No databases in this application': '這應用程式不含資料庫', 'Online examples': '點此處進入線上範例', +'or import from csv file': '或是從逗號分隔檔(CSV)匯入', 'Origin': '原文', 'Original/Translation': '原文/翻譯', +'Other Plugins': 'Other Plugins', +'Other Recipes': 'Other Recipes', +'Overview': 'Overview', 'Password': '密碼', "Password fields don't match": '密碼欄不匹配', 'Peeking at file': '選擇檔案', +'Plugins': 'Plugins', 'Powered by': '基於以下技術構建:', +'Preface': 'Preface', +'previous 100 rows': '往前 100 筆', +'Python': 'Python', 'Query:': '查詢:', +'Quick Examples': 'Quick Examples', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'Recipes': 'Recipes', +'Record': '紀錄', +'record does not exist': '紀錄不存在', 'Record ID': '紀錄編號', +'Record id': '紀錄編號', 'Register': '註冊', +'register': '註冊', 'Registration key': '註冊金鑰', 'Remember me (for 30 days)': '記住我(30 天)', 'Reset Password key': '重設密碼', @@ -104,26 +176,40 @@ 'Rows in Table': '在資料表裏的資料', 'Rows selected': '筆資料被選擇', 'Saved file hash:': '檔案雜湊值已紀錄:', +'Semantic': 'Semantic', +'Services': 'Services', +'Size of cache:': 'Size of cache:', +'state': '狀態', 'Static files': '靜態檔案', +'Statistics': 'Statistics', 'Stylesheet': '網頁風格檔', +'submit': 'submit', 'Submit': '傳送', +'Support': 'Support', 'Sure you want to delete this object?': '確定要刪除此物件?', +'Table': '資料表', 'Table name': '資料表名稱', 'Testing application': '測試中的應用程式', 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"查詢"是一個像 "db.表1.欄位1==\'值\'" 的條件式. 以"db.表1.欄位1==db.表2.欄位2"方式則相當於執行 JOIN SQL.', +'The Core': 'The Core', 'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s', +'The Views': 'The Views', 'There are no controllers': '沒有控件(controllers)', 'There are no models': '沒有資料庫模組(models)', 'There are no modules': '沒有程式模組(modules)', 'There are no static files': '沒有靜態檔案', 'There are no translators, only default language is supported': '沒有翻譯檔,只支援原始語言', 'There are no views': '沒有視圖', +'This App': 'This App', 'This is the %(filename)s template': '這是%(filename)s檔案的樣板(template)', 'Ticket': '問題單', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': '時間標記', +'Twitter': 'Twitter', 'Unable to check for upgrades': '無法做升級檢查', 'Unable to download': '無法下載', 'Unable to download app': '無法下載應用程式', +'unable to parse csv file': '無法解析逗號分隔檔(csv)', 'Update:': '更新:', 'Upload existing application': '更新存在的應用程式', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': '使用下列方式來組合更複雜的條件式, (...)&(...) 代表同時存在的條件, (...)|(...) 代表擇一的條件, ~(...)則代表反向條件.', @@ -131,40 +217,15 @@ 'User %(id)s Registered': '使用者 %(id)s 已註冊', 'User ID': '使用者編號', 'Verify Password': '驗證密碼', +'Videos': 'Videos', 'View': '視圖', 'Views': '視圖', 'Welcome %s': '歡迎 %s', 'Welcome to web2py': '歡迎使用 web2py', +'Welcome to web2py!': 'Welcome to web2py!', 'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', 'YES': '是', +'You are successfully running web2py': 'You are successfully running web2py', +'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', 'You visited the url %s': 'You visited the url %s', -'about': '關於', -'appadmin is disabled because insecure channel': '因為來自非安全通道,管理介面關閉', -'cache': '快取記憶體', -'change password': '變更密碼', -'customize me!': '請調整我!', -'data uploaded': '資料已上傳', -'Database': '資料庫', -'Database %s select': '已選擇 %s 資料庫', -'db': 'db', -'design': '設計', -'done!': '完成!', -'edit profile': '編輯設定檔', -'export as csv file': '以逗號分隔檔(csv)格式匯出', -'insert new': '插入新資料', -'insert new %s': '插入新資料 %s', -'invalid request': '不合法的網路要求(request)', -'login': '登入', -'logout': '登出', -'new record inserted': '已插入新紀錄', -'next 100 rows': '往後 100 筆', -'or import from csv file': '或是從逗號分隔檔(CSV)匯入', -'previous 100 rows': '往前 100 筆', -'Record': '紀錄', -'record does not exist': '紀錄不存在', -'Record id': '紀錄編號', -'register': '註冊', -'state': '狀態', -'Table': '資料表', -'unable to parse csv file': '無法解析逗號分隔檔(csv)', } diff --git a/gluon/cfs.py b/gluon/cfs.py index d40737b3..358540ca 100644 --- a/gluon/cfs.py +++ b/gluon/cfs.py @@ -12,7 +12,7 @@ Functions required to execute app components FOR INTERNAL USE ONLY """ -import os +from os import stat import thread import logging from fileutils import read_file @@ -35,7 +35,7 @@ def getcfs(key, filename, filter=None): This is used on Google App Engine since pyc files cannot be saved. """ try: - t = os.stat(filename).st_mtime + t = stat(filename).st_mtime except OSError: return filter() if callable(filter) else '' cfs_lock.acquire() diff --git a/gluon/languages.py b/gluon/languages.py index 95be43b6..8c0361f4 100644 --- a/gluon/languages.py +++ b/gluon/languages.py @@ -29,15 +29,16 @@ from string import maketrans __all__ = ['translator', 'findT', 'update_all_languages'] -ospath = os.path ostat = os.stat -osep = os.sep +oslistdir = os.listdir pjoin = os.path.join +pexists = os.path.exists pdirname = os.path.dirname isdir = os.path.isdir is_gae = settings.global_settings.web2py_runtime_gae DEFAULT_LANGUAGE = 'en' +DEFAULT_LANGUAGE_NAME = 'English' # DEFAULT PLURAL-FORMS RULES: # language doesn't use plural forms @@ -45,23 +46,7 @@ DEFAULT_NPLURALS = 1 # only one singular/plural form is used DEFAULT_GET_PLURAL_ID = lambda n: 0 # word is unchangeable -DEFAULT_CONSTRUCTOR_PLURAL_FORM = lambda word, plural_id: word - -def safe_eval(text): - if text.strip(): - try: - import ast - return ast.literal_eval(text) - except ImportError: - return eval(text,{},{}) - return None - -# used as default filter in translator.M() -def markmin_aux(m): - return '{%s}' % markmin_escape(m.group('s')) -def markmin(s): - return render(regex_param.sub(markmin_aux,s), - sep='br', autolinks=None, id_prefix='') +DEFAULT_CONSTRUCT_PLURAL_FORM = lambda word, plural_id: word NUMBERS = (int,long,float) @@ -75,14 +60,30 @@ regex_translate = re.compile(PY_STRING_LITERAL_RE, re.DOTALL) regex_param=re.compile(r'{(?P.+?)}') # pattern for a valid accept_language - regex_language = \ - re.compile('^([a-zA-Z]{2})(\-[a-zA-Z]{2})?(\-[a-zA-Z]+)?$') -regex_langfile = re.compile('^[a-zA-Z]{2}(-[a-zA-Z]{2})?\.py$') + re.compile('([a-z]{2}(?:\-[a-z]{2})?(?:\-[a-z]{2})?)(?:[,;]|$)') +regex_langfile = re.compile('^[a-z]{2}(-[a-z]{2})?\.py$') regex_backslash = re.compile(r"\\([\\{}%])") regex_plural = re.compile('%({.+?})') regex_plural_dict = re.compile('^{(?P[^()[\]][^()[\]]*?)\((?P[^()\[\]]+)\)}$') # %%{word(varname or number)} regex_plural_tuple = re.compile('^{(?P[^[\]()]+)(?:\[(?P\d+)\])?}$') # %%{word[index]} or %%{word} +regex_plural_file = re.compile('^plural-[a-zA-Z]{2}(-[a-zA-Z]{2})?\.py$') + +def safe_eval(text): + if text.strip(): + try: + import ast + return ast.literal_eval(text) + except ImportError: + return eval(text,{},{}) + return None + +# used as default filter in translator.M() +def markmin(s): + def markmin_aux(m): + return '{%s}' % markmin_escape(m.group('s')) + return render(regex_param.sub(markmin_aux,s), + sep='br', autolinks=None, id_prefix='') # UTF8 helper functions def upper_fun(s): @@ -90,7 +91,7 @@ def upper_fun(s): def title_fun(s): return unicode(s,'utf-8').title().encode('utf-8') def cap_fun(s): - return lambda s: unicode(s,'utf-8').capitalize().encode('utf-8') + return unicode(s,'utf-8').capitalize().encode('utf-8') ttab_in = maketrans("\\%{}", '\x1c\x1d\x1e\x1f') ttab_out = maketrans('\x1c\x1d\x1e\x1f', "\\%{}") @@ -132,38 +133,6 @@ def clear_cache(filename): finally: lock.release() -def lang_sampling(lang_tuple, langlist): - """ - search *lang_tuple* in *langlist* - - Args: - lang_tuple (tuple of strings): ('aa'[[,'-bb'],'-cc']) - langlist (list of strings): [available languages] - - Returns: - language from langlist or None - """ - # step 1: - # compare "aa-bb-cc" | "aa-bb" | "aa" from lang_tuple - # with strings from langlist. Return appropriate string - # from langlist: - tries = range(len(lang_tuple),0,-1) - for i in tries: - language="".join(lang_tuple[:i]) - if language in langlist: - return language - # step 2 (if not found in step 1): - # compare "aa-bb-cc" | "aa-bb" | "aa" from lang_tuple - # with left part of a string from langlist. Return - # appropriate string from langlist - for i in tries: - lang="".join(lang_tuple[:i]) - for language in langlist: - if language.startswith(lang): - return language - return None - - def read_dict_aux(filename): lang_text = portalocker.read_locked(filename).replace('\r\n', '\n') clear_cache(filename) @@ -175,57 +144,24 @@ def read_dict_aux(filename): return {'__corrupted__':status} def read_dict(filename): - """ - return dictionary with translation messages + """ return dictionary with translation messages """ return getcfs('lang:'+filename, filename, lambda: read_dict_aux(filename)) -def get_lang_info(lang, langdir): - """ - retrieve lang information from *langdir*/*lang*.py file. - Read few strings from lang.py file until keys !langname!, - !langcode! or keys greater then '!*' were found - - args: - lang (str): lang-code or 'default' - langdir (str): path to 'languages' directory in web2py app dir - - returns: - tuple(langcode, langname, langfile_mtime) - e.g.: ('en', 'English', 1338549043.0) - """ - filename = ospath.join(langdir, lang+'.py') - d = read_dict(filename) - langcode = d.get('!langcode!',DEFAULT_LANGUAGE) - langname = d.get('!langname!',langcode) - return (langcode, langname or langcode, ostat(filename).st_mtime) - -def read_possible_languages(appdir): - langs = {} - # scan languages directory for langfiles: - langdir = ospath.join(appdir,'languages') - for filename in os.listdir(langdir): - if regex_langfile.match(filename) or filename=='default.py': - lang = filename[:-3] - langs[lang] = get_lang_info(lang, langdir) - if not 'en' in langs: - # if default.py is not found, add default value: - langs['en'] = ('en', 'English', 0) - return langs - -def read_possible_plurals(): +def read_possible_plural_rules(): """ create list of all possible plural rules files - result is cached to increase speed + result is cached in PLURAL_RULES dictionary to increase speed """ - plurals = {} try: - import contrib.plural_rules as package + import gluon.contrib.plural_rules as package + plurals = {} for importer, modname, ispkg in pkgutil.iter_modules(package.__path__): if len(modname)==2: - module = __import__(package.__name__+'.'+modname) + module = __import__(package.__name__+'.'+modname, + fromlist=[modname]) lang = modname pname = modname+'.py' nplurals = getattr(module,'nplurals', DEFAULT_NPLURALS) @@ -234,19 +170,84 @@ def read_possible_plurals(): DEFAULT_GET_PLURAL_ID) construct_plural_form = getattr( module,'construct_plural_form', - DEFAULT_CONSTRUCTOR_PLURAL_FORM) + DEFAULT_CONSTRUCT_PLURAL_FORM) plurals[lang] = (lang, nplurals, get_plural_id, - construct_plural_form, pname) - except ImportError: - logging.warn('Unable to import plural rules') - plurals['default'] = ('default', - DEFAULT_NPLURALS, - DEFAULT_GET_PLURAL_ID, - DEFAULT_CONSTRUCTOR_PLURAL_FORM, - None) + construct_plural_form) + except ImportError, e: + logging.warn('Unable to import plural rules: %s' % e) return plurals -PLURAL_RULES = read_possible_plurals() +PLURAL_RULES = read_possible_plural_rules() + +def read_possible_languages_aux(langdir): + def get_lang_struct(lang, langcode, langname, langfile_mtime): + if lang == 'default': + real_lang = langcode.lower() + else: + real_lang = lang + (prules_langcode, + nplurals, + get_plural_id, + construct_plural_form + ) = PLURAL_RULES.get(real_lang[:2],('default', + DEFAULT_NPLURALS, + DEFAULT_GET_PLURAL_ID, + DEFAULT_CONSTRUCT_PLURAL_FORM)) + if prules_langcode != 'default': + (pluraldict_fname, + pluraldict_mtime) = plurals.get(real_lang, + plurals.get(real_lang[:2], + ('plural-%s.py'%real_lang,0))) + else: + pluraldict_fname = None + pluraldict_mtime = 0 + return (langcode, # language code from !langcode! + langname, # language name in national spelling from !langname! + langfile_mtime, # m_time of language file + pluraldict_fname,# name of plural dictionary file or None (when default.py is not exist) + pluraldict_mtime,# m_time of plural dictionary file or 0 if file is not exist + prules_langcode, # code of plural rules language or 'default' + nplurals, # nplurals for current language + get_plural_id, # get_plural_id() for current language + construct_plural_form) # construct_plural_form() for current language + + plurals = {} + flist = oslistdir(langdir) + # scan languages directory for plural dict files: + for pname in flist: + if regex_plural_file.match(pname): + plurals[pname[7:-3]] = (pname, + ostat(pjoin(langdir,pname)).st_mtime) + langs = {} + # scan languages directory for langfiles: + for fname in flist: + if regex_langfile.match(fname) or fname == 'default.py': + fname_with_path = pjoin(langdir,fname) + d = read_dict(fname_with_path) + lang = fname[:-3] + langcode = d.get('!langcode!', lang if lang != 'default' + else DEFAULT_LANGUAGE) + langname = d.get('!langname!',langcode) + langfile_mtime = ostat(fname_with_path).st_mtime + langs[lang] = get_lang_struct(lang, langcode, + langname, langfile_mtime) + if 'default' not in langs: + # if default.py is not found, + # add DEFAULT_LANGUAGE as default language: + langs['default'] = get_lang_struct('default', DEFAULT_LANGUAGE, + DEFAULT_LANGUAGE_NAME, 0) + deflang = langs['default'] + deflangcode = deflang[0] + if deflangcode not in langs: + # create language from default.py: + langs[deflangcode] = deflang[:2]+(0,)+deflang[3:] + + return langs + +def read_possible_languages(appdir): + langdir = pjoin(appdir,'languages') + return getcfs('langs:'+langdir, langdir, + lambda: read_possible_languages_aux(langdir)) def read_plural_dict_aux(filename): lang_text = portalocker.read_locked(filename).replace('\r\n', '\n') @@ -401,42 +402,81 @@ class translator(object): T(\"Hello World\") # translates \"Hello World\" using the selected file notice 1: there is no need to force since, by default, T uses - http_accept_language to determine a translation file. + http_accept_language to determine a translation file. notice 2: en and en-en are considered different languages! notice 3: if language xx-yy is not found force() probes other similar - languages using such algorithm: + languages using such algorithm: xx-yy.py -> xx.py -> xx-yy*.py -> xx*.py """ def __init__(self, request): self.request = request self.folder = request.folder - self.langpath = ospath.join(self.folder,'languages') - self.filenames = set(os.listdir(self.langpath)) + self.langpath = pjoin(self.folder, 'languages') self.http_accept_language = request.env.http_accept_language - # self.cache # filled in self.force() - # self.accepted_language = None # filled in self.force() - # self.language_file = None # filled in self.force() - # self.plural_language = None # filled in self.force() - # self.nplurals = None # filled in self.force() - # self.get_plural_id = None # filled in self.force() - # self.construct_plural_form = None # filled in self.force() - # self.plural_rules_file = None # filled in self.force() - # self.plural_file = None # filled in self.force() - # self.plural_dict = None # filled in self.force() - # self.plural_status = None # filled in self.force() - self.requested_languages = \ - self.force(self.http_accept_language) + # filled in self.force(): + #------------------------ + # self.cache + # self.accepted_language + # self.language_file + # self.plural_language + # self.nplurals + # self.get_plural_id + # self.construct_plural_form + # self.plural_file + # self.plural_dict + # self.requested_languages + #---------------------------------------- + # filled in self.set_current_languages(): + #---------------------------------------- + # self.default_language_file + # self.default_t + # self.current_languages + self.set_current_languages() self.lazy = True self.otherTs = {} self.filter = markmin self.ftag = 'markmin' + def get_possible_languages_info(self, lang=None): + """ + return info for selected language or dictionary with all + possible languages info from APP/languages/*.py + args: + *lang* (str): language + returns: + if *lang* is defined: + return tuple(langcode, langname, langfile_mtime, + pluraldict_fname, pluraldict_mtime, + prules_langcode, nplurals, + get_plural_id, construct_plural_form) + or None + + if *lang* is NOT defined: + returns dictionary with all possible languages: + { langcode(from filename): + ( langcode, # language code from !langcode! + langname, # language name in national spelling from !langname! + langfile_mtime, # m_time of language file + pluraldict_fname,# name of plural dictionary file or None (when default.py is not exist) + pluraldict_mtime,# m_time of plural dictionary file or 0 if file is not exist + prules_langcode, # code of plural rules language or 'default' + nplurals, # nplurals for current language + get_plural_id, # get_plural_id() for current language + construct_plural_form) # construct_plural_form() for current language + } + """ + info = read_possible_languages(self.folder) + if lang: info = info.get(lang) + return info + def get_possible_languages(self): - return [lang[:-3] for lang in self.filenames \ - if regex_langfile.match(lang)] + """ get list of all possible languages for current applications """ + return list(set(self.current_languages + + [lang for lang in read_possible_languages(self.folder).iterkeys() + if lang != 'default'])) def set_current_languages(self, *languages): """ @@ -447,38 +487,30 @@ class translator(object): if len(languages) == 1 and isinstance( languages[0], (tuple, list)): languages = languages[0] - self.current_languages = languages + if not languages or languages[0] is None: + # set default language from default.py/DEFAULT_LANGUAGE + pl_info = self.get_possible_languages_info('default') + if pl_info[2]==0: # langfile_mtime + # if languages/default.py is not found + self.default_language_file = self.langpath + self.default_t = {} + self.current_languages = [DEFAULT_LANGUAGE] + else: + self.default_language_file = pjoin(self.langpath, + 'default.py') + self.default_t = read_dict(self.default_language_file) + self.current_languages = [pl_info[0]] # !langcode! + else: + self.current_languages = list(languages) self.force(self.http_accept_language) - def set_plural(self, language): - """ - initialize plural forms subsystem - invoked from self.force() - """ - lang = language[:2] - (self.plural_language, - self.nplurals, - self.get_plural_id, - self.construct_plural_form, - self.plural_filename - ) = PLURAL_RULES.get(language,PLURAL_RULES['default']) - for lang in (language, language[:5], language[:2]): - filename = 'plural-%s.py' % lang - if filename in self.filenames: - self.plural_file = ospath.join(self.langpath,filename) - self.plural_dict = read_plural_dict(self.plural_file) - break - else: - self.plural_file = None - self.plural_dict = {} - + def plural(self, word, n): - """ - get plural form of word for number *n* - NOTE: *word* MUST be defined in current language + """ get plural form of word for number *n* + NOTE: *word" MUST be defined in current language (T.accepted_language) - invoked from T()/M() in %%{} tag + invoked from T()/T.M() in %%{} tag args: word (str): word in singular n (numeric): number plural form created for @@ -486,51 +518,34 @@ class translator(object): returns: (str): word in appropriate singular/plural form """ - nplurals = self.nplurals - if int(n)==1: + if int(n) == 1: return word elif word: id = self.get_plural_id(abs(int(n))) - # id = 0 first plural form - # id = 1 second plural form + # id = 0 singular form + # id = 1 first plural form + # id = 2 second plural form # etc. - forms = self.plural_dict.get(word, []) - if len(forms)>=id: - # have this plural form - return forms[id-1] - else: - # guessing this plural form - forms += ['']*(nplurals-len(forms)-1) - form = self.construct_plural_form(word, id) - forms[id-1] = form - self.plural_dict[word] = forms - if self.plural_file and not is_gae: - write_plural_dict(self.plural_file, - self.plural_dict) - return form - - def get_possible_languages_info(self, lang=None): - """ - return info for selected language or dictionary with all - possible languages info from APP/languages/*.py - args: - *lang* (str): language - returns: - if *lang* is defined: - return tuple(langcode, langname, langfile_mtime) or None - - if *lang* is NOT defined: - returns dictionary with all possible languages: - { langcode(from filename): ( langcode(from !langcode! key), - langname(from !langname! key), - langfile_mtime ) } - """ - info = read_possible_languages(self.folder) - if lang: info = info.get(lang) - return info + if id != 0: + forms = self.plural_dict.get(word, []) + if len(forms)>=id: + # have this plural form: + return forms[id-1] + else: + # guessing this plural form + forms += ['']*(self.nplurals-len(forms)-1) + form = self.construct_plural_form(word, id) + forms[id-1] = form + self.plural_dict[word] = forms + if self.plural_file and not is_gae: + write_plural_dict(self.plural_file, + self.plural_dict) + return form + return word def force(self, *languages): """ + select language(s) for translation if a list of languages is passed as a parameter, @@ -541,41 +556,76 @@ class translator(object): default language will be selected if none of them matches possible_languages. """ + pl_info = read_possible_languages(self.folder) + def set_plural(language): + """ + initialize plural forms subsystem + """ + lang_info = pl_info.get(language) + if lang_info: + (pname, + pmtime, + self.plural_language, + self.nplurals, + self.get_plural_id, + self.construct_plural_form + ) = lang_info[3:] + pdict = {} + if pname: + pname = pjoin(self.langpath, pname) + if pmtime != 0: + pdict = read_plural_dict(pname) + self.plural_file = pname + self.plural_dict = pdict + else: + self.plural_language = 'default' + self.nplurals = DEFAULT_NPLURALS + self.get_plural_id = DEFAULT_GET_PLURAL_ID + self.construct_plural_form = DEFAULT_CONSTRUCT_PLURAL_FORM + self.plural_file = None + self.plural_dict = {} language = '' - if isinstance(languages,str): - languages = regex_language.findall(languages.lower()) + if len(languages)==1 and isinstance(languages[0],str): + languages = regex_language.findall(languages[0].lower()) elif not languages or languages[0] is None: languages = [] - for lang in languages: - if lang+'.py' in self.filenames: - language = lang - langfile = language+'.py' - break - elif len(lang)>5 and lang[:5]+'.py' in self.filenames: - language = lang[:5] - langfile = language+'.py' - break - elif len(lang)>2 and lang[:2]+'.py' in self.filenames: - language = lang[:2] - langfile = language+'.py' - break - else: - if 'default.py' in self.filenames: - language = DEFAULT_LANGUAGE - langfile = 'default.py' - else: - language = DEFAULT_LANGUAGE - langfile = None - self.accepted_language = language - if langfile: - self.language_file = ospath.join(self.langpath,langfile) - self.t = read_dict(self.language_file) - else: - self.language_file = None - self.t = {} - self.cache = global_language_cache.setdefault( - self.language_file,({},allocate_lock())) - self.set_plural(language) + self.requested_languages = languages = tuple(languages) + if languages: + all_languages = set(lang for lang in pl_info.iterkeys() + if lang != 'default') \ + | set(self.current_languages) + for lang in languages: + # compare "aa-bb" | "aa" from *language* parameter + # with strings from langlist using such alghorythm: + # xx-yy.py -> xx.py -> xx*.py + lang5 = lang[:5] + if lang5 in all_languages: + language = lang5 + else: + lang2 = lang[:2] + if len(lang5)>2 and lang2 in all_languages: + language = lang2 + else: + for l in all_languages: + if l[:2]==lang2: + language = l + if language: + if language in self.current_languages: + break + self.language_file = pjoin(self.langpath, language+'.py') + self.t = read_dict(self.language_file) + self.cache = global_language_cache.setdefault( + self.language_file, + ({},allocate_lock())) + set_plural(language) + self.accepted_language = language + return languages + self.accepted_language = language or self.current_languages[0] + self.language_file = self.default_language_file + self.cache = global_language_cache.setdefault(self.language_file, + ({}, allocate_lock())) + self.t = self.default_t + set_plural(self.accepted_language) return languages def __call__(self, message, symbols={}, language=None, lazy=None): @@ -661,20 +711,18 @@ class translator(object): """ key = prefix+message mt = self.t.get(key, None) - if mt is None: - # we did not find a translation - if message.find('##')>0 and not '\n' in message: - # remove comments - message = message.rsplit('##', 1)[0] - # guess translation same as original - self.t[key] = mt = message - # update language file for later translation - if self.language_file and not is_gae: - write_dict(self.language_file, self.t) - # fix backslash escaping - mt = regex_backslash.sub( - lambda m: m.group(1).translate(ttab_in), mt) - return mt + if mt is not None: return mt + # we did not find a translation + if message.find('##')>0 and not '\n' in message: + # remove comments + message = message.rsplit('##', 1)[0] + # guess translation same as original + self.t[key] = mt = self.default_t.get(key, message) + # update language file for latter translation + if self.language_file != self.default_language_file and not is_gae: + write_dict(self.language_file, self.t) + return regex_backslash.sub( + lambda m: m.group(1).translate(ttab_in), mt) def params_substitution(self, message, symbols): """ @@ -796,16 +844,16 @@ class translator(object): message = self.params_substitution(message, symbols) return message.translate(ttab_out) -def findT(path, language='en'): +def findT(path, language=DEFAULT_LANGUAGE): """ must be run by the admin app """ - lang_file = ospath.join(path, 'languages', language + '.py') + lang_file = pjoin(path, 'languages', language + '.py') sentences = read_dict(lang_file) - mp = ospath.join(path, 'models') - cp = ospath.join(path, 'controllers') - vp = ospath.join(path, 'views') - mop = ospath.join(path, 'modules') + mp = pjoin(path, 'models') + cp = pjoin(path, 'controllers') + vp = pjoin(path, 'views') + mop = pjoin(path, 'modules') for filename in \ listdir(mp, '^.+\.py$', 0)+listdir(cp, '^.+\.py$', 0)\ +listdir(vp, '^.+\.html$', 0)+listdir(mop, '^.+\.py$', 0): @@ -827,10 +875,10 @@ def findT(path, language='en'): sentences[message] = message if not '!langcode!' in sentences: sentences['!langcode!'] = ( - 'en' if language in ('default', 'en') else language) + DEFAULT_LANGUAGE if language in ('default', DEFAULT_LANGUAGE) else language) if not '!langname!' in sentences: sentences['!langname!'] = ( - 'English' if language in ('default', 'en') + DEFAULT_LANGUAGE_NAME if language in ('default', DEFAULT_LANGUAGE) else sentences['!langcode!']) write_dict(lang_file, sentences) @@ -843,9 +891,10 @@ copy_reg.pickle(lazyT, lazyT_pickle, lazyT_unpickle) def update_all_languages(application_path): - path = ospath.join(application_path, 'languages/') - for language in listdir(path, regex_langfile): - findT(application_path, language[:-3]) + path = pjoin(application_path, 'languages/') + for language in oslistdir(path): + if regex_langfile.match(language): + findT(application_path, language[:-3]) if __name__ == '__main__': From 2c509a7bc48d8742ec9ed12b68f85ede65d3ff62 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 11 Sep 2012 14:02:55 -0500 Subject: [PATCH 15/80] removed headers from response.stream --- VERSION | 2 +- gluon/globals.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index c6d062b9..228b57df 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-11 13:37:13) stable +Version 2.0.8 (2012-09-11 14:02:50) stable diff --git a/gluon/globals.py b/gluon/globals.py index 56a3d437..66051be3 100644 --- a/gluon/globals.py +++ b/gluon/globals.py @@ -279,7 +279,6 @@ class Response(Storage): request=None, attachment=False, filename=None, - headers=None ): """ if a controller function:: @@ -299,7 +298,7 @@ class Response(Storage): default to the last request argument otherwise) """ - headers = headers if headers is not None else self.headers + headers = self.headers # for attachment settings and backward compatibility keys = [item.lower() for item in headers] if attachment: From 8f7bafb963b550949ad367d247a2a797afc2ef99 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 11 Sep 2012 14:06:44 -0500 Subject: [PATCH 16/80] yet simpler header logic, thanks Anthony and Niphlod --- VERSION | 2 +- gluon/http.py | 6 +++--- gluon/main.py | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/VERSION b/VERSION index 228b57df..3a3bb142 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-11 14:02:50) stable +Version 2.0.8 (2012-09-11 14:06:40) stable diff --git a/gluon/http.py b/gluon/http.py index 9cae6ac7..b42ec628 100644 --- a/gluon/http.py +++ b/gluon/http.py @@ -89,14 +89,14 @@ class HTTP(BaseException): status = str(status) if not regex_status.match(status): status = '500 %s' % (defined_status[500]) - if not 'Content-Type' in headers: - headers['Content-Type'] = 'text/html; charset=UTF-8' + headers.setdefault('Content-Type','text/html; charset=UTF-8') body = self.body if status[:1] == '4': if not body: body = status if isinstance(body, str): - if len(body)<512 and headers['Content-Type'].startswith('text/html'): + if len(body)<512 and \ + headers['Content-Type'].startswith('text/html'): body += '' % ('x'*512) ### trick IE headers['Content-Length'] = len(body) rheaders = [] diff --git a/gluon/main.py b/gluon/main.py index c0ef850e..1e9d02ae 100644 --- a/gluon/main.py +++ b/gluon/main.py @@ -556,8 +556,7 @@ def wsgibase(environ, responder): response.js.replace('\n',''))) for key,value in default_headers: - if not key in rheaders: - rheaders[key] = value + rheaders.setdefault(key,value) # ################################################## # store cookies in headers From 6a170f3b7bb156342a03b5b44c6d1af4697b9390 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 11 Sep 2012 16:49:30 -0500 Subject: [PATCH 17/80] more examples in routes.example.py --- VERSION | 2 +- routes.example.py | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/VERSION b/VERSION index 3a3bb142..efea121c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-11 14:06:40) stable +Version 2.0.8 (2012-09-11 16:49:24) stable diff --git a/routes.example.py b/routes.example.py index ea7a8142..e65f19ad 100644 --- a/routes.example.py +++ b/routes.example.py @@ -31,16 +31,41 @@ routes_app = ((r'/(?Pwelcome|admin|app)\b.*', r'\g'), # routes_in=( (r'/static/(?P[\w./-]+)', r'/init/static/\g') ) # -routes_in = ((r'.*:/favicon.ico', r'/examples/static/favicon.ico'), - (r'.*:/robots.txt', r'/examples/static/robots.txt'), - ((r'.*http://otherdomain.com.* (?P.*)', r'/app/ctr\g'))) +BASE = '' # optonal prefix for incoming URLs + +routes_in = ( + # do not reroute admin unless you want to disable it + (BASE+'/admin/?$anything','/admin/$anything'), + # do not reroute appadmin unless you want to disable it + (BASE+'/$app/appadmin/?$anything','/$app/appadmin/$anything'), + # do not reroute static files + (BASE+'/$app/static/?$anything','/$app/static/$anything'), + # reroute favicon and robots, use exable for lack of better choice + ('/favicon.ico', '/examples/static/favicon.ico'), + ('/robots.txt', '/examples/static/robots.txt'), + # do other stuff + ((r'.*http://otherdomain.com.* (?P.*)', r'/app/ctr\g')), + # remove the BASE prefix + (BASE+'/$anything','/$anything'), + ) # routes_out, like routes_in translates URL paths created with the web2py URL() # function in the same manner that route_in translates inbound URL paths. # -routes_out = ((r'.*http://otherdomain.com.* /app/ctr(?P.*)', r'\g'), - (r'/app(?P.*)', r'\g')) +routes_out = ( + # do not reroute admin unless you want to disable it + ('/admin/$anything', BASE+'/admin/?$anything'), + # do not reroute appadmin unless you want to disable it + ('/$app/appadmin/$anything',BASE+'/$app/appadmin/?$anything'), + # do not reroute static files + ('/$app/static/$anything', BASE+'/$app/static/?$anything'), + # do other stuff + (r'.*http://otherdomain.com.* /app/ctr(?P.*)', r'\g'), + (r'/app(?P.*)', r'\g'), + # restore the BASE prefix + ('/$anything',BASE+'/$anything'), +) # Specify log level for rewrite's debug logging # Possible values: debug, info, warning, error, critical (loglevels), From 91c0b6c76af655183d3e248be422232768380250 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 11 Sep 2012 17:32:46 -0500 Subject: [PATCH 18/80] moved deafult headers logic, thanks Niphlod --- VERSION | 2 +- gluon/main.py | 40 +++++++++++++++++----------------------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/VERSION b/VERSION index efea121c..7303aa3f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-11 16:49:24) stable +Version 2.0.8 (2012-09-11 17:32:41) stable diff --git a/gluon/main.py b/gluon/main.py index 1e9d02ae..8d470579 100644 --- a/gluon/main.py +++ b/gluon/main.py @@ -226,6 +226,20 @@ def serve_controller(request, response, session): requests = ('requests' in globals()) and (requests+1) % 100 or 0 if not requests: gc.collect() # end garbage collection logic + + # ################################################## + # set default headers it not set + # ################################################## + + default_headers = [ + ('Content-Type', contenttype('.'+request.extension)), + ('Cache-Control','no-store, no-cache, must-revalidate, post-check=0, pre-check=0'), + ('Expires', time.strftime('%a, %d %b %Y %H:%M:%S GMT', + time.gmtime())), + ('Pragma', 'no-cache')] + for key,value in default_headers: + response.headers.setdefault(key,value) + raise HTTP(response.status, page, **response.headers) @@ -496,7 +510,7 @@ def wsgibase(environ, responder): import gluon.debug # activate the debugger gluon.debug.dbg.do_debug(mainpyfile=request.folder) - + serve_controller(request, response, session) except HTTP, http_response: @@ -531,32 +545,12 @@ def wsgibase(environ, responder): # ################################################## session._try_store_on_disk(request, response) - - # ################################################## - # set default headers it not set - # ################################################## - rheaders = http_response.headers - - default_headers = [ - ('Content-Type', contenttype('.'+request.extension)), - ('Cache-Control','no-store, no-cache, must-revalidate, post-check=0, pre-check=0'), - ('Expires', time.strftime('%a, %d %b %Y %H:%M:%S GMT', - time.gmtime())), - ('Pragma', 'no-cache')] - if request.cid: if response.flash: - default_headers.append( - ('web2py-component-flash', - urllib2.quote(xmlescape(response.flash).replace('\n','')))) + http_response.headers['web2py-component-flash'] = urllib2.quote(xmlescape(response.flash).replace('\n','')) if response.js: - default_headers.append( - ('web2py-component-command', - response.js.replace('\n',''))) - - for key,value in default_headers: - rheaders.setdefault(key,value) + http_response.headers['web2py-component-command'] = response.js.replace('\n','') # ################################################## # store cookies in headers From 4b334c5117c65f611e74dd2e9733f046e344d0c5 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Wed, 12 Sep 2012 09:55:56 -0500 Subject: [PATCH 19/80] fixed minify caching problem, thanks Niphlod --- VERSION | 2 +- applications/admin/controllers/default.py | 2 +- gluon/contrib/minify/minify.py | 17 ++++++++++++----- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/VERSION b/VERSION index 7303aa3f..cb7ce0da 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-11 17:32:41) stable +Version 2.0.8 (2012-09-12 09:55:52) stable diff --git a/applications/admin/controllers/default.py b/applications/admin/controllers/default.py index cd1153c9..eb79ccea 100644 --- a/applications/admin/controllers/default.py +++ b/applications/admin/controllers/default.py @@ -20,7 +20,7 @@ try: have_git = True except ImportError: have_git = False - GIT_MISSING = 'requires python-git module, but not installed or incompatible version' + GIT_MISSING = 'requires gitpython module, but not installed or incompatible version' from gluon.languages import (read_possible_languages, read_dict, write_dict, read_plural_dict, write_plural_dict) diff --git a/gluon/contrib/minify/minify.py b/gluon/contrib/minify/minify.py index 54fe27c4..9eb1b31c 100644 --- a/gluon/contrib/minify/minify.py +++ b/gluon/contrib/minify/minify.py @@ -11,6 +11,7 @@ Modified by: Massimo Di Pierro import cssmin import jsmin import os +import hashlib def read_binary_file(filename): f = open(filename,'rb') @@ -56,6 +57,7 @@ def minify(files, path_info, folder, optimize_css, optimize_js, new_files = [] css = [] js = [] + processed = [] for k,filename in enumerate(files): if not filename.startswith('/') or \ any(filename.endswith(x) for x in ignore_concat): @@ -66,6 +68,7 @@ def minify(files, path_info, folder, optimize_css, optimize_js, filename[len(static_path)+1:]) if filename.lower().endswith('.css'): + processed.append(filename) if concat_css: contents = read_binary_file(abs_filename) if minify_css: @@ -75,6 +78,7 @@ def minify(files, path_info, folder, optimize_css, optimize_js, else: css.append(filename) elif filename.lower().endswith('.js'): + processed.append(filename) if concat_js: contents = read_binary_file(abs_filename) if minify_js and not filename.endswith('.min.js') and \ @@ -84,6 +88,7 @@ def minify(files, path_info, folder, optimize_css, optimize_js, js.append(contents) else: js.append(filename) + dest_key = hashlib.md5(repr(processed)).hexdigest() if css and concat_css: css = '\n\n'.join(contents for contents in css) if inline_css: @@ -91,12 +96,13 @@ def minify(files, path_info, folder, optimize_css, optimize_js, else: temppath = os.path.join(folder,'static',temp) if not os.path.exists(temppath): os.mkdir(temppath) - tempfile = os.path.join(temppath,'compressed.css') + dest = "compressed_%s.css" % dest_key + tempfile = os.path.join(temppath, dest) write_binary_file(tempfile,css) - css = path_info+'/compressed.css' + css = path_info+'/%s' % dest new_files.append(css) else: - new_files += css + new_files += css if js and concat_js: js = '\n'.join(contents for contents in js) if inline_js: @@ -104,9 +110,10 @@ def minify(files, path_info, folder, optimize_css, optimize_js, else: temppath = os.path.join(folder,'static',temp) if not os.path.exists(temppath): os.mkdir(temppath) - tempfile = os.path.join(folder,'static',temp,'compressed.js') + dest = "compressed_%s.js" % dest_key + tempfile = os.path.join(folder,'static',temp,dest) write_binary_file(tempfile,js) - js = path_info+'/compressed.js' + js = path_info+'/%s' % dest new_files.append(js) else: new_files += js From 39f8a18c3482ee32bc63ffbe7c45a1f38d37df73 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Wed, 12 Sep 2012 10:18:34 -0500 Subject: [PATCH 20/80] navbar dropdown, thanks Paolo --- VERSION | 2 +- applications/welcome/languages/it.py | 9 + applications/welcome/static/css/web2py.css | 1 + .../welcome/static/css/web2py_bootstrap.css | 2 + applications/welcome/views/layout.html | 355 +++++++++--------- gluon/tools.py | 40 +- 6 files changed, 224 insertions(+), 185 deletions(-) diff --git a/VERSION b/VERSION index cb7ce0da..68e0d9b8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-12 09:55:52) stable +Version 2.0.8 (2012-09-12 10:18:30) stable diff --git a/applications/welcome/languages/it.py b/applications/welcome/languages/it.py index 516852d0..ad59b34d 100644 --- a/applications/welcome/languages/it.py +++ b/applications/welcome/languages/it.py @@ -23,6 +23,7 @@ 'Cache': 'Cache', 'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Non può essere vuoto', +'Change password': 'Change password', 'change password': 'Cambia password', 'Check to delete': 'Seleziona per cancellare', 'Clear CACHE?': 'Clear CACHE?', @@ -69,6 +70,7 @@ 'export as csv file': 'esporta come file CSV', 'FAQ': 'FAQ', 'First name': 'Nome', +'Forgot username?': 'Forgot username?', 'Forms and Validators': 'Forms and Validators', 'Free Applications': 'Free Applications', 'Group %(group_id)s created': 'Group %(group_id)s created', @@ -115,6 +117,7 @@ 'Modified On': 'Modified On', 'My Sites': 'My Sites', 'Name': 'Nome', +'New password': 'New password', 'New Record': 'Nuovo elemento (record)', 'new record inserted': 'nuovo record inserito', 'next 100 rows': 'prossime 100 righe', @@ -122,6 +125,7 @@ 'Non può essere vuoto': 'Non può essere vuoto', 'not authorized': 'non autorizzato', 'Object or table name': 'Object or table name', +'Old password': 'Old password', 'Online examples': 'Vedere gli esempi', 'or import from csv file': 'oppure importa da file CSV', 'Origin': 'Origine', @@ -153,10 +157,12 @@ 'Registration key': 'Chiave di Registazione', 'Registration successful': 'Registration successful', 'Remember me (for 30 days)': 'Remember me (for 30 days)', +'Request reset password': 'Request reset password', 'Reset Password key': 'Resetta chiave Password ', 'Role': 'Ruolo', 'Rows in Table': 'Righe nella tabella', 'Rows selected': 'Righe selezionate', +'Save profile': 'Save profile', 'Semantic': 'Semantic', 'Services': 'Services', 'Size of cache:': 'Size of cache:', @@ -185,6 +191,9 @@ 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Per costruire richieste (query) più complesse si usano (...)&(...) come "e" (AND), (...)|(...) come "o" (OR), e ~(...) come negazione (NOT).', 'User %(id)s Logged-in': 'User %(id)s Logged-in', 'User %(id)s Logged-out': 'User %(id)s Logged-out', +'User %(id)s Password changed': 'User %(id)s Password changed', +'User %(id)s Password reset': 'User %(id)s Password reset', +'User %(id)s Profile updated': 'User %(id)s Profile updated', 'User %(id)s Registered': 'User %(id)s Registered', 'User ID': 'ID Utente', 'Verify Password': 'Verify Password', diff --git a/applications/welcome/static/css/web2py.css b/applications/welcome/static/css/web2py.css index be3aebf6..2a399366 100644 --- a/applications/welcome/static/css/web2py.css +++ b/applications/welcome/static/css/web2py.css @@ -107,6 +107,7 @@ div.flash { -webkit-border-radius:5px; z-index:2000; } +div.flash:hover { opacity:0.25; } div.error_wrapper {display:block} div.error { diff --git a/applications/welcome/static/css/web2py_bootstrap.css b/applications/welcome/static/css/web2py_bootstrap.css index de65e658..416cb19a 100644 --- a/applications/welcome/static/css/web2py_bootstrap.css +++ b/applications/welcome/static/css/web2py_bootstrap.css @@ -81,6 +81,8 @@ body { .ie-lte7 #navbar .auth_navbar, #navbar .auth_navbar a {color:expression(this.parentNode.currentStyle['color']); /* ie7 doesn't support inherit */} #navbar .auth_navbar a:hover {color:white;text-decoration:none;} /* this overwrite bootswatch */ +ul#navbar{padding:0;} /*reset ul padding */ +ul#navbar>.auth_navbar{display:inline-block;padding:5px;} /* set padding of span.auth_navbar inside ul*/ body { height:auto; /*to avoid vertical scroll bar*/ diff --git a/applications/welcome/views/layout.html b/applications/welcome/views/layout.html index 35532710..a0b7f584 100644 --- a/applications/welcome/views/layout.html +++ b/applications/welcome/views/layout.html @@ -1,177 +1,178 @@ - - - - - - - - - - - - - - {{=response.title or request.application}} - - - - - - - - - - - - - - - - - - {{ - response.files.append(URL('static','css/bootstrap.min.css')) - response.files.append(URL('static','css/bootstrap-responsive.min.css')) - response.files.append(URL('static','css/web2py.css')) - response.files.append(URL('static','css/web2py_bootstrap.css')) - }} - - {{include 'web2py_ajax.html'}} - - {{ - # using sidebars need to know what sidebar you want to use - left_sidebar_enabled = globals().get('left_sidebar_enabled',False) - right_sidebar_enabled = globals().get('right_sidebar_enabled',False) - middle_columns = {0:'span12',1:'span9',2:'span6'}[ - (left_sidebar_enabled and 1 or 0)+(right_sidebar_enabled and 1 or 0)] - }} - - - - {{block head}}{{end}} - - - - - - -
-
{{=response.flash or ''}}
- - - - -
-
- {{if left_sidebar_enabled:}} - - {{pass}} - -
- {{block center}} - {{include}} - {{end}} -
- - {{if right_sidebar_enabled:}} -
- {{block right_sidebar}} -

Right Sidebar

-

- {{end}} -
- {{pass}} -
-
- - -
- {{block footer}} - - {{end}} -
- -
- - - - - - {{if response.google_analytics_id:}} {{pass}} - - - + + + + + + + + + + + + + + {{=response.title or request.application}} + + + + + + + + + + + + + + + + + + {{ + response.files.append(URL('static','css/bootstrap.min.css')) + response.files.append(URL('static','css/bootstrap-responsive.min.css')) + response.files.append(URL('static','css/web2py.css')) + response.files.append(URL('static','css/web2py_bootstrap.css')) + }} + + {{include 'web2py_ajax.html'}} + + {{ + # using sidebars need to know what sidebar you want to use + left_sidebar_enabled = globals().get('left_sidebar_enabled',False) + right_sidebar_enabled = globals().get('right_sidebar_enabled',False) + middle_columns = {0:'span12',1:'span9',2:'span6'}[ + (left_sidebar_enabled and 1 or 0)+(right_sidebar_enabled and 1 or 0)] + }} + + + + {{block head}}{{end}} + + + + + + +
+
{{=response.flash or ''}}
+ + + + +
+
+ {{if left_sidebar_enabled:}} + + {{pass}} + +
+ {{block center}} + {{include}} + {{end}} +
+ + {{if right_sidebar_enabled:}} +
+ {{block right_sidebar}} +

Right Sidebar

+

+ {{end}} +
+ {{pass}} +
+
+ + +
+ {{block footer}} + + {{end}} +
+ +
+ + + + + + {{if response.google_analytics_id:}} {{pass}} + + + + diff --git a/gluon/tools.py b/gluon/tools.py index bf4503e7..cb56f25f 100644 --- a/gluon/tools.py +++ b/gluon/tools.py @@ -1208,16 +1208,17 @@ class Auth(object): def navbar(self, prefix='Welcome', action=None, separators=(' [ ',' | ',' ] '), user_identifier=DEFAULT, - referrer_actions=DEFAULT): + referrer_actions=DEFAULT, mode='default'): referrer_actions = [] if not referrer_actions else referrer_actions request = current.request + asdropdown = (mode == 'dropdown') T = current.T if isinstance(prefix, str): prefix = T(prefix) if prefix: prefix = prefix.strip() + ' ' if not action: - action=self.url(self.settings.function) + action = self.url(self.settings.function) s1,s2,s3 = separators if URL() == action: next = '' @@ -1244,11 +1245,19 @@ class Auth(object): profile = A(T('Profile'), _href=href('profile')) password = A(T('Password'), _href=href('change_password')) bar = SPAN(prefix, user_identifier, s1, logout, s3, _class='auth_navbar') + + if asdropdown: + logout = LI(A(I(_class='icon-off'), ' '+T('Logout'), _href='%s/logout?_next=%s' % + (action, urllib.quote(self.settings.logout_next)))) # the space before T('Logout') is intentional. It creates a gap between icon and text + profile = LI(A(I(_class='icon-user'), ' '+T('Profile'), _href=href('profile'))) + password = LI(A(I(_class='icon-lock'), ' '+T('Password'), _href=href('change_password'))) + bar = UL(logout,_class='dropdown-menu') # logout will be the last item in list + if not 'profile' in self.settings.actions_disabled: - bar.insert(-1, s2) + if not asdropdown: bar.insert(-1, s2) bar.insert(-1, profile) if not 'change_password' in self.settings.actions_disabled: - bar.insert(-1, s2) + if not asdropdown: bar.insert(-1, s2) bar.insert(-1, password) else: login = A(T('Login'), _href=href('login')) @@ -1259,17 +1268,34 @@ class Auth(object): T('Lost password?'), _href=href('request_reset_password')) bar = SPAN(s1, login, s3, _class='auth_navbar') + if asdropdown: + user_identifier = '' + login = LI(A(I(_class='icon-off'), ' '+T('Login'), _href=href('login'))) #the space before T('Login') is intentional. It creates a gap between icon and text + register = LI(A(I(_class='icon-user'), ' '+T('Register'), _href=href('register'))) + retrieve_username = LI(A(I(_class='icon-edit'), ' '+T('Forgot username?'), _href=href('retrieve_username'))) + lost_password = LI(A(I(_class='icon-lock'), ' '+T('Lost password?'), _href=href('request_reset_password'))) + bar = UL(login,_class='dropdown-menu') # login will be the last item in list + if not 'register' in self.settings.actions_disabled: - bar.insert(-1, s2) + if not asdropdown: bar.insert(-1, s2) bar.insert(-1, register) if self.settings.use_username and not 'retrieve_username' \ in self.settings.actions_disabled: - bar.insert(-1, s2) + if not asdropdown: bar.insert(-1, s2) bar.insert(-1, retrieve_username) if not 'request_reset_password' \ in self.settings.actions_disabled: - bar.insert(-1, s2) + if not asdropdown: bar.insert(-1, s2) bar.insert(-1, lost_password) + + if asdropdown: + bar.insert(-1, LI('',_class='divider')) + if self.user_id: + bar = LI(A(prefix, user_identifier, _href='#'), + bar,_class='dropdown') + else: + bar = LI(A(T('Login'), _href='#'), + bar,_class='dropdown') return bar def __get_migrate(self, tablename, migrate=True): From 7e61e576cdd7263c293056b3b6a20dcf14f7ed2f Mon Sep 17 00:00:00 2001 From: mdipierro Date: Wed, 12 Sep 2012 10:43:40 -0500 Subject: [PATCH 21/80] fixed span12 problem in welcome --- VERSION | 2 +- applications/welcome/views/layout.html | 30 +++++++++++++++----------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/VERSION b/VERSION index 68e0d9b8..6d441136 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-12 10:18:30) stable +Version 2.0.8 (2012-09-12 10:43:36) stable diff --git a/applications/welcome/views/layout.html b/applications/welcome/views/layout.html index a0b7f584..45e637b1 100644 --- a/applications/welcome/views/layout.html +++ b/applications/welcome/views/layout.html @@ -92,11 +92,13 @@ @@ -130,15 +132,17 @@
- {{block footer}} -
From 2f6fbb689b4ad41519b14cc66bfb8a46f1d8e00f Mon Sep 17 00:00:00 2001 From: mdipierro Date: Wed, 12 Sep 2012 11:08:32 -0500 Subject: [PATCH 22/80] fixed issue 999 removed unwanted redirect in grid --- VERSION | 2 +- gluon/sqlhtml.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 6d441136..eebaddd7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-12 10:43:36) stable +Version 2.0.8 (2012-09-12 11:08:28) stable diff --git a/gluon/sqlhtml.py b/gluon/sqlhtml.py index d5a638d7..94082f68 100644 --- a/gluon/sqlhtml.py +++ b/gluon/sqlhtml.py @@ -1664,8 +1664,9 @@ class SQLFORM(FORM): return URL(**b) referrer = session.get('_web2py_grid_referrer_'+formname, url()) - if user_signature: - if (args != request.args and user_signature and \ + if user_signature: + if ('/'.join(str(a) for a in args) != '/'.join(request.args) and \ + user_signature and \ not URL.verify(request,user_signature=user_signature)) or \ (not (session.auth and session.auth.user) and \ ('edit' in request.args or \ From 0f546e70628fa670d032c2dd8496179dddee83c9 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Wed, 12 Sep 2012 11:10:58 -0500 Subject: [PATCH 23/80] fixed issue 1000, broken GAE belongs for field id, thanks Alan --- VERSION | 2 +- gluon/dal.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index eebaddd7..ee33b75b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-12 11:08:28) stable +Version 2.0.8 (2012-09-12 11:10:55) stable diff --git a/gluon/dal.py b/gluon/dal.py index 89cae33f..83fce76e 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -4349,7 +4349,7 @@ class GoogleDatastoreAdapter(NoSQLAdapter): if first.type != 'id': return [GAEF(first.name,'in',self.represent(second,first.type),lambda a,b:a in b)] else: - second = [Key.from_path(first._tablename, i) for i in second] + second = [Key.from_path(first._tablename, int(i)) for i in second] return [GAEF(first.name,'in',second,lambda a,b:a in b)] def CONTAINS(self,first,second): From 19e19f4ec5de8fd385fd01b07e347ca9597026bd Mon Sep 17 00:00:00 2001 From: mdipierro Date: Wed, 12 Sep 2012 11:16:51 -0500 Subject: [PATCH 24/80] removed unnecessary line --- VERSION | 2 +- gluon/tools.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/VERSION b/VERSION index ee33b75b..f5afbe06 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-12 11:10:55) stable +Version 2.0.8 (2012-09-12 11:16:46) stable diff --git a/gluon/tools.py b/gluon/tools.py index cb56f25f..0213e611 100644 --- a/gluon/tools.py +++ b/gluon/tools.py @@ -1269,7 +1269,6 @@ class Auth(object): bar = SPAN(s1, login, s3, _class='auth_navbar') if asdropdown: - user_identifier = '' login = LI(A(I(_class='icon-off'), ' '+T('Login'), _href=href('login'))) #the space before T('Login') is intentional. It creates a gap between icon and text register = LI(A(I(_class='icon-user'), ' '+T('Register'), _href=href('register'))) retrieve_username = LI(A(I(_class='icon-edit'), ' '+T('Forgot username?'), _href=href('retrieve_username'))) From 7898055f0cf207a05fd96ccb40ca4d1ccc729ce8 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Wed, 12 Sep 2012 11:26:21 -0500 Subject: [PATCH 25/80] removed applications/welcome/private/auth.key --- VERSION | 2 +- applications/welcome/private/auth.key | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 applications/welcome/private/auth.key diff --git a/VERSION b/VERSION index f5afbe06..3889096d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-12 11:16:46) stable +Version 2.0.8 (2012-09-12 11:26:18) stable diff --git a/applications/welcome/private/auth.key b/applications/welcome/private/auth.key deleted file mode 100644 index cfe65bbb..00000000 --- a/applications/welcome/private/auth.key +++ /dev/null @@ -1 +0,0 @@ -sha512:e5b75f2b-4ce9-41c0-a93b-b03f0135cd2c \ No newline at end of file From 54e67932a0efb0052cce3990fdd0fe8beaa2ecf5 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Wed, 12 Sep 2012 22:53:59 -0500 Subject: [PATCH 26/80] more flexible notifications --- VERSION | 2 +- applications/welcome/static/css/web2py.css | 19 ++++++++---- .../welcome/static/css/web2py_bootstrap.css | 29 +++++++++++++++++-- applications/welcome/static/js/web2py.js | 4 +-- applications/welcome/views/layout.html | 4 +-- 5 files changed, 44 insertions(+), 14 deletions(-) diff --git a/VERSION b/VERSION index 3889096d..89ed2b8f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.8 (2012-09-12 11:26:18) stable +Version 2.0.8 (2012-09-12 22:53:52) stable diff --git a/applications/welcome/static/css/web2py.css b/applications/welcome/static/css/web2py.css index 2a399366..835828a9 100644 --- a/applications/welcome/static/css/web2py.css +++ b/applications/welcome/static/css/web2py.css @@ -95,16 +95,23 @@ div.flash { top:48px; right:50px; min-width:280px; - opacity:0.85; + opacity:0.95; margin:0px 0px 10px 10px; - color:#fff; vertical-align:middle; cursor:pointer; - background:#000; + color:#fff; + background-color:#000; border:2px solid #fff; - border-radius:5px; - -moz-border-radius:5px; - -webkit-border-radius:5px; + border-radius:8px; + -o-border-radius: 8px; + -moz-border-radius:8px; + -webkit-border-radius:8px; + background-image: -webkit-linear-gradient(top,#222,#000); + background-image: -o-linear-gradient(top,#222,#000); + background-image: linear-gradient(top,#222,#000); + background-repeat: repeat-x; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + -webkit-font-smoothing: antialiased; z-index:2000; } div.flash:hover { opacity:0.25; } diff --git a/applications/welcome/static/css/web2py_bootstrap.css b/applications/welcome/static/css/web2py_bootstrap.css index 416cb19a..f4054daa 100644 --- a/applications/welcome/static/css/web2py_bootstrap.css +++ b/applications/welcome/static/css/web2py_bootstrap.css @@ -1,8 +1,27 @@ -body { - padding-top: 60px; +#navbar .auth_navbar, #navbar .auth_navbar a {color:inherit;} + +div.flash.fcenter { + left: 25%; + right: 25%; } -#navbar .auth_navbar, #navbar .auth_navbar a {color:inherit;} +div.flash.ftop, div.flash.ftop:hover { + position: relative; + margin:0; + padding:1em; + top:0; + left:0; + width:100%; + text-align:center; + color:#3A87AD; + background:#D9EDF7; + border:1px solid #BCE8F1; + border-top:0px; + border-left:0px; + border-right:0px; + border-radius:0; + opacity:1; +} /* bootstrap dropdown */ @@ -18,6 +37,10 @@ body { visibility: visible; } +#header { + margin-top: 60px; +} + .mastheader h1 { margin-bottom: 9px; font-size: 81px; diff --git a/applications/welcome/static/js/web2py.js b/applications/welcome/static/js/web2py.js index 9a2e208c..3ec64455 100644 --- a/applications/welcome/static/js/web2py.js +++ b/applications/welcome/static/js/web2py.js @@ -39,7 +39,7 @@ function web2py_ajax_init(target) { function web2py_event_handlers() { var doc = jQuery(document) - doc.on('click', '.flash', function(e){jQuery(this).fadeOut('slow'); e.preventDefault();}); + doc.on('click', '.flash', function(e){var t=jQuery(this); if(t.css('top')=='0px') t.slideUp('slow'); else t.fadeOut(); e.preventDefault();}); doc.on('keyup', 'input.integer', function(){this.value=this.value.reverse().replace(/[^0-9\-]|\-(?=.)/g,'').reverse();}); doc.on('keyup', 'input.double, input.decimal', function(){this.value=this.value.reverse().replace(/[^0-9\-\.,]|[\-](?=.)|[\.,](?=[0-9]*[\.,])/g,'').reverse();}); var confirm_message = (typeof w2p_ajax_confirm_message != 'undefined') ? w2p_ajax_confirm_message : "Are you sure you want to delete this object?"; @@ -55,7 +55,7 @@ function web2py_event_handlers() { jQuery(function() { var flash = jQuery('.flash'); flash.hide(); - if(flash.html()) flash.slideDown(); + if(flash.html()) flash.append('×').slideDown(); web2py_ajax_init(document); web2py_event_handlers(); }); diff --git a/applications/welcome/views/layout.html b/applications/welcome/views/layout.html index 45e637b1..82af4196 100644 --- a/applications/welcome/views/layout.html +++ b/applications/welcome/views/layout.html @@ -65,6 +65,8 @@ +
{{=response.flash or ''}}
+