diff --git a/VERSION b/VERSION index a4b941d0..7bc11a3d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.00.0 (2012-05-23 09:27:57) dev +Version 2.00.0 (2012-06-05 20:02:32) dev diff --git a/applications/admin/controllers/default.py b/applications/admin/controllers/default.py index f9959b93..e3848f10 100644 --- a/applications/admin/controllers/default.py +++ b/applications/admin/controllers/default.py @@ -63,7 +63,7 @@ def get_app(name=None): if app and (not MULTI_USER_MODE or is_manager() or \ db(db.app.name==app)(db.app.owner==auth.user.id).count()): return app - session.flash = 'App does not exist or your are not authorized' + session.flash = T('App does not exist or your are not authorized') redirect(URL('site')) def index(): @@ -1108,7 +1108,7 @@ def errors(): method = request.args(1) or 'new' db_ready = {} db_ready['status'] = get_ticket_storage(app) - db_ready['errmessage'] = "No ticket_storage.txt found under /private folder" + db_ready['errmessage'] = T("No ticket_storage.txt found under /private folder") db_ready['errlink'] = "http://web2py.com/books/default/chapter/29/13#Collecting-tickets" if method == 'new': @@ -1397,7 +1397,7 @@ def reload_routes(): def manage_students(): if not (MULTI_USER_MODE and is_manager()): - session.flash = 'Not Authorized' + session.flash = T('Not Authorized') redirect(URL('site')) db.auth_user.registration_key.writable = True grid = SQLFORM.grid(db.auth_user) @@ -1405,7 +1405,7 @@ def manage_students(): def bulk_register(): if not (MULTI_USER_MODE and is_manager()): - session.flash = 'Not Authorized' + session.flash = T('Not Authorized') redirect(URL('site')) form = SQLFORM.factory(Field('emails','text')) if form.process().accepted: diff --git a/applications/admin/controllers/gae.py b/applications/admin/controllers/gae.py index 646c7733..77b2458b 100644 --- a/applications/admin/controllers/gae.py +++ b/applications/admin/controllers/gae.py @@ -37,9 +37,9 @@ def deploy(): regex = re.compile('^\w+$') apps = sorted(file for file in os.listdir(apath(r=request)) if regex.match(file)) form = SQLFORM.factory( - Field('appcfg',default=GAE_APPCFG,label='Path to appcfg.py', + Field('appcfg',default=GAE_APPCFG,label=T('Path to appcfg.py'), requires=EXISTS(error_message=T('file not found'))), - Field('google_application_id',requires=IS_ALPHANUMERIC()), + Field('google_application_id',requires=IS_ALPHANUMERIC(),label=T('Google Application Id')), Field('applications','list:string', requires=IS_IN_SET(apps,multiple=True), label=T('web2py apps to deploy')), diff --git a/applications/admin/controllers/mercurial.py b/applications/admin/controllers/mercurial.py index a91b66a6..68921342 100644 --- a/applications/admin/controllers/mercurial.py +++ b/applications/admin/controllers/mercurial.py @@ -45,7 +45,7 @@ def commit(): INPUT(_type='submit',_value='Commit')) if form.accepts(request.vars,session): oldid = repo[repo.lookup('.')] - scmutil.addremove(repo) + addremove(repo) repo.commit(text=form.vars.comment) if repo[repo.lookup('.')] == oldid: response.flash = 'no changes' diff --git a/applications/admin/controllers/wizard.py b/applications/admin/controllers/wizard.py index 4420d94a..8de9dc1a 100644 --- a/applications/admin/controllers/wizard.py +++ b/applications/admin/controllers/wizard.py @@ -166,7 +166,7 @@ def step3(): try: tables=sort_tables(session.app['tables']) except RuntimeError: - response.flash=T('invalid circual reference') + response.flash=T('invalid circular reference') else: if n': '>', +'>=': '>=', +'A new version of web2py is available': 'O nouă versiune de web2py este disponibilă', +'A new version of web2py is available: %s': 'O nouă versiune de web2py este disponibilă: %s', +'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENȚIE: Nu vă puteți conecta decât utilizând o conexiune securizată (HTTPS) sau rulând aplicația pe computerul local.', +'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENȚIE: Nu puteți efectua mai multe teste o dată deoarece lansarea în execuție a mai multor subpocese nu este sigură.', +'ATTENTION: you cannot edit the running application!': 'ATENȚIE: nu puteți edita o aplicație în curs de execuție!', +'Abort': 'Anulează', +'About': 'Despre', +'About application': 'Despre aplicație', +'Access Control': 'Control acces', +'Add': 'Adaugă', +'Additional code for your application': 'Cod suplimentar pentru aplicație', +'Admin is disabled because insecure channel': 'Adminstrarea este dezactivată deoarece conexiunea nu este sigură', +'Admin is disabled because unsecure channel': 'Administrarea este dezactivată deoarece conexiunea nu este securizată', +'Admin language': 'Limba de administrare', +'Administration': 'Administrare', +'Administrative Interface': 'Interfață administrare', +'Administrator Password:': 'Parolă administrator:', +'Ajax Recipes': 'Rețete Ajax', +'And': 'Și', +'Application name:': 'Nume aplicație:', +'Are you sure you want to delete file "%s"?': 'Sigur ștergeți fișierul "%s"?', +'Are you sure you want to delete this object?': 'Sigur ștergeți acest obiect?', +'Are you sure you want to uninstall application "%s"': 'Sigur dezinstalați aplicația "%s"', +'Are you sure you want to uninstall application "%s"?': 'Sigur dezinstalați aplicația "%s"?', +'Authentication': 'Autentificare', +'Available databases and tables': 'Baze de date și tabele disponibile', +'Back': 'Înapoi', +'Begin': 'Început', +'Buy this book': 'Cumpără această carte', +'Cache Keys': 'Chei cache', +'Cannot be empty': 'Nu poate fi vid', +'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'Compilare imposibilă: aplicația conține erori. Debogați aplicația și încercați din nou.', +'Change Password': 'Schimbare parolă', +'Change admin password': 'Schimbă parola de administrare', +'Change password': 'Schimbare parolă', +'Check for upgrades': 'Verifică dacă există upgrade-uri', +'Check to delete': 'Coșați pentru a șterge', +'Checking for upgrades...': 'Verifică dacă există actualizări...', +'Clean': 'Curăță', +'Clear': 'Golește', +'Click row to expand traceback': 'Clic pe linie pentru a extinde mesajul de trasabilitate', +'Click row to view a ticket': 'Click row to view a ticket', +'Client IP': 'IP client', +'Community': 'Comunitate', +'Compile': 'Compilează', +'Components and Plugins': 'Componente și plugin-uri', +'Controller': 'Controlor', +'Controllers': 'Controlori', +'Copyright': 'Drepturi de autor', +'Count': 'Număr', +'Create': 'Crează', +'Create new application': 'Creați aplicație nouă', +'Current request': 'Cerere curentă', +'Current response': 'Răspuns curent', +'Current session': 'Sesiune curentă', +'DB Model': 'Model bază de date', +'DESIGN': 'DESIGN', +'Database': 'Baza de date', +'Date and Time': 'Data și ora', +'Debug': 'Debogare', +'Delete': 'Șterge', +'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)', +'Delete:': 'Șterge:', +'Demo': 'Demo', +'Deploy': 'Instalare', +'Deploy on Google App Engine': 'Instalare pe Google App Engine', +'Deployment Recipes': 'Rețete de instalare', +'Description': 'Descriere', +'Design for': 'Design pentru', +'Detailed traceback description': 'Descriere detaliată a mesajului de trasabilitate', +'Disable': 'Dezactivează', +'Disk Cache Keys': 'Chei cache de disc', +'Documentation': 'Documentație', +"Don't know what to do?": 'Nu știți ce să faceți?', +'Download': 'Descărcare', +'E-mail': 'E-mail', +'E-mail invalid': 'E-mail invalid', +'EDIT': 'EDITARE', +'Edit': 'Editare', +'Edit Profile': 'Editare profil', +'Edit This App': 'Editați această aplicație', +'Edit application': 'Editare aplicație', +'Edit current record': 'Editare înregistrare curentă', +'Editing file': 'Editare fișier', +'Editing file "%s"': 'Editare fișier "%s"', +'Email and SMS': 'E-mail și SMS', +'Error': 'Eroare', +'Error logs for "%(app)s"': 'Log erori pentru "%(app)s"', +'Error snapshot': 'Instantaneu eroare', +'Error ticket': 'Tichet eroare', +'Errors': 'Erori', +'Exception instance attributes': 'Exception instance attributes', +'Expand Abbreviation': 'Extinde abreviația', +'Export': 'Export', +'FAQ': 'Întrebări frecvente', +'False': 'Neadevărat', +'File': 'Fișier', +'First name': 'Prenume', +'Forbidden': 'Interzis', +'Forms and Validators': 'Formulare și validatori', +'Frames': 'Frames', +'Free Applications': 'Aplicații gratuite', +'Functions with no doctests will result in [passed] tests.': 'Funcțiile fără doctests vor genera teste [trecute].', +'Get from URL:': 'Obține de la adresa:', +'Go to Matching Pair': 'Mergi la perechea care se potrivește', +'Group %(group_id)s created': 'Grup %(group_id)s creat', +'Group ID': 'ID grup', +'Group uniquely assigned to user %(id)s': 'Grup asociat în mod unic utilizatorului %(id)s', +'Groups': 'Grupuri', +'Hello World': 'Salutare lume', +'Help': 'Ajutor', +'Home': 'Acasă', +'How did you get here?': 'Cum ați ajuns aici?', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\r\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Dacă raportul de deasupra conține un număr de tichet, asta indică un eșec în executarea controlorului, înainte de orice încercare de a executa doctests-urile. Aceasta se întâmplă de obicei din cauza unei erori de identare sau a unei erori din afara corpului funcției.\r\nUn titlu în verde arată ca toate testele (dacă definite) au fost trecute. În acest caz rezultatele testelor nu sunt arătate.', +'Import/Export': 'Import/Export', +'Index': 'Index', +'Install': 'Instalează', +'Installed applications': 'Aplicații instalate', +'Internal State': 'Stare internă', +'Introduction': 'Introducere', +'Invalid Query': 'Interogare invalidă', +'Invalid action': 'Acțiune invalidă', +'Invalid email': 'E-mail invalid', +'Invalid password': 'Parolă invalidă', +'Key bindings': 'Combinație taste', +'Key bindings for ZenCoding Plugin': 'Key bindings for ZenCoding Plugin', +'Language files (static strings) updated': 'Fișierele de limbă (șirurile statice de caractere) actualizate', +'Languages': 'Limbi', +'Last name': 'Nume', +'Last saved on:': 'Ultima salvare:', +'Layout': 'Șablon', +'Layout Plugins': 'Șablon plugin-uri', +'Layouts': 'Șabloane', +'License for': 'Licență pentru', +'Live Chat': 'Chat live', +'Logged in': 'Logat', +'Logged out': 'Delogat', +'Login': 'Autentificare', +'Login to the Administrative Interface': 'Logare interfață de administrare', +'Logout': 'Ieșire', +'Lost Password': 'Parolă pierdută', +'Lost password?': 'Parolă pierdută?', +'Main Menu': 'Meniu principal', +'Match Pair': 'Potrivește pereche', +'Menu Model': 'Model meniu', +'Merge Lines': 'Unește linii', +'Models': 'Modele', +'Modules': 'Module', +'My Sites': 'Site-urile mele', +'NO': 'NU', +'Name': 'Nume', +'New': 'Nou', +'New Application Wizard': 'New Application Wizard', +'New Record': 'Înregistrare nouă', +'New application wizard': 'Magician aplicație nouă', +'New password': 'Parola nouă', +'New simple application': 'O nouă aplicație simplă', +'Next Edit Point': 'Următorul punct de editare', +'No databases in this application': 'Aplicație fără bază de date', +'No ticket_storage.txt found under /private folder': 'No ticket_storage.txt found under /private folder', +'Object or table name': 'Obiect sau nume de tabel', +'Old password': 'Parola veche', +'Online examples': 'Exemple online', +'Or': 'Sau', +'OR': 'SAU', +'Origin': 'Origine', +'Original/Translation': 'Original/Traducere', +'Other Plugins': 'Alte plugin-uri', +'Other Recipes': 'Alte rețete', +'Overview': 'Prezentare de ansamblu', +'Overwrite installed app': 'Suprascrie aplicație instalată', +'Pack all': 'Împachetează tot', +'Password': 'Parola', +"Password fields don't match": 'Câmpurile de parolă nu se potrivesc', +'Peeking at file': 'Vizualizare fișier', +'Plugins': 'Plugin-uri', +'Powered by': 'Pus în mișcare de', +'Preface': 'Prefață', +'Previous Edit Point': 'Punct de editare anterior', +'Profile': 'Profil', +'Project Progress': 'Progres proiect', +'Python': 'Python', +'Query': 'Interogare', +'Query:': 'Interogare:', +'Quick Examples': 'Exemple rapide', +'RAM Cache Keys': 'Chei cache RAM', +'Recipes': 'Rețete', +'Record ID': 'ID înregistrare', +'Register': 'Înregistrare', +'Registration identifier': 'Identificator de autentificare', +'Registration key': 'Cheie înregistrare', +'Registration successful': 'Autentificare reușită', +'Reload routes': 'Reîncarcare rute', +'Remember me (for 30 days)': 'Ține-mă minte (timp de 30 de zile)', +'Request reset password': 'Cerere resetare parolă', +'Reset Password key': 'Cheie resetare parolă', +'Resolve Conflict file': 'Rezolvă conflict fișier', +'Role': 'Rol', +'Rows in table': 'Linii în tabel', +'Rows selected': 'Linii selectate', +"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')", +'Save': 'Salvează', +'Save profile': 'Salvează profil', +'Save via Ajax': 'Salvează utilizând Ajax', +'Saved file hash:': 'Hash fișier salvat:', +'Search': 'Căutare', +'Searching:': 'Căutare:', +'Semantic': 'Semantică', +'Services': 'Servicii', +'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s', +'Site': 'Site', +'Sorry, could not find mercurial installed': 'Scuze, dar n-am gasit unde este instalat mercurial', +'Start a new app': 'Începe o nouă aplicație', +'Start wizard': 'Startează magician', +'Static files': 'Fișiere statice', +'Stylesheet': 'Foaie de stiluri', +'Submit': 'Înregistrează', +'Support': 'Suport', +'Sure you want to delete this object?': 'Sigur ștergeți acest obiect?', +'Table name': 'Nume tabel', +'Testing application': 'Testare aplicație', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Interogarea (query)" este o condiție de tipul "db.tabel1.câmp1==\'valoare\'". Ceva de genul "db.tabel1.câmp1==db.tabel2.câmp2" generează un JOIN SQL.', +'The Core': 'Nucleul', +'The Views': 'Vederile', +'The application logic, each URL path is mapped in one exposed function in the controller': 'Logica aplicației, fiecare rută URL este mapată într-o funcție expusă de controlor', +'The data representation, define database tables and sets': 'Reprezentarea datelor, definește tabele și seturi de date', +'The output of the file is a dictionary that was rendered by the view': 'Fișierul produce un dicționar care a fost prelucrat de vederea', +'The presentations layer, views are also known as templates': 'Nivelul de prezentare, vederile sunt cunoscute de asemenea ca șabloane', +'There are no controllers': 'Nu există controlori', +'There are no models': 'Nu există modele', +'There are no modules': 'Nu există module', +'There are no plugins': 'Nu există plugin-uri', +'There are no static files': 'Nu există fișiere statice', +'There are no translators, only default language is supported': 'Nu există traduceri, doar limba implicită este suportată', +'There are no views': 'Nu există vederi', +'These files are served without processing, your images go here': 'Aceste fișiere sunt servite fără procesare, fișierele imagine se pun aici', +'This App': 'Această aplicație', +'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', +'Ticket ID': 'ID tichet', +'Timestamp': 'Moment în timp (timestamp)', +'To create a plugin, name a file/folder plugin_[name]': 'Pentru a crea un plugin, numește un fișier/director plugin_[nume]', +'Traceback': 'Trasabilitate', +'Translation strings for the application': 'Șiruri de traducere pentru aplicație', +'True': 'Adevărat', +'Twitter': 'Twitter', +'Unable to check for upgrades': 'Imposibil de verificat dacă există actualizări', +'Unable to download': 'Imposibil de descărcat', +'Unable to download app': 'Imposibil de descărcat aplicația', +'Uninstall': 'Dezinstalează', +'Update:': 'Actualizare:', +'Upload a package:': 'Încarcă un pachet:', +'Upload and install packed application': 'Încarcă și instalează aplicație împachetată', +'Upload existing application': 'Încarcă aplicația existentă', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Folosiți (...)&(...) pentru ȘI, (...)|(...) pentru SAU, și ~(...) pentru NEGARE, pentru a crea interogări complexe.', +'User %(id)s Logged-in': 'Utilizator %(id)s autentificat', +'User %(id)s Logged-out': 'Utilizator %(id)s delogat', +'User %(id)s Password changed': 'Parola utilizatorului %(id)s a fost schimbată', +'User %(id)s Password reset': 'Resetare parola utilizator %(id)s', +'User %(id)s Profile updated': 'Profil utilizator %(id)s actualizat', +'User %(id)s Registered': 'Utilizator %(id)s înregistrat', +'User ID': 'ID utilizator', +'VERSION': 'VERSIUNE', +'Verify Password': 'Verifică parola', +'Version': 'Version', +'Version %s.%s.%s (%s) %s': 'Versiune %s.%s.%s (%s) %s', +'Versioning': 'Versiuni', +'Videos': 'Video-uri', +'View': 'Vedere', +'Views': 'Vederi', +'Web Framework': 'Framework web', +'Welcome': 'Bine ați venit', +'Welcome %s': 'Bine ați venit %s', +'Welcome to web2py': 'Bun venit la web2py', +'Welcome to web2py!': 'Bun venit la web2py!', +'Which called the function': 'Care a apelat funcția', +'Wrap with Abbreviation': 'Încadrează cu abreviația', +'YES': 'DA', +'You are successfully running web2py': 'Rulați cu succes web2py', +'You can modify this application and adapt it to your needs': 'Puteți modifica și adapta aplicația nevoilor dvs.', +'You visited the url': 'Ați vizitat adresa', +'about': 'despre', +'additional code for your application': 'cod suplimentar pentru aplicația dvs.', +'admin disabled because no admin password': 'administrare dezactivată deoarece parola de administrator nu a fost furnizată', +'admin disabled because not supported on google app engine': 'administrare dezactivată deoarece funcționalitatea nu e suportat pe Google App Engine', +'admin disabled because unable to access password file': 'administrare dezactivată deoarece nu există acces la fișierul cu parole', +'administrative interface': 'interfață de administrare', +'and rename it (required):': 'și renumește (obligatoriu):', +'and rename it:': ' și renumește:', +'appadmin': 'appadmin', +'appadmin is disabled because insecure channel': 'appadmin dezactivat deoarece conexiunea nu e sigură', +'application "%s" uninstalled': 'aplicația "%s" a fost dezinstalată', +'application compiled': 'aplicația a fost compilată', +'application is compiled and cannot be designed': 'aplicația este compilată și nu poate fi editată', +'arguments': 'argumente', +'back': 'înapoi', +'cache': 'cache', +'cache, errors and sessions cleaned': 'cache, erori și sesiuni golite', +'cannot create file': 'fișier imposibil de creat', +'cannot upload file "%(filename)s"': 'imposibil de încărcat fișierul "%(filename)s"', +'change password': 'schimbare parolă', +'check all': 'coșează tot', +'clean': 'golire', +'click to check for upgrades': 'Clic pentru a verifica dacă există upgrade-uri', +'code': 'code', +'collapse/expand all': 'restrânge/extinde tot', +'compile': 'compilare', +'compiled application removed': 'aplicația compilată a fost ștearsă', +'contains': 'conține', +'controllers': 'controlori', +'create file with filename:': 'crează fișier cu numele:', +'create new application:': 'crează aplicație nouă:', +'created by': 'creat de', +'crontab': 'crontab', +'currently running': 'acum în funcționare', +'currently saved or': 'în prezent salvat sau', +'customize me!': 'Personalizează-mă!', +'data uploaded': 'date încărcate', +'database': 'bază de date', +'database %s select': 'selectare bază de date %s', +'database administration': 'administrare bază de date', +'db': 'db', +'defines tables': 'definire tabele', +'delete': 'șterge', +'delete all checked': 'șterge tot ce e coșat', +'design': 'design', +'details': 'detalii', +'direction: ltr': 'direcție: stânga-sus-dreapta', +'docs': 'documentație', +'done!': 'gata!', +'download layouts': 'descărcare șabloane', +'download plugins': 'descărcare plugin-uri', +'edit': 'editare', +'edit controller': 'editare controlor', +'edit profile': 'editare profil', +'edit views:': 'editează vederi:', +'enter a number between %(min)g and %(max)g': 'introduceți un număr între %(min)g și %(max)g', +'enter an integer between %(min)g and %(max)g': 'introduceți un întreg între %(min)g și %(max)g', +'errors': 'erori', +'export as csv file': 'exportă ca fișier csv', +'exposes': 'expune', +'exposes:': 'expune:', +'extends': 'extinde', +'failed to reload module': 'reîncarcare modul nereușită', +'file "%(filename)s" created': 'fișier "%(filename)s" creat', +'file "%(filename)s" deleted': 'fișier "%(filename)s" șters', +'file "%(filename)s" uploaded': 'fișier "%(filename)s" încărcat', +'file "%(filename)s" was not deleted': 'fișierul "%(filename)s" n-a fost șters', +'file "%s" of %s restored': 'fișier "%s" de %s restaurat', +'file changed on disk': 'fișier modificat pe disc', +'file does not exist': 'fișier inexistent', +'file saved on %(time)s': 'fișier salvat %(time)s', +'file saved on %s': 'fișier salvat pe %s', +'files': 'fișiere', +'filter': 'filtru', +'help': 'ajutor', +'htmledit': 'editare html', +'includes': 'include', +'index': 'index', +'insert new': 'adaugă nou', +'insert new %s': 'adaugă nou %s', +'inspect attributes': 'inspectare atribute', +'internal error': 'eroare internă', +'invalid password': 'parolă invalidă', +'invalid request': 'cerere invalidă', +'invalid ticket': 'tichet invalid', +'language file "%(filename)s" created/updated': 'fișier de limbă "%(filename)s" creat/actualizat', +'languages': 'limbi', +'languages updated': 'limbi actualizate', +'loading...': 'încarc...', +'locals': 'localizare', +'located in the file': 'prezentă în fișierul', +'login': 'autentificare', +'logout': 'ieșire', +'merge': 'unește', +'models': 'modele', +'modules': 'module', +'new application "%s" created': 'aplicația nouă "%s" a fost creată', +'new record inserted': 'înregistrare nouă adăugată', +'next 100 rows': 'următoarele 100 de linii', +'online designer': 'designer online', +'or import from csv file': 'sau importă din fișier csv', +'or provide application url:': 'sau furnizează adresă url:', +'pack all': 'împachetează toate', +'pack compiled': 'împachetează ce e compilat', +'please input your password again': 'introduceți parola din nou', +'plugins': 'plugin-uri', +'previous 100 rows': '100 de linii anterioare', +'record': 'înregistrare', +'record does not exist': 'înregistrare inexistentă', +'record id': 'id înregistrare', +'register': 'înregistrare', +'remove compiled': 'șterge compilate', +'request': 'cerere', +'response': 'răspuns', +'restore': 'restaurare', +'revert': 'revenire', +'save': 'salvare', +'selected': 'selectat', +'session': 'sesiune', +'session expired': 'sesiune expirată', +'shell': 'line de commandă', +'site': 'site', +'some files could not be removed': 'anumite fișiere n-au putut fi șterse', +'starts with': 'începe cu', +'state': 'stare', +'static': 'static', +'successful': 'cu succes', +'table': 'tabel', +'test': 'test', +'the application logic, each URL path is mapped in one exposed function in the controller': 'logica aplicației, fiecare rută URL este mapată într-o funcție expusă de controlor', +'the data representation, define database tables and sets': 'reprezentarea datelor, definește tabelele bazei de date și seturile (de date)', +'the presentations layer, views are also known as templates': 'nivelul de prezentare, vederile sunt de asemenea numite și șabloane', +'these files are served without processing, your images go here': 'aceste fișiere sunt servite fără procesare, imaginea se plasează acolo', +'to previous version.': 'la versiunea anterioară.', +'toggle breakpoint': 'comutare breakpoint', +'too short': 'prea scurt', +'translation strings for the application': 'șiruri de caractere folosite la traducerea aplicației', +'try': 'încearcă', +'try something like': 'încearcă ceva de genul', +'unable to create application "%s"': 'imposibil de creat aplicația "%s"', +'unable to delete file "%(filename)s"': 'imposibil de șters fișierul "%(filename)s"', +'unable to parse csv file': 'imposibil de analizat fișierul csv', +'unable to uninstall "%s"': 'imposibil de dezinstalat "%s"', +'uncheck all': 'decoșează tot', +'uninstall': 'dezinstalează', +'update': 'actualizează', +'update all languages': 'actualizează toate limbile', +'upload': 'încarcă', +'upload application:': 'incarcă aplicația:', +'upload file:': 'încărcă fișier:', +'upload plugin file:': 'încarcă fișier plugin:', +'user': 'utilizator', +'value already in database or empty': 'Valoare existentă în baza de date sau vidă', +'variables': 'variables', +'versioning': 'versiuni', +'view': 'vedere', +'views': 'vederi', +'web2py Recent Tweets': 'Ultimele tweet-uri web2py', +'web2py is up to date': 'web2py este la zi', +} diff --git a/applications/admin/languages/ru-ru.py b/applications/admin/languages/ru.py similarity index 100% rename from applications/admin/languages/ru-ru.py rename to applications/admin/languages/ru.py diff --git a/applications/admin/languages/uk.py b/applications/admin/languages/uk.py new file mode 100644 index 00000000..1a29f017 --- /dev/null +++ b/applications/admin/languages/uk.py @@ -0,0 +1,424 @@ +# coding: utf8 +{ +' at char %s': ' на символі %s', +' at line %s': ' в рядку %s', +'"User Exception" debug mode. ': 'Режим ладнання "Сигнали від користувачів" ("User Exception" debug mode) ', +'"User Exception" debug mode. An error ticket could be issued!': 'Режим ладнання "Сигнали від користувачів" ("User Exception" debug mode). Користувачі можуть залишати відмітки про помилки!', +'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"Оновити" це додатковий вираз, такий, як "field1=\'нове_значення\'". Ви не можете змінювати або вилучати дані об\'єднаних таблиць', +'%Y-%m-%d': '%Y/%m/%d', +'%Y-%m-%d %H:%M:%S': '%Y/%m/%d %H:%M:%S', +'%s Recent Tweets': '%s останніх твітів', +'%s rows deleted': '%s рядків вилучено', +'%s rows updated': '%s рядків оновлено', +'%s students registered': '%s студентів зареєстровано', +'(requires internet access)': '(потрібно мати доступ в інтернет)', +'(something like "it-it")': '(щось схоже на "uk-ua")', +'ATTENTION:': 'УВАГА:', +'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': "УВАГА: Вхід потребує надійного (HTTPS) з'єднання або запуску на локальному комп'ютері.", +'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ОБЕРЕЖНО: ТЕСТУВАННЯ НЕ Є ПОТОКО-БЕЗПЕЧНИМ, ТОЖ НЕ ЗАПУСКАЙТЕ ДЕКІЛЬКА ТЕСТІВ ОДНОЧАСНО.', +'ATTENTION: you cannot edit the running application!': 'УВАГА: Ви не можете редагувати додаток, який зараз виконуєте!', +'Abort': 'Припинити', +'About': 'Про', +'About application': 'Про додаток', +'Add breakpoint': 'Додати точку зупинки', +'Additional code for your application': 'Додатковий код для вашого додатку', +'Admin is disabled because insecure channel': "Адмін.інтерфейс відключено через використання ненадійного каналу звя'зку", +'Admin language': 'Мова інтерфейсу:', +'Administrator Password:': 'Пароль адміністратора:', +'App does not exist or your are not authorized': 'Додаток не існує, або ви не авторизовані', +'Application cannot be generated in demo mode': 'В демо-режимі генерувати додатки не можна', +'Application name:': 'Назва додатку:', +'Are you sure you want to delete file "%s"?': 'Ви впевнені, що хочете вилучити файл "%s"?', +'Are you sure you want to delete plugin "%s"?': 'Ви впевнені, що хочете вилучити втулку "%s"?"', +'Are you sure you want to delete this object?': "Ви впевнені, що хочете вилучити цей об'єкт?", +'Are you sure you want to uninstall application "%s"?': 'Ви впевнені, що хочете вилучити (uninstall) додаток "%s"?', +'Available databases and tables': 'Доступні бази даних та таблиці', +'Basics': 'Початок', +'Begin': 'Початок', +'Breakpoints': 'Точки зупинок', +'Bulk Register': 'Масова реєстрація', +'Bulk Student Registration': 'Масова реєстрація студентів', +'Cache Keys': 'Ключі кешу', +'Cancel': 'Відмінити', +'Cannot be empty': 'Не може бути порожнім', +'Cannot compile: there are errors in your app:': 'Не вдається скомпілювати: є помилки у вашому додатку:', +'Change admin password': 'Змінити пароль адміністратора', +'Check for upgrades': 'Перевірити оновлення', +'Check to delete': 'Помітити на вилучення', +'Checking for upgrades...': 'Відбувається пошук оновлень...', +'Clean': 'Очистити', +'Click row to expand traceback': '"Клацніть" мишкою по рядку, щоб розгорнути стек викликів (traceback)', +'Click row to view a ticket': 'Для перегляду відмітки (ticket) "клацніть" мишкою по рядку', +'Code listing': 'Лістинг', +'Compile': 'Компілювати', +'Condition': 'Умова', +'Controllers': 'Контролери', +'Count': 'К-сть', +'Create': 'Створити', +'Created On': 'Створено в', +'Current request': 'Поточний запит', +'Current response': 'Поточна відповідь', +'Current session': 'Поточна сесія', +'Date and Time': 'Дата і час', +'Debug': 'Ладнати (Debug)', +'Delete': 'Вилучити', +'Delete this file (you will be asked to confirm deletion)': 'Вилучити цей файл (буде відображено запит на підтвердження операції)', +'Delete:': 'Вилучити:', +'Deploy': 'Розгорнути', +'Deploy on Google App Engine': 'Розгорнути на Google App Engine (GAE)', +'Deployment form': 'Форма розгортання (deployment form)', +'Detailed traceback description': 'Детальний опис стеку викликів (traceback)', +'Disable': 'Вимкнути', +'Disabled': 'Вимкнено', +'Disk Cache Keys': 'Ключі дискового кешу', +'Downgrade': 'Повернути попередню версію', +'Edit': 'Редагувати', +'Edit application': 'Налаштування додатку', +'Edit current record': 'Редагувати поточний запис', +'Editing Language file': 'Редагується файл перекладу', +'Editing file "%s"': 'Редагується файл "%s"', +'Enable': 'Увімкнути', +'Error': 'Помилка', +'Error logs for "%(app)s"': 'Список зареєстрованих помилок додатку "%(app)s"', +'Error snapshot': 'Розгорнутий знімок стану (Error snapshot)', +'Error ticket': 'Відмітка (ticket) про помилку', +'Errors': 'Помилки', +'Exception %s': 'Виключення %s', +'Exception instance attributes': 'Атрибути примірника класу Exception (виключення)', +'Expand Abbreviation': 'Розгорнути абревіатуру', +'File': 'Файл', +'Filename': "Ім'я файлу", +'Frames': 'Стек викликів', +'Functions with no doctests will result in [passed] tests.': 'Функції, в яких відсутні док-тести відносяться до функцій, які успішно пройшли тести.', +'GAE Email': 'Ел.пошта GAE', +'GAE Output': 'Відповідь GAE', +'GAE Password': 'Пароль GAE', +'Generate': 'Генерувати', +'Get from URL:': 'Отримати з URL:', +'Globals': 'Глобальні змінні', +'Go to Matching Pair': 'Перейти до відповідної пари', +'Google App Engine Deployment Interface': 'Інтерфейс розгортання Google App Engine', +'Google Application Id': 'Ідентифікатор Google Application', +'Goto': 'Перейти до', +'Help': 'Допомога', +'Hide/Show Translated strings': 'Сховати/показати рядки перекладу', +'Hits': 'Спрацьовувань', +'Home': 'Домівка', +'If start the downgrade, be patient, it may take a while to rollback': 'Запустивши повернення на попередню версію, будьте терплячими, це може зайняти трохи часу', +'If start the upgrade, be patient, it may take a while to download': 'Запустивши оновлення, будьте терплячими, потрібен час для завантаження необхідних даних', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Якщо в наданому вище звіті присутня відмітка про помилку (ticket number), то це вказує на збій у виконанні контролера ще до початку запуску док-тестів. Це, зазвичай, сигналізує про помилку вирівнювання тексту програми (indention error) або помилку за межами функції (error outside function code).\r\nЗелений заголовок сигналізує, що всі тести (з наявних) пройшли успішно. В цьому випадку результат тестів показано не буде.', +'Import/Export': 'Імпорт/Експорт', +'In development, use the default Rocket webserver that is currently supported by this debugger.': 'Під час розробки , використовуйте вбудований веб-сервер Rocket, він найкраще налаштований на спільну роботу з інтерактивним ладначем.', +'Install': 'Встановлення', +'Installed applications': 'Встановлені додатки (applications)', +'Interaction at %s line %s': 'Виконується %s рядок %s', +'Interactive console': 'Інтерактивна консоль', +'Internal State': 'Внутрішній стан', +'Invalid Query': 'Помилковий запит', +'Invalid action': 'Помилкова дія', +'Key bindings': 'Клавіатурні скорочення:', +'Key bindings for ZenCoding Plugin': 'Клавіатурні скорочення для втулки ZenCoding plugin', +'Language files (static strings) updated': 'Файли перекладів (незмінні рядки) оновлено', +'Languages': 'Переклади', +'Last saved on:': 'Востаннє збережено:', +'License for': 'Ліцензія додатку', +'Line number': '№ рядка', +'LineNo': '№ рядка', +'Locals': 'Локальні змінні', +'Login': 'Вхід', +'Login to the Administrative Interface': 'Вхід в адміністративний інтерфейс', +'Logout': 'Вихід', +'Main Menu': 'Основне меню', +'Manage Admin Users/Students': 'Адміністратор керування користувачами/студентами', +'Manage Students': 'Керувати студентами', +'Match Pair': 'Знайти пару', +'Merge Lines': "З'єднати рядки", +'Minimum length is %s': 'Мінімальна довжина становить %s', +'Models': 'Моделі', +'Modified On': 'Змінено в', +'Modules': 'Модулі', +'Must include at least %s %s': 'Має вміщувати щонайменше %s %s', +'Must include at least %s lower case': 'Повинен включати щонайменше %s малих букв', +'Must include at least %s of the following : %s': 'Має включати не менше %s таких символів : %s', +'Must include at least %s upper case': 'Повинен включати щонайменше %s великих букв', +'NO': 'НІ', +'New Application Wizard': 'Майстер створення нового додатку', +'New Record': 'Новий запис', +'New application wizard': 'Майстер створення нового додатку', +'New simple application': 'Новий простий додаток', +'Next Edit Point': 'Наступне місце редагування', +'No Interaction yet': 'Ладнач не активовано', +'No databases in this application': 'Даний додаток не використовує бази даних', +'No ticket_storage.txt found under /private folder': 'В каталозі /private відсутній файл ticket_storage.txt', +'Not Authorized': 'Не дозволено', +"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": 'У промисловій експлуатації, ви повинні налаштувати ваш веб-сервер на використання одного процесу та багатьох потоків, якщо бажаєте скористатись цим ладначем.', +'Original/Translation': 'Оригінал/переклад', +'Overwrite installed app': 'Перезаписати встановлений додаток', +'PAM authenticated user, cannot change password here': 'Ввімкнена система ідентифікації користувачів PAM. Для зміни паролю скористайтесь командами вашої ОС ', +'Pack all': 'Запак.все', +'Pack compiled': 'Запак.компл', +'Path to appcfg.py': 'Шлях до appcfg.py', +'Peeking at file': 'Перегляд файлу', +'Please': 'Будь-ласка', +'Plugin "%s" in application': 'Втулка "%s" в додатку', +'Plugins': 'Втулки (Plugins)', +'Powered by': 'Працює на', +'Previous Edit Point': 'Попереднє місце редагування', +'Project Progress': 'Поступ проекту', +'Query:': 'Запит:', +'RAM Cache Keys': "Ключ ОЗП-кешу (RAM Cache)", +'Reload routes': 'Перезавантажити маршрути', +'Remove compiled': 'Вилуч.компл', +'Removed Breakpoint on %s at line %s': 'Вилучено точку зупинки у %s в рядку %s', +'Resolve Conflict file': "Файл розв'язування конфлікту", +'Rows in table': 'Рядків у таблиці', +'Rows selected': 'Рядків вибрано', +'Run tests': 'Запустити всі тести', +'Run tests in this file': 'Запустити тести у цьому файлі', +"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Запустити тести з цього файлу (для тестування всіх файлів, вам необхідно натиснути кнопку з назвою 'тестувати всі')", +'Running on %s': 'Запущено на %s', +'Save': 'Зберегти', +'Save via Ajax': 'зберегти через Ajax', +'Saved file hash:': 'Хеш збереженого файлу:', +'Searching:': 'Пошук:', +'Set Breakpoint on %s at line %s: %s': 'Додано точку зупинки в %s на рядок %s: %s', +'Site': 'Сайт', +'Sorry, could not find mercurial installed': 'Не вдалось виявити встановлену систему контролю версій Mercurial', +'Start a new app': 'Створюється новий додаток', +'Start wizard': 'Активувати майстра', +'Static files': 'Статичні файли', +'Step': 'Крок', +'Submit': 'Застосувати', +'Temporary': 'Тимчасово', +'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.table1.field1==\'значення\'". Вираз "db.table1.field1==db.table2.field2" повертає результат об\'єднання (SQL JOIN) таблиць.', +'The app exists, was NOT created by wizard, continue to overwrite!': 'Додаток вже існує, і його НЕ було створено майстром. Продовжуємо перезаписування!', +'The app exists, was created by wizard, continue to overwrite!': 'Додаток вже існує і його було створено майстром. Продовжуємо переписування!', +'The application logic, each URL path is mapped in one exposed function in the controller': 'Логіка додатку, кожний шлях URL проектується на одну з експонуючих функцій в контролері', +'The data representation, define database tables and sets': 'Представлення даних, опис таблиць БД та наборів', +'The presentations layer, views are also known as templates': 'Презентаційний рівень, відображення, відомі також як шаблони', +'There are no controllers': 'Жодного контролера, наразі, не існує', +'There are no models': 'Моделей, наразі, нема', +'There are no modules': 'Модулів поки що нема', +'There are no plugins': 'Жодної втулки, наразі, не встановлено', +'There are no static files': 'Статичних файлів, наразі, нема', +'There are no translators': 'Перекладів нема', +'There are no translators, only default language is supported': 'Перекладів нема, підтримується тільки мова оригіналу', +'There are no views': 'Відображень нема', +'These files are served without processing, your images go here': 'Ці файли обслуговуються "як є", без обробки, ваші графічні файли та інші супутні файли даних можуть знаходитись тут', +"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": 'Цей ладнач може працювати некоректно, якщо ви використовуєте веб-сервер без підтримки потоків або використовуєте декілька сервісних процесів.', +'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'Це експериментальна властивість, яка вимагає подальшого тестування. Якщо ви вирішили повернутись на попередню версію, ви це робити на ваш власний розсуд.', +'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'Це експериментальна властивість, яка вимагає подальшого тестування. Якщо ви вирішили розпочати оновлення, ви це робите на ваш власний розсуд', +'This is the %(filename)s template': 'Це шаблон %(filename)s', +'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'На цій сторінці ви можете завантажити свій додаток в сервіс хмарних обчислень Google App Engine. Майте на увазі, що спочатку необхідно локально створити індекси, і це можна зробити встановивши сервер додатків Google appserver та запустивши в ньому додаток один раз, інакше при виборі записів виникатимуть помилки. Увага: розгортання може зайняти тривалий час, в залежності від швидкості мережі. Увага: це призведе до перезапису app.yaml. НЕ ПУБЛІКУЙТЕ ДВІЧІ.', +'Ticket': 'Відмітка (Ticket)', +'Ticket ID': 'Ідентифікатор відмітки (Ticket ID)', +'To create a plugin, name a file/folder plugin_[name]': 'Для створення втулки, назвіть файл/каталог plugin_[name]', +'To emulate a breakpoint programatically, write:': 'Для встановлення точки зупинки програмним чином напишіть:', +'Traceback': 'Стек викликів (Traceback)', +'Translation strings for the application': 'Пари рядків <оригінал>:<переклад> для вибраної мови', +'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'наберіть тут будь-які команди ладнача PDB і натисніть клавішу [Return] ([Enter]), щоб запустити їх на виконання.', +'Type python statement in here and hit Return (Enter) to execute it.': 'Наберіть тут будь-які вирази Python і натисніть клавішу [Return] ([Enter]), щоб запустити їх на виконання.', +'Unable to check for upgrades': 'Неможливо перевірити оновлення', +'Unable to determine the line number!': 'Не можу визначити номер рядка!', +'Unable to download app because:': 'Не можу завантажити додаток через:', +'Unable to download because:': 'Неможливо завантажити через:', +'Uninstall': 'Вилучити', +'Unsupported webserver working mode: %s': 'Веб-сервер знаходиться в режимі, який не підтримується: %s', +'Update:': 'Поновити:', +'Upgrade': 'Оновити', +'Upload a package:': 'Завантажити пакет:', +'Upload and install packed application': 'Завантажити та встановити запакований додаток', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Для створення складних запитів використовуйте (...)&(...) замість AND, (...)|(...) замість OR, та ~(...) замість NOT.', +'Using the shell may lock the database to other users of this app.': 'Використання оболонки може заблокувати базу даних від сумісного використання іншими користувачами цього додатку.', +'Version': 'Версія', +'Version %s.%s.%s (%s) %s': 'Версія %s.%s.%s (%s) %s', +'Versioning': 'Контроль версій', +'Views': 'Відображення (Views)', +'WARNING:': 'ПОПЕРЕДЖЕННЯ:', +'Web Framework': 'Web Framework', +'Wrap with Abbreviation': 'Загорнути з абревіатурою', +'YES': 'ТАК', +'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'Ви також можете встановлювати/вилучати точки зупинок під час редагування першоджерел (sources), використовуючи кнопку "+/- точку зупинки"', +'You have one more login attempt before you are locked out': 'У вас є ще одна спроба перед тим, як вхід буде заблоковано', +'You need to set up and reach a': 'Треба встановити та досягнути', +'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Ваш додаток буде заблоковано, поки ви не клацнете по одній з кнопок керування ("наступний", "крок", "продовжити", та ін.)', +'Your can inspect variables using the console bellow': 'Ви можете досліджувати змінні, використовуючи інтерактивну консоль', +'about': 'про', +'admin disabled because no admin password': 'адмін.інтерфейс відключено, бо не вказано пароль адміністратора', +'admin disabled because not supported on google app engine': 'адмін.інтерфейс відключено через те, що Google Application Engine його не підтримує', +'admin disabled because too many invalid login attempts': 'адмін.інтерфейс заблоковано, бо кількість хибних спроб входу перевищило граничний рівень', +'admin disabled because unable to access password file': 'адмін.інтерфейс відключено через відсутність доступу до файлу паролів', +'administrative interface': 'інтерфейс адміністратора', +'and rename it:': 'i змінити назву на:', +'appadmin': 'Aдм.панель', +'appadmin is disabled because insecure channel': "адмін.панель відключено через використання ненадійного каналу зв'язку", +'application "%s" uninstalled': 'додаток "%s" вилучено', +'application %(appname)s installed with md5sum: %(digest)s': 'додаток %(appname)s встановлено з md5sum: %(digest)s', +'application compiled': 'додаток скомпільовано', +'application is compiled and cannot be designed': 'додаток скомпільований. налаштування змінювати не можна', +'arguments': 'аргументи', +'back': '<< назад', +'breakpoint': 'точку зупинки', +'breakpoints': 'точки зупинок', +'cache': 'кеш', +'cache, errors and sessions cleaned': 'кеш, список зареєстрованих помилок та сесії очищенні', +'cannot create file': 'не можу створити файл', +'cannot upload file "%(filename)s"': 'не можу завантажити файл "%(filename)s"', +'check all': 'відмітити всі', +'code': 'код', +'collapse/expand all': 'згорнути/розгорнути все', +'compiled application removed': 'скомпільований додаток вилучено', +'continue': 'продовжити', +'controllers': 'контролери', +'create file with filename:': 'створити файл з назвою:', +'created by': 'Автор:', +'crontab': 'таблиця cron', +'currently running': 'наразі, активний додаток', +'currently saved or': 'останній збережений, або', +'data uploaded': 'дані завантажено', +'database': 'база даних', +'database %s select': 'Вибірка з бази даних %s', +'database administration': 'адміністрування бази даних', +'db': 'дб', +'defines tables': "об'являє таблиці", +'delete': 'вилучити', +'delete all checked': 'вилучити всі відмічені', +'delete plugin': 'вилучити втулку', +'deleted after first hit': 'автоматично вилучається після першого спрацювання', +'design': 'налаштування', +'details': 'детальніше', +'direction: ltr': 'напрямок: зліва-направо (ltr)', +'disabled in demo mode': 'відключено в демо-режимі', +'disabled in multi user mode': 'відключено в багато-користувацькому режимі', +'docs': 'док.', +'done!': 'зроблено!', +'download layouts': 'завантажити макет (layout)', +'download plugins': 'завантажити втулки', +'edit all': 'редагувати всі', +'edit controller': 'редагувати контролер', +'edit views:': 'редагувати відображення (views):', +'enter a value': 'введіть значення', +'export as csv file': 'експортувати як файл csv', +'exposes': 'експонує', +'exposes:': 'експонує:', +'extends': 'розширює', +'failed to compile file because:': 'не вдалось скомпілювати файл через:', +'failed to reload module because:': 'не вдалось перевантажити модуль через:', +'file "%(filename)s" created': 'файл "%(filename)s" створено', +'file "%(filename)s" deleted': 'файл "%(filename)s" вилучено', +'file "%(filename)s" uploaded': 'файл "%(filename)s" завантажено', +'file "%s" of %s restored': 'файл "%s" з %s відновлено', +'file changed on disk': 'файл змінено на диску', +'file does not exist': 'файлу не існує', +'file not found': 'файл не знайдено', +'file saved on %(time)s': 'файл збережено в %(time)s', +'file saved on %s': 'файл збережено в %s', +'files': 'файли', +'filter': 'фільтр', +'go!': 'почали!', +'honored only if the expression evaluates to true': 'точка зупинки активується тільки за істинності умови', +'includes': 'включає', +'index': 'індекс', +'insert new': 'вставити новий', +'insert new %s': 'вставити новий %s', +'inspect attributes': 'інспектувати атрибути', +'internal error': 'внутрішня помилка', +'internal error: %s': 'внутрішня помилка: %s', +'invalid circual reference': 'помилкове циклічне посилання', +'invalid circular reference': 'помилкове циклічне посилання', +'invalid password': 'неправильний пароль', +'invalid password.': 'неправильний пароль.', +'invalid request': 'хибний запит', +'invalid table names (auth_* tables already defined)': "хибна назва таблиці (таблиці auth_* вже оголошено)", +'invalid ticket': 'недійсна відмітка про помилку (ticket)', +'language file "%(filename)s" created/updated': 'Файл перекладу "%(filename)s" створено/оновлено', +'languages': 'переклади', +'loading...': 'завантаження...', +'locals': 'локальні', +'merge': "з'єднати", +'models': 'моделі', +'modules': 'модулі', +'new application "%s" created': 'новий додаток "%s" створено', +'new plugin installed': 'нова втулка (plugin) встановлена', +'new record inserted': 'новий рядок додано', +'next': 'наступний', +'next 100 rows': 'наступні 100 рядків', +'no match': 'співпадань нема', +'no permission to uninstall "%s"': 'нема прав на вилучення (uninstall) "%s"', +'online designer': 'ДБ-дизайнер', +'or import from csv file': 'або імпортувати через csv-файл', +'pack plugin': 'запакувати втулку', +'password changed': 'пароль змінено', +'peek': 'глянути', +'plugin': 'втулка', +'plugin "%(plugin)s" deleted': 'втулку "%(plugin)s" вилучено', +'plugin not specified': 'втулку не визначено', +'plugins': 'втулки (plugins)', +'previous 100 rows': 'попередні 100 рядків', +'record': 'запис', +'record does not exist': 'запису не існує', +'record id': 'Ід.запису', +'refresh': 'оновіть', +'request': 'запит', +'resolve': "розв'язати", +'response': 'відповідь', +'restart': 'перезапустити майстра', +'restore': 'повернути', +'return': 'повернутись', +'revert': 'відновитись', +'selected': 'відмічено', +'session': 'сесія', +'session expired': 'час даної сесії вичерпано', +'shell': 'консоль', +'site': 'сайт', +'skip to generate': 'перейти до генерування результату', +'some files could not be removed': 'деякі файли не можна вилучити', +'state': 'стан', +'static': 'статичні', +'step': 'крок', +'stop': 'зупинити', +'submit': 'застосувати', +'successful': 'успішно', +'table': 'таблиця', +'test': 'тестувати всі', +'this page to see if a breakpoint was hit and debug interaction is required.': 'цю сторінку, щоб побачити, чи була досягнута точка зупинки і процес ладнання розпочато.', +'ticket': 'відмітка', +'to previous version.': 'до попередньої версії.', +'to use the debugger!': 'щоб активувати ладнач!', +'toggle breakpoint': '+/- точку зупинки', +'try something like': 'спробуйте щось схоже на', +'try view': 'дивитись результат', +'unable to create application "%s"': 'не можу створити додаток "%s"', +'unable to create application "%s" (it may exist already)': 'не можу створити додаток "%s" (можливо його вже створено)', +'unable to delete file "%(filename)s"': 'не можу вилучити файл "%(filename)s"', +'unable to delete file plugin "%(plugin)s"': 'не можу вилучити файл втулки "%(plugin)s"', +'unable to download layout': 'не вдається завантажити макет', +'unable to download plugin: %s': 'не вдається завантажити втулку: %s', +'unable to install application "%(appname)s"': 'не вдається встановити додаток "%(appname)s"', +'unable to parse csv file': 'не вдається розібрати csv-файл', +'unable to uninstall "%s"': 'не вдається вилучити "%s"', +'unable to upgrade because "%s"': 'не вдається оновити, тому що "%s"', +'uncheck all': 'зняти відмітку з усіх', +'uninstall': 'вилучити', +'update': 'оновити', +'update all languages': 'оновити всі переклади', +'upgrade now': 'оновитись зараз', +'upgrade_web2py': 'оновити web2py', +'upload': 'завантажити', +'upload file:': 'завантажити файл:', +'upload plugin file:': 'завантажити файл втулки:', +'user': 'користувач', +'value not allowed': 'недопустиме значення', +'variables': 'змінні', +'views': 'відображення', +'web2py Debugger': 'Ладнач web2py', +'web2py Recent Tweets': 'Останні твіти web2py', +'web2py apps to deploy': 'Готові до розгортання додатки web2py', +'web2py downgrade': 'повернення на попередню версію web2py', +'web2py is up to date': 'web2py оновлено до актуальної версії', +'web2py online debugger': 'оперативний ладнач (online debugger) web2py', +'web2py upgrade': 'оновлення web2py', +'web2py upgraded; please restart it': 'web2py оновлено; будь-ласка перезапустіть його', +'you must specify a name for the uploaded application': "ви повинні вказати ім'я додатка, перед ти, як завантажити його", +} diff --git a/applications/admin/languages/zh-cn.py b/applications/admin/languages/zh.py similarity index 100% rename from applications/admin/languages/zh-cn.py rename to applications/admin/languages/zh.py diff --git a/applications/admin/models/0_imports.py b/applications/admin/models/0_imports.py index ad01f129..0b3b4597 100644 --- a/applications/admin/models/0_imports.py +++ b/applications/admin/models/0_imports.py @@ -12,7 +12,11 @@ import socket from textwrap import dedent try: - from mercurial import ui, hg, cmdutil, scmutil + from mercurial import ui, hg, cmdutil + try: + from mercurial.scmutil import addremove + except: + from mercurial.cmdutil import addremove have_mercurial = True except ImportError: have_mercurial = False diff --git a/applications/admin/static/js/ajax_editor.js b/applications/admin/static/js/ajax_editor.js index dbb2be73..f846376b 100644 --- a/applications/admin/static/js/ajax_editor.js +++ b/applications/admin/static/js/ajax_editor.js @@ -71,7 +71,7 @@ function doClickSave() { success: function(json,text,xhr){ // show flash message (if any) - var flash=xhr.getResponseHeader('web2py-component-flash'); + var flash=decodeURIComponent(xhr.getResponseHeader('web2py-component-flash')); if (flash) jQuery('.flash').html(flash).slideDown(); else jQuery('.flash').hide(); @@ -149,7 +149,7 @@ function doToggleBreakpoint(filename, url) { success: function(json,text,xhr){ // show flash message (if any) - var flash=xhr.getResponseHeader('web2py-component-flash'); + var flash=decodeURIComponent(xhr.getResponseHeader('web2py-component-flash')); if (flash) jQuery('.flash').html(flash).slideDown(); else jQuery('.flash').hide(); try { diff --git a/applications/admin/static/js/web2py.js b/applications/admin/static/js/web2py.js index 6a84c20a..b2f7e8dd 100644 --- a/applications/admin/static/js/web2py.js +++ b/applications/admin/static/js/web2py.js @@ -86,7 +86,7 @@ function web2py_ajax_page(method, action, data, target) { var html=xhr.responseText; var content=xhr.getResponseHeader('web2py-component-content'); var command=xhr.getResponseHeader('web2py-component-command'); - var flash=xhr.getResponseHeader('web2py-component-flash'); + var flash=decodeURIComponent(xhr.getResponseHeader('web2py-component-flash')); var t = jQuery('#'+target); if(content=='prepend') t.prepend(html); else if(content=='append') t.append(html); diff --git a/applications/admin/views/debug/index.html b/applications/admin/views/debug/index.html index db3a39a9..4f1aecfc 100644 --- a/applications/admin/views/debug/index.html +++ b/applications/admin/views/debug/index.html @@ -64,14 +64,14 @@
- +
>>>
- Type PDB debugger command in here and hit Return (Enter) to execute it. + {{=T('Type PDB debugger command in here and hit Return (Enter) to execute it.')}}
@@ -79,7 +79,7 @@
    -
  • Using the shell may lock the database to other users of this app.
  • +
  • {{=T('Using the shell may lock the database to other users of this app.')}}
diff --git a/applications/admin/views/default/edit.html b/applications/admin/views/default/edit.html index 3847269a..f0a7f764 100644 --- a/applications/admin/views/default/edit.html +++ b/applications/admin/views/default/edit.html @@ -42,7 +42,7 @@ - {{elif TEXT_EDITOR_KEYBINDING == 'emacs':}} + {{elif TEXT_EDITOR_KEYBINDING == 'vi':}} -

Google App Engine Deployment Interface

+

{{=T("Google App Engine Deployment Interface")}}

{{=T("This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.")}}

@@ -20,10 +20,10 @@ $(document).ready(function() {

Command

{{=CODE(command)}} -

GAE Output

+

{{=T("GAE Output")}}


 {{else:}}
-

Deployment form

+

{{=T("Deployment form")}}

{{=form}}
diff --git a/applications/examples/static/js/web2py.js b/applications/examples/static/js/web2py.js index 6a84c20a..b2f7e8dd 100644 --- a/applications/examples/static/js/web2py.js +++ b/applications/examples/static/js/web2py.js @@ -86,7 +86,7 @@ function web2py_ajax_page(method, action, data, target) { var html=xhr.responseText; var content=xhr.getResponseHeader('web2py-component-content'); var command=xhr.getResponseHeader('web2py-component-command'); - var flash=xhr.getResponseHeader('web2py-component-flash'); + var flash=decodeURIComponent(xhr.getResponseHeader('web2py-component-flash')); var t = jQuery('#'+target); if(content=='prepend') t.prepend(html); else if(content=='append') t.append(html); diff --git a/applications/examples/views/default/who.html b/applications/examples/views/default/who.html index ffe00cd9..5f08ef53 100644 --- a/applications/examples/views/default/who.html +++ b/applications/examples/views/default/who.html @@ -67,6 +67,7 @@
  • Hans Murx (Database support)
  • Hans C. v. Stockhausen (OpenID, Google Wave)
  • Ian Reinhart Geiser (html helpers) +
  • Ionel Anton (Romanian translation)
  • Jan Beilicke (markmin)
  • Jonathan Benn (is_url validator and tests)
  • Jonathan Lundell (multiple contributions) @@ -127,6 +128,7 @@
  • Yannis Aribaud (CAS compliance)
  • Yarko Tymciurak (design)
  • Younghyun Jo (internationalization) +
  • Vladyslav Kozlovskyy (internationalization and mercurial support)
  • Vidul Nikolaev Petrov (captcha)
  • Vinicius Assef
  • Zahariash (memory management) diff --git a/applications/welcome/controllers/default.py b/applications/welcome/controllers/default.py index 14a5a8ea..f449da20 100644 --- a/applications/welcome/controllers/default.py +++ b/applications/welcome/controllers/default.py @@ -14,7 +14,7 @@ def index(): example action using the internationalization operator T and flash rendered by views/default/index.html or views/generic.html """ - response.flash = "Welcome to web2py!" + response.flash = T("Welcome to web2py!") return dict(message=T('Hello World')) def user(): @@ -68,4 +68,3 @@ def data(): LOAD('default','data.load',args='tables',ajax=True,user_signature=True) """ return dict(form=crud()) - diff --git a/applications/welcome/languages/cs-cz.py b/applications/welcome/languages/cs.py similarity index 100% rename from applications/welcome/languages/cs-cz.py rename to applications/welcome/languages/cs.py diff --git a/applications/welcome/languages/es-es.py b/applications/welcome/languages/es.py similarity index 100% rename from applications/welcome/languages/es-es.py rename to applications/welcome/languages/es.py diff --git a/applications/welcome/languages/fr-fr.py b/applications/welcome/languages/fr.py similarity index 100% rename from applications/welcome/languages/fr-fr.py rename to applications/welcome/languages/fr.py diff --git a/applications/welcome/languages/hi-hi.py b/applications/welcome/languages/hi.py similarity index 100% rename from applications/welcome/languages/hi-hi.py rename to applications/welcome/languages/hi.py diff --git a/applications/welcome/languages/hu-hu.py b/applications/welcome/languages/hu-hu.py deleted file mode 100644 index d1c08e30..00000000 --- a/applications/welcome/languages/hu-hu.py +++ /dev/null @@ -1,94 +0,0 @@ -# coding: utf8 -{ -'"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 rows deleted': '%s sorok t\xc3\xb6rl\xc5\x91dtek', -'%s rows updated': '%s sorok friss\xc3\xadt\xc5\x91dtek', -'Available databases and tables': 'El\xc3\xa9rhet\xc5\x91 adatb\xc3\xa1zisok \xc3\xa9s t\xc3\xa1bl\xc3\xa1k', -'Cannot be empty': 'Nem lehet \xc3\xbcres', -'Check to delete': 'T\xc3\xb6rl\xc3\xa9shez v\xc3\xa1laszd ki', -'Client IP': 'Client IP', -'Controller': 'Controller', -'Copyright': 'Copyright', -'Current request': 'Jelenlegi lek\xc3\xa9rdez\xc3\xa9s', -'Current response': 'Jelenlegi v\xc3\xa1lasz', -'Current session': 'Jelenlegi folyamat', -'DB Model': 'DB Model', -'Database': 'Adatb\xc3\xa1zis', -'Delete:': 'T\xc3\xb6r\xc3\xb6l:', -'Description': 'Description', -'E-mail': 'E-mail', -'Edit': 'Szerkeszt', -'Edit This App': 'Alkalmaz\xc3\xa1st szerkeszt', -'Edit current record': 'Aktu\xc3\xa1lis bejegyz\xc3\xa9s szerkeszt\xc3\xa9se', -'First name': 'First name', -'Group ID': 'Group ID', -'Hello World': 'Hello Vil\xc3\xa1g', -'Import/Export': 'Import/Export', -'Index': 'Index', -'Internal State': 'Internal State', -'Invalid Query': 'Hib\xc3\xa1s lek\xc3\xa9rdez\xc3\xa9s', -'Invalid email': 'Invalid email', -'Last name': 'Last name', -'Layout': 'Szerkezet', -'Main Menu': 'F\xc5\x91men\xc3\xbc', -'Menu Model': 'Men\xc3\xbc model', -'Name': 'Name', -'New Record': '\xc3\x9aj bejegyz\xc3\xa9s', -'No databases in this application': 'Nincs adatb\xc3\xa1zis ebben az alkalmaz\xc3\xa1sban', -'Origin': 'Origin', -'Password': 'Password', -'Powered by': 'Powered by', -'Query:': 'Lek\xc3\xa9rdez\xc3\xa9s:', -'Record ID': 'Record ID', -'Registration key': 'Registration key', -'Reset Password key': 'Reset Password key', -'Role': 'Role', -'Rows in table': 'Sorok a t\xc3\xa1bl\xc3\xa1ban', -'Rows selected': 'Kiv\xc3\xa1lasztott sorok', -'Stylesheet': 'Stylesheet', -'Sure you want to delete this object?': 'Biztos t\xc3\xb6rli 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.', -'Timestamp': 'Timestamp', -'Update:': 'Friss\xc3\xadt:', -'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\xc3\xa9zet', -'Welcome %s': 'Welcome %s', -'Welcome to web2py': 'Isten hozott a web2py-ban', -'appadmin is disabled because insecure channel': 'az appadmin a biztons\xc3\xa1gtalan csatorna miatt letiltva', -'cache': 'gyors\xc3\xadt\xc3\xb3t\xc3\xa1r', -'change password': 'jelsz\xc3\xb3 megv\xc3\xa1ltoztat\xc3\xa1sa', -'Online examples': 'online p\xc3\xa9ld\xc3\xa1k\xc3\xa9rt kattints ide', -'Administrative interface': 'az adminisztr\xc3\xa1ci\xc3\xb3s fel\xc3\xbclet\xc3\xa9rt kattints ide', -'customize me!': 'v\xc3\xa1ltoztass meg!', -'data uploaded': 'adat felt\xc3\xb6ltve', -'database': 'adatb\xc3\xa1zis', -'database %s select': 'adatb\xc3\xa1zis %s kiv\xc3\xa1laszt\xc3\xa1s', -'db': 'db', -'design': 'design', -'done!': 'k\xc3\xa9sz!', -'edit profile': 'profil szerkeszt\xc3\xa9se', -'export as csv file': 'export\xc3\xa1l csv f\xc3\xa1jlba', -'insert new': '\xc3\xbaj beilleszt\xc3\xa9se', -'insert new %s': '\xc3\xbaj beilleszt\xc3\xa9se %s', -'invalid request': 'hib\xc3\xa1s k\xc3\xa9r\xc3\xa9s', -'login': 'bel\xc3\xa9p', -'logout': 'kil\xc3\xa9p', -'lost password': 'elveszett jelsz\xc3\xb3', -'new record inserted': '\xc3\xbaj bejegyz\xc3\xa9s felv\xc3\xa9ve', -'next 100 rows': 'k\xc3\xb6vetkez\xc5\x91 100 sor', -'or import from csv file': 'vagy bet\xc3\xb6lt\xc3\xa9s csv f\xc3\xa1jlb\xc3\xb3l', -'previous 100 rows': 'el\xc5\x91z\xc5\x91 100 sor', -'record': 'bejegyz\xc3\xa9s', -'record does not exist': 'bejegyz\xc3\xa9s nem l\xc3\xa9tezik', -'record id': 'bejegyz\xc3\xa9s id', -'register': 'regisztr\xc3\xa1ci\xc3\xb3', -'selected': 'kiv\xc3\xa1lasztott', -'state': '\xc3\xa1llapot', -'table': 't\xc3\xa1bla', -'unable to parse csv file': 'nem lehet a csv f\xc3\xa1jlt beolvasni', -} - diff --git a/applications/welcome/languages/it-it.py b/applications/welcome/languages/it-it.py deleted file mode 100644 index 71c79547..00000000 --- a/applications/welcome/languages/it-it.py +++ /dev/null @@ -1,108 +0,0 @@ -# coding: utf8 -{ -'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" è un\'espressione opzionale come "campo1=\'nuovo valore\'". Non si può fare "update" o "delete" dei risultati di un JOIN ', -'%Y-%m-%d': '%d/%m/%Y', -'%Y-%m-%d %H:%M:%S': '%d/%m/%Y %H:%M:%S', -'%s rows deleted': '%s righe ("record") cancellate', -'%s rows updated': '%s righe ("record") modificate', -'Administrative interface': 'Interfaccia amministrativa', -'Available databases and tables': 'Database e tabelle disponibili', -'Cannot be empty': 'Non può essere vuoto', -'Check to delete': 'Seleziona per cancellare', -'Client IP': 'Client IP', -'Controller': 'Controller', -'Copyright': 'Copyright', -'Current request': 'Richiesta (request) corrente', -'Current response': 'Risposta (response) corrente', -'Current session': 'Sessione (session) corrente', -'DB Model': 'Modello di DB', -'Database': 'Database', -'Delete': 'Delete', -'Delete:': 'Cancella:', -'Description': 'Descrizione', -'Documentation': 'Documentazione', -'E-mail': 'E-mail', -'Edit': 'Modifica', -'Edit This App': 'Modifica questa applicazione', -'Edit current record': 'Modifica record corrente', -'First name': 'Nome', -'Group ID': 'ID Gruppo', -'Hello': 'Hello', -'Hello World': 'Salve Mondo', -'Hello World in a flash!': 'Salve Mondo in un flash!', -'Import/Export': 'Importa/Esporta', -'Index': 'Indice', -'Internal State': 'Stato interno', -'Invalid Query': 'Richiesta (query) non valida', -'Invalid email': 'Email non valida', -'Last name': 'Cognome', -'Layout': 'Layout', -'Main Menu': 'Menu principale', -'Menu Model': 'Menu Modelli', -'Name': 'Nome', -'New Record': 'Nuovo elemento (record)', -'No databases in this application': 'Nessun database presente in questa applicazione', -'Online examples': 'Vedere gli esempi', -'Origin': 'Origine', -'Password': 'Password', -'Powered by': 'Powered by', -'Query:': 'Richiesta (query):', -'Record ID': 'Record ID', -'Registration key': 'Chiave di Registazione', -'Reset Password key': 'Resetta chiave Password ', -'Role': 'Ruolo', -'Rows in table': 'Righe nella tabella', -'Rows selected': 'Righe selezionate', -'Stylesheet': 'Foglio di stile (stylesheet)', -'Sure you want to delete this object?': 'Vuoi veramente cancellare questo oggetto?', -'Table name': 'Nome tabella', -'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'La richiesta (query) è una condizione come ad esempio "db.tabella1.campo1==\'valore\'". Una condizione come "db.tabella1.campo1==db.tabella2.campo2" produce un "JOIN" SQL.', -'The output of the file is a dictionary that was rendered by the view': 'L\'output del file è un "dictionary" che è stato visualizzato dalla vista', -'This is a copy of the scaffolding application': "Questa è una copia dell'applicazione di base (scaffold)", -'Timestamp': 'Ora (timestamp)', -'Update:': 'Aggiorna:', -'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': 'ID Utente', -'View': 'Vista', -'Welcome %s': 'Benvenuto %s', -'Welcome to web2py': 'Benvenuto su web2py', -'Which called the function': 'che ha chiamato la funzione', -'You are successfully running web2py': 'Stai eseguendo web2py con successo', -'You can modify this application and adapt it to your needs': 'Puoi modificare questa applicazione adattandola alle tue necessità', -'You visited the url': "Hai visitato l'URL", -'appadmin is disabled because insecure channel': 'Amministrazione (appadmin) disabilitata: comunicazione non sicura', -'cache': 'cache', -'change password': 'Cambia password', -'customize me!': 'Personalizzami!', -'data uploaded': 'dati caricati', -'database': 'database', -'database %s select': 'database %s select', -'db': 'db', -'design': 'progetta', -'done!': 'fatto!', -'edit profile': 'modifica profilo', -'export as csv file': 'esporta come file CSV', -'hello': 'hello', -'hello world': 'salve mondo', -'insert new': 'inserisci nuovo', -'insert new %s': 'inserisci nuovo %s', -'invalid request': 'richiesta non valida', -'located in the file': 'presente nel file', -'login': 'accesso', -'logout': 'uscita', -'lost password?': 'dimenticato la password?', -'new record inserted': 'nuovo record inserito', -'next 100 rows': 'prossime 100 righe', -'not authorized': 'non autorizzato', -'or import from csv file': 'oppure importa da file CSV', -'previous 100 rows': '100 righe precedenti', -'record': 'record', -'record does not exist': 'il record non esiste', -'record id': 'record id', -'register': 'registrazione', -'selected': 'selezionato', -'state': 'stato', -'table': 'tabella', -'unable to parse csv file': 'non riesco a decodificare questo file CSV', -} - diff --git a/applications/welcome/languages/pl-pl.py b/applications/welcome/languages/pl-pl.py deleted file mode 100644 index bdc6f38d..00000000 --- a/applications/welcome/languages/pl-pl.py +++ /dev/null @@ -1,82 +0,0 @@ -# coding: utf8 -{ -'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"Uaktualnij" jest dodatkowym wyra\xc5\xbceniem postaci "pole1=\'nowawarto\xc5\x9b\xc4\x87\'". Nie mo\xc5\xbcesz uaktualni\xc4\x87 lub usun\xc4\x85\xc4\x87 wynik\xc3\xb3w z JOIN:', -'%Y-%m-%d': '%Y-%m-%d', -'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', -'%s rows deleted': 'Wierszy usuni\xc4\x99tych: %s', -'%s rows updated': 'Wierszy uaktualnionych: %s', -'Available databases and tables': 'Dost\xc4\x99pne bazy danych i tabele', -'Cannot be empty': 'Nie mo\xc5\xbce by\xc4\x87 puste', -'Change Password': 'Change Password', -'Check to delete': 'Zaznacz aby usun\xc4\x85\xc4\x87', -'Controller': 'Controller', -'Copyright': 'Copyright', -'Current request': 'Aktualne \xc5\xbc\xc4\x85danie', -'Current response': 'Aktualna odpowied\xc5\xba', -'Current session': 'Aktualna sesja', -'DB Model': 'DB Model', -'Database': 'Database', -'Delete:': 'Usu\xc5\x84:', -'Edit': 'Edit', -'Edit Profile': 'Edit Profile', -'Edit This App': 'Edit This App', -'Edit current record': 'Edytuj aktualny rekord', -'Hello World': 'Witaj \xc5\x9awiecie', -'Import/Export': 'Importuj/eksportuj', -'Index': 'Index', -'Internal State': 'Stan wewn\xc4\x99trzny', -'Invalid Query': 'B\xc5\x82\xc4\x99dne zapytanie', -'Layout': 'Layout', -'Login': 'Zaloguj', -'Logout': 'Logout', -'Lost Password': 'Przypomnij has\xc5\x82o', -'Main Menu': 'Main Menu', -'Menu Model': 'Menu Model', -'New Record': 'Nowy rekord', -'No databases in this application': 'Brak baz danych w tej aplikacji', -'Powered by': 'Powered by', -'Query:': 'Zapytanie:', -'Register': 'Zarejestruj', -'Rows in table': 'Wiersze w tabeli', -'Rows selected': 'Wybrane wiersze', -'Stylesheet': 'Stylesheet', -'Sure you want to delete this object?': 'Czy na pewno chcesz usun\xc4\x85\xc4\x87 ten obiekt?', -'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\xc5\x9b\xc4\x87\'". Takie co\xc5\x9b jak "db.tabela1.pole1==db.tabela2.pole2" oznacza SQL JOIN.', -'Update:': 'Uaktualnij:', -'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'U\xc5\xbcyj (...)&(...) jako AND, (...)|(...) jako OR oraz ~(...) jako NOT do tworzenia bardziej skomplikowanych zapyta\xc5\x84.', -'View': 'View', -'Welcome %s': 'Welcome %s', -'Welcome to web2py': 'Witaj w web2py', -'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', -'cache': 'cache', -'change password': 'change password', -'Online examples': 'Kliknij aby przej\xc5\x9b\xc4\x87 do interaktywnych przyk\xc5\x82ad\xc3\xb3w', -'Administrative interface': 'Kliknij aby przej\xc5\x9b\xc4\x87 do panelu administracyjnego', -'customize me!': 'dostosuj mnie!', -'data uploaded': 'dane wys\xc5\x82ane', -'database': 'baza danych', -'database %s select': 'wyb\xc3\xb3r z bazy danych %s', -'db': 'baza danych', -'design': 'projektuj', -'done!': 'zrobione!', -'edit profile': 'edit profile', -'export as csv file': 'eksportuj jako plik csv', -'insert new': 'wstaw nowy rekord tabeli', -'insert new %s': 'wstaw nowy rekord do tabeli %s', -'invalid request': 'B\xc5\x82\xc4\x99dne \xc5\xbc\xc4\x85danie', -'login': 'login', -'logout': 'logout', -'new record inserted': 'nowy rekord zosta\xc5\x82 wstawiony', -'next 100 rows': 'nast\xc4\x99pne 100 wierszy', -'or import from csv file': 'lub zaimportuj z pliku csv', -'previous 100 rows': 'poprzednie 100 wierszy', -'record': 'record', -'record does not exist': 'rekord nie istnieje', -'record id': 'id rekordu', -'register': 'register', -'selected': 'wybranych', -'state': 'stan', -'table': 'tabela', -'unable to parse csv file': 'nie mo\xc5\xbcna sparsowa\xc4\x87 pliku csv', -} - diff --git a/applications/welcome/languages/pt-pt.py b/applications/welcome/languages/pt-pt.py deleted file mode 100644 index 6c190d32..00000000 --- a/applications/welcome/languages/pt-pt.py +++ /dev/null @@ -1,117 +0,0 @@ -# coding: utf8 -{ -'"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 rows deleted': '%s linhas eliminadas', -'%s rows updated': '%s linhas actualizadas', -'About': 'About', -'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', -'Cannot be empty': 'não pode ser vazio', -'Category Create': 'Category Create', -'Category Select': 'Category Select', -'Check to delete': 'seleccione para eliminar', -'Comment Create': 'Comment Create', -'Comment Select': 'Comment Select', -'Content': 'Content', -'Controller': 'Controlador', -'Copyright': 'Direitos de cópia', -'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', -'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.', -'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', -'appadmin is disabled because insecure channel': 'appadmin está desactivada pois o canal é inseguro', -'cache': 'cache', -'change password': 'alterar palavra-chave', -'Online examples': 'Exemplos online', -'Administrative interface': 'Painel administrativo', -'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', -'design': 'design', -'done!': 'concluído!', -'edit category': 'edit category', -'edit comment': 'edit comment', -'edit post': 'edit post', -'edit profile': 'Editar perfil', -'export as csv file': 'exportar como ficheiro csv', -'insert new': 'inserir novo', -'insert new %s': 'inserir novo %s', -'invalid request': 'Pedido Inválido', -'login': 'login', -'logout': 'logout', -'new record inserted': 'novo registo inserido', -'next 100 rows': 'próximas 100 linhas', -'or import from csv file': 'ou importe a partir de ficheiro csv', -'previous 100 rows': '100 linhas anteriores', -'record': 'registo', -'record does not exist': 'registo inexistente', -'record id': 'id de registo', -'register': 'register', -'search category': 'search category', -'search comment': 'search comment', -'search post': 'search post', -'select category': 'select category', -'select comment': 'select comment', -'select post': 'select post', -'selected': 'seleccionado(s)', -'show category': 'show category', -'show comment': 'show comment', -'show post': 'show post', -'state': 'estado', -'table': 'tabela', -'unable to parse csv file': 'não foi possível carregar ficheiro csv', -} - diff --git a/applications/welcome/languages/ro.py b/applications/welcome/languages/ro.py new file mode 100644 index 00000000..05c09b50 --- /dev/null +++ b/applications/welcome/languages/ro.py @@ -0,0 +1,354 @@ +# coding: utf8 +{ +'!=': '!=', +'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" (actualizează) este o expresie opțională precum "câmp1=\'valoare_nouă\'". Nu puteți actualiza sau șterge rezultatele unui JOIN', +'%(nrows)s records found': '%(nrows)s înregistrări găsite', +'%Y-%m-%d': '%Y-%m-%d', +'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'%s rows deleted': '%s linii șterse', +'%s rows updated': '%s linii actualizate', +'(something like "it-it")': '(ceva ce seamănă cu "it-it")', +'<': '<', +'<=': '<=', +'=': '=', +'>': '>', +'>=': '>=', +'A new version of web2py is available': 'O nouă versiune de web2py este disponibilă', +'A new version of web2py is available: %s': 'O nouă versiune de web2py este disponibilă: %s', +'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENȚIE: Nu vă puteți conecta decât utilizând o conexiune securizată (HTTPS) sau rulând aplicația pe computerul local.', +'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENȚIE: Nu puteți efectua mai multe teste o dată deoarece lansarea în execuție a mai multor subpocese nu este sigură.', +'ATTENTION: you cannot edit the running application!': 'ATENȚIE: nu puteți edita o aplicație în curs de execuție!', +'About': 'Despre', +'About application': 'Despre aplicație', +'Access Control': 'Control acces', +'Add': 'Adaugă', +'Admin is disabled because insecure channel': 'Adminstrarea este dezactivată deoarece conexiunea nu este sigură', +'Admin is disabled because unsecure channel': 'Administrarea este dezactivată deoarece conexiunea nu este securizată', +'Administration': 'Administrare', +'Administrative Interface': 'Interfață administrare', +'Administrator Password:': 'Parolă administrator:', +'Ajax Recipes': 'Rețete Ajax', +'And': 'Și', +'Are you sure you want to delete file "%s"?': 'Sigur ștergeți fișierul "%s"?', +'Are you sure you want to delete this object?': 'Sigur ștergeți acest obiect?', +'Are you sure you want to uninstall application "%s"': 'Sigur dezinstalați aplicația "%s"', +'Are you sure you want to uninstall application "%s"?': 'Sigur dezinstalați aplicația "%s"?', +'Authentication': 'Autentificare', +'Available databases and tables': 'Baze de date și tabele disponibile', +'Back': 'Înapoi', +'Buy this book': 'Cumpără această carte', +'Cache Keys': 'Chei cache', +'Cannot be empty': 'Nu poate fi vid', +'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'Compilare imposibilă: aplicația conține erori. Debogați aplicația și încercați din nou.', +'Change Password': 'Schimbare parolă', +'Change password': 'Schimbare parolă', +'Check to delete': 'Coșați pentru a șterge', +'Clear': 'Golește', +'Client IP': 'IP client', +'Community': 'Comunitate', +'Components and Plugins': 'Componente și plugin-uri', +'Controller': 'Controlor', +'Controllers': 'Controlori', +'Copyright': 'Drepturi de autor', +'Create new application': 'Creați aplicație nouă', +'Current request': 'Cerere curentă', +'Current response': 'Răspuns curent', +'Current session': 'Sesiune curentă', +'DB Model': 'Model bază de date', +'DESIGN': 'DESIGN', +'Database': 'Baza de date', +'Date and Time': 'Data și ora', +'Delete': 'Șterge', +'Delete:': 'Șterge:', +'Demo': 'Demo', +'Deploy on Google App Engine': 'Instalare pe Google App Engine', +'Deployment Recipes': 'Rețete de instalare', +'Description': 'Descriere', +'Design for': 'Design pentru', +'Disk Cache Keys': 'Chei cache de disc', +'Documentation': 'Documentație', +"Don't know what to do?": 'Nu știți ce să faceți?', +'Download': 'Descărcare', +'E-mail': 'E-mail', +'E-mail invalid': 'E-mail invalid', +'EDIT': 'EDITARE', +'Edit': 'Editare', +'Edit Profile': 'Editare profil', +'Edit This App': 'Editați această aplicație', +'Edit application': 'Editare aplicație', +'Edit current record': 'Editare înregistrare curentă', +'Editing file': 'Editare fișier', +'Editing file "%s"': 'Editare fișier "%s"', +'Email and SMS': 'E-mail și SMS', +'Error logs for "%(app)s"': 'Log erori pentru "%(app)s"', +'Errors': 'Erori', +'Export': 'Export', +'FAQ': 'Întrebări frecvente', +'False': 'Neadevărat', +'First name': 'Prenume', +'Forbidden': 'Interzis', +'Forms and Validators': 'Formulare și validatori', +'Free Applications': 'Aplicații gratuite', +'Functions with no doctests will result in [passed] tests.': 'Funcțiile fără doctests vor genera teste [trecute].', +'Group %(group_id)s created': 'Grup %(group_id)s creat', +'Group ID': 'ID grup', +'Group uniquely assigned to user %(id)s': 'Grup asociat în mod unic utilizatorului %(id)s', +'Groups': 'Grupuri', +'Hello World': 'Salutare lume', +'Home': 'Acasă', +'How did you get here?': 'Cum ați ajuns aici?', +'Import/Export': 'Import/Export', +'Index': 'Index', +'Installed applications': 'Aplicații instalate', +'Internal State': 'Stare internă', +'Introduction': 'Introducere', +'Invalid Query': 'Interogare invalidă', +'Invalid action': 'Acțiune invalidă', +'Invalid email': 'E-mail invalid', +'Invalid password': 'Parolă invalidă', +'Language files (static strings) updated': 'Fișierele de limbă (șirurile statice de caractere) actualizate', +'Languages': 'Limbi', +'Last name': 'Nume', +'Last saved on:': 'Ultima salvare:', +'Layout': 'Șablon', +'Layout Plugins': 'Șablon plugin-uri', +'Layouts': 'Șabloane', +'License for': 'Licență pentru', +'Live Chat': 'Chat live', +'Logged in': 'Logat', +'Logged out': 'Delogat', +'Login': 'Autentificare', +'Login to the Administrative Interface': 'Logare interfață de administrare', +'Logout': 'Ieșire', +'Lost Password': 'Parolă pierdută', +'Lost password?': 'Parolă pierdută?', +'Main Menu': 'Meniu principal', +'Menu Model': 'Model meniu', +'Models': 'Modele', +'Modules': 'Module', +'My Sites': 'Site-urile mele', +'NO': 'NU', +'Name': 'Nume', +'New': 'Nou', +'New Record': 'Înregistrare nouă', +'New password': 'Parola nouă', +'No databases in this application': 'Aplicație fără bază de date', +'Object or table name': 'Obiect sau nume de tabel', +'Old password': 'Parola veche', +'Online examples': 'Exemple online', +'Or': 'Sau', +'Origin': 'Origine', +'Original/Translation': 'Original/Traducere', +'Other Plugins': 'Alte plugin-uri', +'Other Recipes': 'Alte rețete', +'Overview': 'Prezentare de ansamblu', +'Password': 'Parola', +"Password fields don't match": 'Câmpurile de parolă nu se potrivesc', +'Peeking at file': 'Vizualizare fișier', +'Plugins': 'Plugin-uri', +'Powered by': 'Pus în mișcare de', +'Preface': 'Prefață', +'Profile': 'Profil', +'Python': 'Python', +'Query': 'Interogare', +'Query:': 'Interogare:', +'Quick Examples': 'Exemple rapide', +'RAM Cache Keys': 'Chei cache RAM', +'Recipes': 'Rețete', +'Record ID': 'ID înregistrare', +'Register': 'Înregistrare', +'Registration identifier': 'Identificator de autentificare', +'Registration key': 'Cheie înregistrare', +'Registration successful': 'Autentificare reușită', +'Remember me (for 30 days)': 'Ține-mă minte (timp de 30 de zile)', +'Request reset password': 'Cerere resetare parolă', +'Reset Password key': 'Cheie restare parolă', +'Resolve Conflict file': 'Fișier rezolvare conflict', +'Role': 'Rol', +'Rows in table': 'Linii în tabel', +'Rows selected': 'Linii selectate', +'Save profile': 'Salvează profil', +'Saved file hash:': 'Hash fișier salvat:', +'Search': 'Căutare', +'Semantic': 'Semantică', +'Services': 'Servicii', +'Static files': 'Fișiere statice', +'Stylesheet': 'Foaie de stiluri', +'Submit': 'Înregistrează', +'Support': 'Suport', +'Sure you want to delete this object?': 'Sigur ștergeți acest obiect?', +'Table name': 'Nume tabel', +'Testing application': 'Testare aplicație', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Interogarea (query)" este o condiție de tipul "db.tabel1.câmp1==\'valoare\'". Ceva de genul "db.tabel1.câmp1==db.tabel2.câmp2" generează un JOIN SQL.', +'The Core': 'Nucleul', +'The Views': 'Vederile', +'The output of the file is a dictionary that was rendered by the view': 'Fișierul produce un dicționar care a fost prelucrat de vederea', +'There are no controllers': 'Nu există controlori', +'There are no models': 'Nu există modele', +'There are no modules': 'Nu există module', +'There are no static files': 'Nu există fișiere statice', +'There are no translators, only default language is supported': 'Nu există traduceri, doar limba implicită este suportată', +'There are no views': 'Nu există vederi', +'This App': 'Această aplicație', +'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', +'Timestamp': 'Moment în timp (timestamp)', +'True': 'Adevărat', +'Twitter': 'Twitter', +'Unable to check for upgrades': 'Imposibil de verificat dacă există actualizări', +'Unable to download': 'Imposibil de descărcat', +'Unable to download app': 'Imposibil de descărcat aplicația', +'Update:': 'Actualizare:', +'Upload existing application': 'Încarcă aplicația existentă', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Folosiți (...)&(...) pentru AND, (...)|(...) pentru OR, și ~(...) pentru NOT, pentru a crea interogări complexe.', +'User %(id)s Logged-in': 'Utilizator %(id)s autentificat', +'User %(id)s Logged-out': 'Utilizator %(id)s delogat', +'User %(id)s Password changed': 'Parola utilizatorului %(id)s a fost schimbată', +'User %(id)s Password reset': 'Resetare parola utilizator %(id)s', +'User %(id)s Profile updated': 'Profil utilizator %(id)s actualizat', +'User %(id)s Registered': 'Utilizator %(id)s înregistrat', +'User ID': 'ID utilizator', +'Verify Password': 'Verifică parola', +'Videos': 'Video-uri', +'View': 'Vedere', +'Views': 'Vederi', +'Welcome': 'Bine ați venit', +'Welcome %s': 'Bine ați venit %s', +'Welcome to web2py': 'Bun venit la web2py', +'Welcome to web2py!': 'Bun venit la web2py!', +'Which called the function': 'Care a apelat funcția', +'YES': 'DA', +'You are successfully running web2py': 'Rulați cu succes web2py', +'You can modify this application and adapt it to your needs': 'Puteți modifica și adapta aplicația nevoilor dvs.', +'You visited the url': 'Ați vizitat adresa', +'about': 'despre', +'additional code for your application': 'cod suplimentar pentru aplicația dvs.', +'admin disabled because no admin password': 'administrare dezactivată deoarece parola de administrator nu a fost furnizată', +'admin disabled because not supported on google app engine': 'administrare dezactivată deoarece funcționalitatea nu e suportat pe Google App Engine', +'admin disabled because unable to access password file': 'administrare dezactivată deoarece nu există acces la fișierul cu parole', +'and rename it (required):': 'și renumiți (obligatoriu):', +'and rename it:': ' și renumiți:', +'appadmin': 'appadmin', +'appadmin is disabled because insecure channel': 'appadmin dezactivat deoarece conexiunea nu e sigură', +'application "%s" uninstalled': 'aplicația "%s" a fost dezinstalată', +'application compiled': 'aplicația a fost compilată', +'application is compiled and cannot be designed': 'aplicația este compilată și nu poate fi editată', +'cache': 'cache', +'cache, errors and sessions cleaned': 'cache, erori și sesiuni golite', +'cannot create file': 'fișier imposibil de creat', +'cannot upload file "%(filename)s"': 'imposibil de încărcat fișierul "%(filename)s"', +'change password': 'schimbare parolă', +'check all': 'coșați tot', +'clean': 'golire', +'click to check for upgrades': 'Clic pentru a verifica dacă există upgrade-uri', +'compile': 'compilare', +'compiled application removed': 'aplicația compilată a fost ștearsă', +'contains': 'conține', +'controllers': 'controlori', +'create file with filename:': 'crează fișier cu numele:', +'create new application:': 'crează aplicație nouă:', +'crontab': 'crontab', +'currently saved or': 'în prezent salvat sau', +'customize me!': 'Personalizează-mă!', +'data uploaded': 'date încărcate', +'database': 'bază de date', +'database %s select': 'selectare bază de date %s', +'database administration': 'administrare bază de date', +'db': 'db', +'defines tables': 'definire tabele', +'delete': 'șterge', +'delete all checked': 'șterge tot ce e coșat', +'design': 'design', +'done!': 'gata!', +'edit': 'editare', +'edit controller': 'editare controlor', +'edit profile': 'editare profil', +'enter a number between %(min)g and %(max)g': 'introduceți un număr între %(min)g și %(max)g', +'enter an integer between %(min)g and %(max)g': 'introduceți un întreg între %(min)g și %(max)g', +'errors': 'erori', +'export as csv file': 'exportă ca fișier csv', +'exposes': 'expune', +'extends': 'extinde', +'failed to reload module': 'reîncarcare modul nereușită', +'file "%(filename)s" created': 'fișier "%(filename)s" creat', +'file "%(filename)s" deleted': 'fișier "%(filename)s" șters', +'file "%(filename)s" uploaded': 'fișier "%(filename)s" încărcat', +'file "%(filename)s" was not deleted': 'fișierul "%(filename)s" n-a fost șters', +'file "%s" of %s restored': 'fișier "%s" de %s restaurat', +'file changed on disk': 'fișier modificat pe disc', +'file does not exist': 'fișier inexistent', +'file saved on %(time)s': 'fișier salvat %(time)s', +'file saved on %s': 'fișier salvat pe %s', +'help': 'ajutor', +'htmledit': 'editare html', +'includes': 'include', +'insert new': 'adaugă nou', +'insert new %s': 'adaugă nou %s', +'internal error': 'eroare internă', +'invalid password': 'parolă invalidă', +'invalid request': 'cerere invalidă', +'invalid ticket': 'tichet invalid', +'language file "%(filename)s" created/updated': 'fișier de limbă "%(filename)s" creat/actualizat', +'languages': 'limbi', +'languages updated': 'limbi actualizate', +'loading...': 'încarc...', +'located in the file': 'prezentă în fișierul', +'login': 'autentificare', +'logout': 'ieșire', +'merge': 'unește', +'models': 'modele', +'modules': 'module', +'new application "%s" created': 'aplicația nouă "%s" a fost creată', +'new record inserted': 'înregistrare nouă adăugată', +'next 100 rows': 'următoarele 100 de linii', +'or import from csv file': 'sau importă din fișier csv', +'or provide application url:': 'sau furnizează adresă url:', +'pack all': 'împachetează toate', +'pack compiled': 'pachet compilat', +'please input your password again': 'introduceți parola din nou', +'previous 100 rows': '100 de linii anterioare', +'record': 'înregistrare', +'record does not exist': 'înregistrare inexistentă', +'record id': 'id înregistrare', +'register': 'înregistrare', +'remove compiled': 'șterge compilate', +'restore': 'restaurare', +'revert': 'revenire', +'save': 'salvare', +'selected': 'selectat(e)', +'session expired': 'sesiune expirată', +'shell': 'line de commandă', +'site': 'site', +'some files could not be removed': 'anumite fișiere n-au putut fi șterse', +'starts with': 'începe cu', +'state': 'stare', +'static': 'static', +'table': 'tabel', +'test': 'test', +'the application logic, each URL path is mapped in one exposed function in the controller': 'logica aplicației, fiecare rută URL este mapată într-o funcție expusă de controlor', +'the data representation, define database tables and sets': 'reprezentarea datelor, definește tabelele bazei de date și seturile (de date)', +'the presentations layer, views are also known as templates': 'nivelul de prezentare, vederile sunt de asemenea numite și șabloane', +'these files are served without processing, your images go here': 'aceste fișiere sunt servite fără procesare, imaginea se plasează acolo', +'to previous version.': 'la versiunea anterioară.', +'too short': 'prea scurt', +'translation strings for the application': 'șiruri de caractere folosite la traducerea aplicației', +'try': 'încearcă', +'try something like': 'încearcă ceva de genul', +'unable to create application "%s"': 'imposibil de creat aplicația "%s"', +'unable to delete file "%(filename)s"': 'imposibil de șters fișierul "%(filename)s"', +'unable to parse csv file': 'imposibil de analizat fișierul csv', +'unable to uninstall "%s"': 'imposibil de dezinstalat "%s"', +'uncheck all': 'decoșează tot', +'uninstall': 'dezinstalează', +'update': 'actualizează', +'update all languages': 'actualizează toate limbile', +'upload application:': 'incarcă aplicația:', +'upload file:': 'încarcă fișier:', +'value already in database or empty': 'Valoare existentă în baza de date sau vidă', +'versioning': 'versiuni', +'view': 'vedere', +'views': 'vederi', +'web2py Recent Tweets': 'Ultimele tweet-uri web2py', +'web2py is up to date': 'web2py este la zi', +} diff --git a/applications/welcome/languages/ru-ru.py b/applications/welcome/languages/ru.py similarity index 100% rename from applications/welcome/languages/ru-ru.py rename to applications/welcome/languages/ru.py diff --git a/applications/welcome/languages/sk-sk.py b/applications/welcome/languages/sk.py similarity index 100% rename from applications/welcome/languages/sk-sk.py rename to applications/welcome/languages/sk.py diff --git a/applications/welcome/languages/uk.py b/applications/welcome/languages/uk.py new file mode 100644 index 00000000..a01a7dc0 --- /dev/null +++ b/applications/welcome/languages/uk.py @@ -0,0 +1,177 @@ +# coding: utf8 +{ +'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"Оновити" це додатковий вираз, такий, як "field1=\'нове_значення\'". Ви не можете змінювати або вилучати дані об\'єднаних таблиць.', +'%Y-%m-%d': '%Y/%m/%d', +'%Y-%m-%d %H:%M:%S': '%Y/%m/%d %H:%M:%S', +'%s rows deleted': '%s рядків вилучено', +'%s rows updated': '%s рядків оновлено', +'About': 'Про додаток', +'Access Control': 'Контроль доступу', +'Administrative Interface': 'Адміністративний інтерфейс', +'Ajax Recipes': 'Рецепти для Ajax', +'Are you sure you want to delete this object?': "Ви впевнені, що хочете вилучити цей об'єкт?", +'Available databases and tables': 'Доступні бази даних та таблиці', +'Buy this book': 'Купити книжку', +'Cache Keys': 'Ключі кешу', +'Cannot be empty': 'Порожнє значення неприпустиме', +'Change password': 'Змінити пароль', +'Check to delete': 'Позначити для вилучення', +'Check to delete:': 'Позначте для вилучення:', +'Client IP': 'IP клієнта', +'Community': 'Спільнота', +'Components and Plugins': 'Компоненти та втулки', +'Controller': 'Контролер', +'Copyright': 'Правовласник', +'Current request': 'Поточний запит (current request)', +'Current response': 'Поточна відповідь (current response)', +'Current session': 'Поточна сесія (current session)', +'DB Model': 'Модель БД', +'Database': 'База даних', +'Delete:': 'Вилучити:', +'Demo': 'Демо', +'Deployment Recipes': 'Способи розгортання', +'Description': 'Опис', +'Disk Cache Keys': 'Ключі дискового кешу', +'Documentation': 'Документація', +"Don't know what to do?": 'Не знаєте що робити далі?', +'Download': 'Завантажити', +'E-mail': 'Ел.пошта', +'Edit Page': 'Редагувати сторінку', +'Edit current record': 'Редагувати поточний запис', +'Email and SMS': 'Ел.пошта та SMS', +'Error!': 'Помилка!', +'Errors': 'Помилки', +'Errors in form, please check it out.': 'У формі є помилка. Виправте її, будь-ласка.', +'FAQ': 'ЧаПи (FAQ)', +'First name': "Ім'я", +'Forms and Validators': 'Форми та коректність даних', +'Free Applications': 'Вільні додатки', +'Group %(group_id)s created': 'Групу %(group_id)s створено', +'Group ID': 'Ідентифікатор групи', +'Group uniquely assigned to user %(id)s': "Група унікально зв'язана з користувачем %(id)s", +'Groups': 'Групи', +'Hello World': 'Привіт, світ!', +'Home': 'Початок', +'How did you get here?': 'Як цього було досягнуто?', +'Import/Export': 'Імпорт/Експорт', +'Internal State': 'Внутрішній стан', +'Introduction': 'Введення', +'Invalid Query': 'Помилковий запит', +'Invalid email': 'Невірна адреса ел.пошти', +'Invalid login': "Невірне ім'я користувача", +'Invalid password': 'Невірний пароль', +'Last name': 'Прізвище', +'Layout': 'Макет (Layout)', +'Layout Plugins': 'Втулки макетів', +'Layouts': 'Макети', +'Live Chat': 'Чат', +'Logged in': 'Вхід здійснено', +'Logged out': 'Вихід здійснено', +'Login': 'Вхід', +'Logout': 'Вихід', +'Lost Password': 'Забули пароль', +'Lost password?': 'Забули пароль?', +'Menu Model': 'Модель меню', +'My Sites': 'Сайт (усі додатки)', +'Name': "Ім'я", +'New Record': 'Новий запис', +'New password': 'Новий пароль', +'No databases in this application': 'Даний додаток не використовує базу даних', +'Object or table name': "Об'єкт або назва таблиці", +'Old password': 'Старий пароль', +'Online examples': 'Зразковий демо-сайт', +'Origin': 'Походження', +'Other Plugins': 'Інші втулки', +'Other Recipes': 'Інші рецепти', +'Overview': 'Огляд', +'Page Not Found!': 'Сторінку не знайдено!', +'Page saved': 'Сторінку збережено', +'Password': 'Пароль', +'Password changed': 'Пароль змінено', +"Password fields don't match": 'Пароль не співпав', +'Plugins': 'Втулки (Plugins)', +'Powered by': 'Працює на', +'Preface': 'Передмова', +'Profile': 'Параметри', +'Profile updated': 'Параметри змінено', +'Python': 'Мова Python', +'Query:': 'Запит:', +'Quick Examples': 'Швидкі приклади', +'RAM Cache Keys': "Ключі кешу в пам'яті", +'Recipes': 'Рецепти', +'Record %(id)s updated': 'Запис %(id)s змінено', +'Record ID': 'Ід.запису', +'Record Updated': 'Запис змінено', +'Register': 'Реєстрація', +'Registration identifier': 'Реєстраційний ідентифікатор', +'Registration key': 'Реєстраційний ключ', +'Registration successful': 'Реєстрація пройшла успішно', +'Remember me (for 30 days)': "Запам'ятати мене (на 30 днів)", +'Request reset password': 'Запит на зміну пароля', +'Reset Password key': 'Ключ скидання пароля', +'Role': 'Роль', +'Rows in table': 'Рядки в таблиці', +'Rows selected': 'Відмічено рядків', +'Save profile': 'Зберегти параметри', +'Semantic': 'Семантика', +'Services': 'Сервіс', +'Stylesheet': 'CSS-стилі', +'Submit': 'Застосувати', +'Support': 'Підтримка', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Запит" це умова, на зразок "db.table1.field1==\'значення\'". Вираз "db.table1.field1==db.table2.field2" повертає результат об\'єднання (SQL JOIN) таблиць.', +'The Core': 'Ядро', +'The Views': 'Відображення (Views)', +'The output of the file is a dictionary that was rendered by the view': 'Результат функції - словник пар (назва=значення) було відображено з допомогою відображення (view)', +'This App': 'Цей додаток', +'Timestamp': 'Відмітка часу', +'Twitter': 'Твіттер', +'Update:': 'Оновити:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Для створення складних запитів використовуйте (...)&(...) замість AND, (...)|(...) замість OR, та ~(...) замість NOT.', +'User %(id)s Logged-in': 'Користувач %(id)s увійшов', +'User %(id)s Logged-out': 'Користувач %(id)s вийшов', +'User %(id)s Password changed': 'Користувач %(id)s змінив свій пароль', +'User %(id)s Password reset': 'Користувач %(id)s скинув пароль', +'User %(id)s Profile updated': 'Параметри користувача %(id)s змінено', +'User %(id)s Registered': 'Користувач %(id)s зареєструвався', +'User ID': 'Ід.користувача', +'Verify Password': 'Повторити пароль', +'Videos': 'Відео', +'View': 'Відображення (View)', +'Welcome': 'Ласкаво просимо', +'Welcome to web2py!': 'Ласкаво просимо до web2py!', +'Which called the function': 'Управління передалось функції', +'You are successfully running web2py': 'Ви успішно запустили web2py', +'You can modify this application and adapt it to your needs': 'Ви можете модифікувати цей додаток і адаптувати його до своїх потреб', +'You visited the url': 'Ви відвідали наступну адресу:', +'appadmin is disabled because insecure channel': 'appadmin вимкнено через те, що використовується незахищений канал', +'cache': 'кеш', +'customize me!': 'причепуріть мене!', +'data uploaded': 'дані завантажено', +'database': 'база даних', +'database %s select': 'Вибірка з бази даних %s', +'db': 'бд', +'design': 'налаштування', +'done!': 'зроблено!', +'edit': 'редагувати', +'enter a value': 'введіть значення', +'enter an integer between %(min)g and %(max)g': 'введіть ціле число між %(min)g та %(max)g', +'export as csv file': 'експортувати як файл csv', +'insert new': 'Створити новий запис', +'insert new %s': 'створити новий запис %s', +'invalid request': 'хибний запит', +'located in the file': 'яка розташована у файлі', +'new record inserted': 'новий рядок додано', +'next 100 rows': 'наступні 100 рядків', +'or import from csv file': 'або імпортувати з csv-файлу', +'please input your password again': 'Будь-ласка введіть пароль ще раз', +'previous 100 rows': 'попередні 100 рядків', +'record': 'запис', +'record does not exist': 'запису не існує', +'record id': 'ід. запису', +'selected': 'запис(ів) вибрано', +'state': 'стан', +'table': 'Таблиця', +'too short': 'Занадто короткий', +'unable to parse csv file': 'не вдається розібрати csv-файл', +'value already in database or empty': 'значення вже в базі даних або порожнє', +} diff --git a/applications/welcome/languages/zh-tw.py b/applications/welcome/languages/zh.py similarity index 100% rename from applications/welcome/languages/zh-tw.py rename to applications/welcome/languages/zh.py diff --git a/applications/welcome/static/css/bootswatch.css b/applications/welcome/static/css/bootswatch.css new file mode 100644 index 00000000..961896c1 --- /dev/null +++ b/applications/welcome/static/css/bootswatch.css @@ -0,0 +1,85 @@ +body { + padding-top: 90px; /* container go all the way to the bottom of the topbar */ + height:auto; /*to avoid vertical scroll bar*/ +} + +h1,h2,h3,h4,h5,h6 {font-family: inherit;} + +li {margin-bottom: 0;} /*bootswatch*/ + +.auth_navbar, .navbar .btn-group{padding:0;} + +@media only screen and (max-width: 320px) { + .navbar-inner{position:relative;} + #navbar{float:none;position:absolute;bottom:-10px;left:4px;} +} + +.jumbotron h1 { + margin-bottom: 9px; + font-size: 81px; + font-weight: bold; + letter-spacing: -1px; + line-height: 1; +} + +.subhead h1 { + font-size: 54px; +} + +.jumbotron small { + font-size: 20px; + font-weight: 300; +} + +/* bootstrap dropdown */ + +.dropdown-menu ul { + left: 100%; + position: absolute; + top: 0; + visibility: hidden; + margin-top: -1px; +} + +.dropdown-menu li:hover ul { + visibility: visible; +} + +.navbar .dropdown-menu ul:before { + border-bottom: 7px solid transparent; + border-left: none; + border-right: 7px solid rgba(0, 0, 0, 0.2); + border-top: 7px solid transparent; + left: -7px; + top: 5px; +} + +.navbar .dropdown-menu ul:after { + border-top: 6px solid transparent; + border-left: none; + border-right: 6px solid #fff; + border-bottom: 6px solid transparent; + left: 10px; + top: 6px; + left: -6px; +} + +.dropdown-menu span{ + display:inline-block; +} + +.icon-chevron-right { + border-left: 4px solid #000; + border-right: 4px solid transparent; + border-bottom: 4px solid transparent; + border-top: 4px solid transparent; + content: ""; + display: inline-block; + height: 0; + opacity: 0.7; + vertical-align: top; + width: 0; + margin-right:-13px; + margin-top: 7px; + float:right; +} diff --git a/applications/welcome/static/css/bootswatch_nojs.css b/applications/welcome/static/css/bootswatch_nojs.css new file mode 100644 index 00000000..2b75915e --- /dev/null +++ b/applications/welcome/static/css/bootswatch_nojs.css @@ -0,0 +1,38 @@ +.nav > li.dropdown > a:after { + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + content: ""; + display: inline-block; + height: 0; + opacity: 0.7; + vertical-align: top; + width: 0; + + margin-left: 2px; + margin-top: 8px; + + border-bottom-color: #FFFFFF; + border-top-color: #FFFFFF; +} + + +ul.dropdown-menu li.dropdown > a:after { + border-left: 4px solid #000; + border-right: 4px solid transparent; + border-bottom: 4px solid transparent; + border-top: 4px solid transparent; + content: ""; + display: inline-block; + height: 0; + opacity: 0.7; + vertical-align: top; + width: 0; + + margin-left: 8px; + margin-top: 6px; +} + +ul.nav li.dropdown:hover ul.dropdown-menu { + display: block; +} \ No newline at end of file diff --git a/applications/welcome/static/css/web2py.css b/applications/welcome/static/css/web2py.css index 359c86d8..2bfead1d 100644 --- a/applications/welcome/static/css/web2py.css +++ b/applications/welcome/static/css/web2py.css @@ -3,7 +3,7 @@ body { margin: 0; padding:0; border: 0; } a { text-decoration:none; white-space: nowrap;} a:hover {text-decoration: underline} a.button {text-decoration: none} -h1,h2,h3,h4,h5,h6 {margin: 0.5em 0 0.25em 0; display: block; font-family: Helvetica} +h1,h2,h3,h4,h5,h6 {margin: 0.5em 0 0.25em 0; display: block; font-family: Helvetica;} h1 { font-size: 4.00em;} h2 { font-size: 3.00em;} h3 { font-size: 2.00em;} @@ -41,7 +41,6 @@ ul { list-style-type: none; margin: 0px; padding: 0px; } html, body { height: 100%; } - .wrapper { min-height: 100%; height: auto !important; @@ -67,9 +66,6 @@ html, body { /* Sticky footer end */ -body { - background-color: #FFFFFF; -} .footer { border-top: 1px #DEDEDE solid; } @@ -97,8 +93,6 @@ td.w2p_fl, td.w2p_fc { padding-top: 4px; } #auth_user_remember__row label {display: inline;} #web2py_user_form td { vertical-align:top; } -a, a:visited, a:hover { color:#0069D6} - /*********** web2py specific ***********/ div.flash { font-weight: bold; @@ -120,6 +114,8 @@ div.flash { -webkit-border-radius: 5px; z-index: 2; } +div.flash {z-index:2000;} + div.error { background-color: red; color: white; @@ -177,7 +173,7 @@ div.error { /* All Mobile Sizes (devices and browser) */ @media only screen and (max-width: 767px) { - +/* removed because of bootswatch .topbar {text-align: center;} #navbar, #menu {float: none;} #navbar {font-size: 1.2em; padding: .6em 0 1.2em;} @@ -185,10 +181,9 @@ div.error { #menu select {font-size: 1.2em; margin: 0; padding: 0;} div.flash {top: 110px; right: 10px;} - +*/ } - /* *Grid * @@ -295,5 +290,14 @@ div.error { #w2p_query_panel {} +.web2py_breadcrumbs ul { + list-style: none; + margin-bottom: 18px; +} + +.web2py_breadcrumbs ul li { + display: inline-block; +} + .ie9 #query_panel {padding-bottom:2px;} diff --git a/applications/welcome/static/js/web2py.js b/applications/welcome/static/js/web2py.js index 6a84c20a..b2f7e8dd 100644 --- a/applications/welcome/static/js/web2py.js +++ b/applications/welcome/static/js/web2py.js @@ -86,7 +86,7 @@ function web2py_ajax_page(method, action, data, target) { var html=xhr.responseText; var content=xhr.getResponseHeader('web2py-component-content'); var command=xhr.getResponseHeader('web2py-component-command'); - var flash=xhr.getResponseHeader('web2py-component-flash'); + var flash=decodeURIComponent(xhr.getResponseHeader('web2py-component-flash')); var t = jQuery('#'+target); if(content=='prepend') t.prepend(html); else if(content=='append') t.append(html); diff --git a/applications/welcome/views/layout.html b/applications/welcome/views/layout.html index ea507d60..7454e378 100644 --- a/applications/welcome/views/layout.html +++ b/applications/welcome/views/layout.html @@ -1,168 +1,182 @@ - - - - - - - - - - - - - - {{=response.title or request.application}} - - - - - - - - - - - - - - - - - - - - {{ - response.files.append(URL('static','css/bootstrap.min.css')) - response.files.append(URL('static','css/web2py.css')) - if response.menu: - response.files.append(URL('static','css/superfish.css')) - response.files.append(URL('static','js/superfish.js')) - pass - }} - - {{include 'web2py_ajax.html'}} - - {{if response.menu:}} - - {{pass}} - - {{ - # 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}} - - -
    -
    -
    -
    - - {{is_mobile=request.user_agent().is_mobile}} - {{if response.menu:}} - - {{pass}} -
    -
    -
    -
    - -
    {{=response.flash or ''}}
    - -
    -
    -
    - -
    - Share - -
    - -
    -
    -
    -
  • - -
    -
    -
    - {{if left_sidebar_enabled:}} - - {{pass}} - -
    - {{block center}} - {{include}} - {{end}} -
    - - {{if right_sidebar_enabled:}} -
    - {{block right_sidebar}} -

    Right Sidebar

    -

    - {{end}} -
    - {{pass}} -
    -
    -
    - - - - - {{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/web2py.css')) + response.files.append(URL('static','css/bootswatch.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 ''}}
    + +
    + +
    + +
    + Share + +
    + +
    + +
    +
    + {{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/__init__.py b/gluon/__init__.py index f5bfa2cd..b1dde0cb 100644 --- a/gluon/__init__.py +++ b/gluon/__init__.py @@ -10,7 +10,7 @@ Web2Py framework modules ======================== """ -__all__ = ['A', 'B', 'BEAUTIFY', 'BODY', 'BR', 'CAT', 'CENTER', 'CLEANUP', 'CODE', 'CRYPT', 'DAL', 'DIV', 'EM', 'EMBED', 'FIELDSET', 'FORM', 'Field', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEAD', 'HR', 'HTML', 'HTTP', 'I', 'IFRAME', 'IMG', 'INPUT', 'IS_ALPHANUMERIC', 'IS_DATE', 'IS_DATETIME', 'IS_DATETIME_IN_RANGE', 'IS_DATE_IN_RANGE', 'IS_DECIMAL_IN_RANGE', 'IS_EMAIL', 'IS_EMPTY_OR', 'IS_EQUAL_TO', 'IS_EXPR', 'IS_FLOAT_IN_RANGE', 'IS_IMAGE', 'IS_INT_IN_RANGE', 'IS_IN_DB', 'IS_IN_SET', 'IS_IPV4', 'IS_LENGTH', 'IS_LIST_OF', 'IS_LOWER', 'IS_MATCH', 'IS_NOT_EMPTY', 'IS_NOT_IN_DB', 'IS_NULL_OR', 'IS_SLUG', 'IS_STRONG', 'IS_TIME', 'IS_UPLOAD_FILENAME', 'IS_UPPER', 'IS_URL', 'LABEL', 'LEGEND', 'LI', 'LINK', 'LOAD', 'MARKMIN', 'MENU', 'META', 'OBJECT', 'OL', 'ON', 'OPTGROUP', 'OPTION', 'P', 'PRE', 'SCRIPT', 'SELECT', 'SPAN', 'SQLFORM', 'SQLTABLE', 'STYLE', 'TABLE', 'TAG', 'TBODY', 'TD', 'TEXTAREA', 'TFOOT', 'TH', 'THEAD', 'TITLE', 'TR', 'TT', 'UL', 'URL', 'XHTML', 'XML','redirect','current','embed64'] +__all__ = ['A', 'B', 'BEAUTIFY', 'BODY', 'BR', 'CAT', 'CENTER', 'CLEANUP', 'CODE', 'CRYPT', 'DAL', 'DIV', 'EM', 'EMBED', 'FIELDSET', 'FORM', 'Field', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEAD', 'HR', 'HTML', 'HTTP', 'I', 'IFRAME', 'IMG', 'INPUT', 'IS_ALPHANUMERIC', 'IS_DATE', 'IS_DATETIME', 'IS_DATETIME_IN_RANGE', 'IS_DATE_IN_RANGE', 'IS_DECIMAL_IN_RANGE', 'IS_EMAIL', 'IS_EMPTY_OR', 'IS_EQUAL_TO', 'IS_EXPR', 'IS_FLOAT_IN_RANGE', 'IS_IMAGE', 'IS_INT_IN_RANGE', 'IS_IN_DB', 'IS_IN_SET', 'IS_IPV4', 'IS_LENGTH', 'IS_LIST_OF', 'IS_LOWER', 'IS_MATCH', 'IS_NOT_EMPTY', 'IS_NOT_IN_DB', 'IS_NULL_OR', 'IS_SLUG', 'IS_STRONG', 'IS_TIME', 'IS_UPLOAD_FILENAME', 'IS_UPPER', 'IS_URL', 'LABEL', 'LEGEND', 'LI', 'LINK', 'LOAD', 'MARKMIN', 'MENU', 'META', 'OBJECT', 'OL', 'ON', 'OPTGROUP', 'OPTION', 'P', 'PRE', 'SCRIPT', 'SELECT', 'SPAN', 'SQLFORM', 'SQLTABLE', 'STRONG', 'STYLE', 'TABLE', 'TAG', 'TBODY', 'TD', 'TEXTAREA', 'TFOOT', 'TH', 'THEAD', 'TITLE', 'TR', 'TT', 'UL', 'URL', 'XHTML', 'XML','redirect','current','embed64'] from globals import current from html import * diff --git a/gluon/dal.py b/gluon/dal.py index d4378eb9..09fbb747 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -638,37 +638,47 @@ class BaseAdapter(ConnectionPool): ftype = field.type.native or field.type.type elif field.type.startswith('reference'): referenced = field.type[10:].strip() + if referenced == '.': + referenced = tablename constraint_name = self.constraint_name(tablename, field.name) - if hasattr(table,'_primarykey'): - rtablename,rfieldname = referenced.split('.') - rtable = table._db[rtablename] - rfield = rtable[rfieldname] - # must be PK reference or unique - if rfieldname in rtable._primarykey or rfield.unique: - ftype = self.types[rfield.type[:9]] % dict(length=rfield.length) - # multicolumn primary key reference? - if not rfield.unique and len(rtable._primarykey)>1 : - # then it has to be a table level FK - if rtablename not in TFK: - TFK[rtablename] = {} - TFK[rtablename][rfieldname] = field.name - else: - ftype = ftype + \ - self.types['reference FK'] %dict(\ + if not '.' in referenced \ + and referenced != tablename \ + and hasattr(table,'_primarykey'): + ftype = self.types['integer'] + else: + if hasattr(table,'_primarykey'): + rtablename,rfieldname = referenced.split('.') + rtable = table._db[rtablename] + rfield = rtable[rfieldname] + # must be PK reference or unique + if rfieldname in rtable._primarykey or rfield.unique: + ftype = self.types[rfield.type[:9]] % \ + dict(length=rfield.length) + # multicolumn primary key reference? + if not rfield.unique and len(rtable._primarykey)>1: + # then it has to be a table level FK + if rtablename not in TFK: + TFK[rtablename] = {} + TFK[rtablename][rfieldname] = field.name + else: + ftype = ftype + self.types['reference FK'] \ + % dict( constraint_name=constraint_name, table_name=tablename, field_name=field.name, foreign_key='%s (%s)'%(rtablename, rfieldname), on_delete_action=field.ondelete) - else: - # make a guess here for circular references - id_fieldname = referenced in table._db and table._db[referenced]._id.name or 'id' - ftype = self.types[field.type[:9]]\ - % dict(table_name=tablename, - field_name=field.name, - constraint_name=constraint_name, - foreign_key=referenced + ('(%s)' % id_fieldname), - on_delete_action=field.ondelete) + else: + # make a guess here for circular references + id_fieldname = referenced in table._db \ + and table._db[referenced]._id.name or 'id' + ftype = self.types[field.type[:9]] % \ + dict(table_name=tablename, + field_name=field.name, + constraint_name=constraint_name, + foreign_key=referenced + \ + ('(%s)' % id_fieldname), + on_delete_action=field.ondelete) elif field.type.startswith('list:reference'): ftype = self.types[field.type[:14]] elif field.type.startswith('decimal'): @@ -679,8 +689,8 @@ class BaseAdapter(ConnectionPool): srid = self.srid geotype, parms = field.type[:-1].split('(') if not geotype in self.types: - raise SyntaxError, 'Field: unknown field type: %s for %s' % \ - (field.type, field.name) + raise SyntaxError, 'Field: unknown field type: %s for %s' \ + % (field.type, field.name) ftype = self.types[geotype] if self.dbengine == 'postgres' and geotype == 'geometry': # parameters: schema, srid, dimension @@ -1137,6 +1147,8 @@ class BaseAdapter(ConnectionPool): return str(self.represent(expression,field_type)) elif isinstance(expression,(list,tuple)): return ','.join(self.represent(item,field_type) for item in expression) + elif isinstance(expression, bool): + return '1' if expression else '0' else: return str(expression) @@ -1480,7 +1492,10 @@ class BaseAdapter(ConnectionPool): if isinstance(obj, CALLABLETYPES): obj = obj() if isinstance(fieldtype, SQLCustomType): - return fieldtype.encoder(obj) + value = fieldtype.encoder(obj) + if fieldtype.type in ('string','text'): + return self.adapt(value) + return value if isinstance(obj, (Expression, Field)): return str(obj) if fieldtype.startswith('list:'): @@ -2173,7 +2188,7 @@ class PostgreSQLAdapter(BaseAdapter): self.srid = srid self.find_or_make_work_folder() library, uri = uri.split('://')[:2] - m = re.compile('^(?P[^:@]+)(\:(?P[^@]*))?@(?P[^\:@/]+)(\:(?P[0-9]+))?/(?P[^\?]+)(\?sslmode=(?P.+))?$').match(uri) + m = re.compile('^(?P[^:@]+)(\:(?P[^@]*))?@(?P[^\:@]+)(\:(?P[0-9]+))?/(?P[^\?]+)(\?sslmode=(?P.+))?$').match(uri) if not m: raise SyntaxError, "Invalid URI string in DAL" user = credential_decoder(m.group('user')) @@ -3490,7 +3505,7 @@ class SAPDBAdapter(BaseAdapter): self.db_codec = db_codec self.find_or_make_work_folder() uri = uri.split('://')[1] - m = re.compile('^(?P[^:@]+)(\:(?P[^@]*))?@(?P[^\:@/]+)(\:(?P[0-9]+))?/(?P[^\?]+)(\?sslmode=(?P.+))?$').match(uri) + m = re.compile('^(?P[^:@]+)(\:(?P[^@]*))?@(?P[^\:@]+)(\:(?P[0-9]+))?/(?P[^\?]+)(\?sslmode=(?P.+))?$').match(uri) if not m: raise SyntaxError, "Invalid URI string in DAL" user = credential_decoder(m.group('user')) @@ -4112,11 +4127,9 @@ class GoogleDatastoreAdapter(NoSQLAdapter): def select(self,query,fields,attributes): (items, tablename, fields) = self.select_raw(query,fields,attributes) # self.db['_lastsql'] = self._select(query,fields,attributes) - rows = [] - for item in items: - rows.append([ - t=='id' and item.key().id_or_name() or getattr(item, t) \ - for t in fields]) + rows = [[(t=='id' and item.key().id_or_name()) or \ + (t=='nativeRef' and item) or getattr(item, t) \ + for t in fields] for item in items] colnames = ['%s.%s' % (tablename, t) for t in fields] processor = attributes.get('processor',self.parse) return processor(rows,fields,colnames,False) @@ -5142,7 +5155,7 @@ class IMAPAdapter(NoSQLAdapter): db['_lastsql'] = '' - m = re.compile('^(?P[^:]+)(\:(?P[^@]*))?@(?P[^\:@/]+)(\:(?P[0-9]+))?$').match(uri) + m = re.compile('^(?P[^:]+)(\:(?P[^@]*))?@(?P[^\:@]+)(\:(?P[0-9]+))?$').match(uri) user = m.group('user') password = m.group('password') host = m.group('host') @@ -5315,7 +5328,7 @@ class IMAPAdapter(NoSQLAdapter): sub_items = [sub_item for sub_item in sub_items if len(sub_item.strip()) > 0] mailbox = sub_items[len(sub_items) - 1] # remove unwanted characters and store original names - mailbox_name = mailbox.replace("[", "").replace("]", "").replace("/", "_") + mailbox_name = re.sub('[^_\w]','',re.sub('[/ ]','_',mailbox)) mailboxes.append(mailbox_name) self.connection.mailbox_names[mailbox_name] = mailbox # print "Mailboxes query", mailboxes @@ -6023,6 +6036,10 @@ class Row(dict): def __setattr__(self, key, value): self[key] = value + def __str__(self): + ### this could be made smarter + return '' + def __repr__(self): return '' @@ -6582,6 +6599,10 @@ def index(): # # print 're3:'+tag field = args[i] if not field in db[table]: break + # hand-built patterns should respect .readable=False as well + if not db[table][field].readable: + return Row({'status':418,'pattern':pattern, + 'error':'I\'m a teapot','response':None}) try: item = dbset.select(db[table][field],limitby=(0,1)).first() except ValueError: @@ -7748,6 +7769,7 @@ class Field(Expression): # True - put uploaded file in # /./uuid_key[:2] # directory) + uploadfs=None # a pyfilesystem where to store upload to be used as argument of DAL.define_table @@ -7784,6 +7806,7 @@ class Field(Expression): represent=None, uploadfolder=None, uploadseparate=False, + uploadfs=None, compute=None, custom_store=None, custom_retrieve=None, @@ -7815,6 +7838,7 @@ class Field(Expression): self.uploadfield = uploadfield self.uploadfolder = uploadfolder self.uploadseparate = uploadseparate + self.uploadfs = uploadfs self.widget = widget if label is DEFAULT: self.label = fieldname.replace('_', ' ').title() @@ -7872,13 +7896,20 @@ class Field(Expression): elif self.db._adapter.folder: path = os.path.join(self.db._adapter.folder, '..', 'uploads') else: - raise RuntimeError, "you must specify a Field(...,uploadfolder=...)" + raise RuntimeError,\ + "you must specify a Field(...,uploadfolder=...)" if self.uploadseparate: - path = os.path.join(path,"%s.%s" % (self._tablename, self.name),uuid_key[:2]) + if self.uploadfs: + raise RuntimeError, "not supported" + path = os.path.join(path,"%s.%s" %(self._tablename, self.name), + uuid_key[:2]) if not os.path.exists(path): os.makedirs(path) pathfilename = os.path.join(path, newfilename) - dest_file = open(pathfilename, 'wb') + if self.uploadfs: + dest_file = self.uploadfs.open(newfilename, 'wb') + else: + dest_file = open(pathfilename, 'wb') try: shutil.copyfileobj(file, dest_file) except IOError: @@ -7902,15 +7933,19 @@ class Field(Expression): file_properties = self.retrieve_file_properties(name,path) filename = file_properties['filename'] if isinstance(self.uploadfield, str): # ## if file is in DB - return (filename, cStringIO.StringIO(row[self.uploadfield] or '')) + stream = cStringIO.StringIO(row[self.uploadfield] or '') elif isinstance(self.uploadfield,Field): blob_uploadfield_name = self.uploadfield.uploadfield query = self.uploadfield == name data = self.uploadfield.table(query)[blob_uploadfield_name] - return (filename, cStringIO.StringIO(data)) + stream = cStringIO.StringIO(data) + elif self.uploadfs: + # ## if file is on pyfilesystem + stream = self.uploadfs.open(name, 'rb') else: - # ## if file is on filesystem - return (filename, open(os.path.join(file_properties['path'], name), 'rb')) + # ## if file is on regular filesystem + stream = open(os.path.join(file_properties['path'], name), 'rb') + return (filename, stream) def retrieve_file_properties(self, name, path=None): if self.custom_retrieve_file_properties: diff --git a/gluon/html.py b/gluon/html.py index a42bd8e1..b9e79219 100644 --- a/gluon/html.py +++ b/gluon/html.py @@ -80,6 +80,7 @@ __all__ = [ 'OPTGROUP', 'SELECT', 'SPAN', + 'STRONG', 'STYLE', 'TABLE', 'TAG', @@ -1320,6 +1321,11 @@ class P(DIV): return text +class STRONG(DIV): + + tag = 'strong' + + class B(DIV): tag = 'b' @@ -2049,6 +2055,9 @@ class BEAUTIFY(DIV): if level == 0: return for c in self.components: + if hasattr(c,'value') and not callable(c.value): + if c.value: + components.append(c.value) if hasattr(c,'xml') and callable(c.xml): components.append(c) continue @@ -2271,10 +2280,10 @@ class web2pyHTMLParser(HTMLParser): data = data.decode('latin1') self.parent.append(data.encode('utf8','xmlcharref')) def handle_charref(self,name): - if name[1].lower()=='x': - self.parent.append(unichr(int(name[2:], 16)).encode('utf8')) + if name.startswith('x'): + self.parent.append(unichr(int(name[1:], 16)).encode('utf8')) else: - self.parent.append(unichr(int(name[1:], 10)).encode('utf8')) + self.parent.append(unichr(int(name)).encode('utf8')) def handle_entityref(self,name): self.parent.append(unichr(name2codepoint[name]).encode('utf8')) def handle_endtag(self, tagname): diff --git a/gluon/languages.py b/gluon/languages.py index 2fd07c9a..cfccf855 100644 --- a/gluon/languages.py +++ b/gluon/languages.py @@ -34,7 +34,7 @@ regex_translate = re.compile(PY_STRING_LITERAL_RE, re.DOTALL) # patter for a valid accept_language regex_language = \ - re.compile('^[a-zA-Z]{2}(\-[a-zA-Z]{2})?(\-[a-zA-Z]+)?$') + re.compile('^([a-zA-Z]{2})(\-[a-zA-Z]{2})?(\-[a-zA-Z]+)?$') def read_dict_aux(filename): @@ -223,28 +223,66 @@ class translator(object): self.force(self.http_accept_language) def force(self, *languages): + 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 + if not languages or languages[0] is None: languages = [] if len(languages) == 1 and isinstance(languages[0], (str, unicode)): languages = languages[0] + if languages: if isinstance(languages, (str, unicode)): - accept_languages = languages.split(';') + parts = languages.split(';') languages = [] - [languages.extend(al.split(',')) for al in accept_languages] - languages = [item.strip().lower() for item in languages \ - if regex_language.match(item.strip())] + [languages.extend(al.split(',')) for al in parts] + possible_languages = self.get_possible_languages() for language in languages: - if language in self.current_languages: - self.accepted_language = language - break - filename = os.path.join(self.folder, 'languages/', language + '.py') - if os.path.exists(filename): - self.accepted_language = language - self.language_file = filename - self.t = read_dict(filename) - return languages + match_language = regex_language.match(language.strip().lower()) + if match_language: + match_language = tuple(part + for part in match_language.groups() + if part) + language = lang_sampling(match_language, + self.current_languages) + if language: + self.accepted_language = language + break + language = lang_sampling(match_language, possible_languages) + if language: + filename = os.path.join( + self.folder,'languages/',language + '.py') + if os.path.exists(filename): + self.accepted_language = language + self.language_file = filename + self.t = read_dict(filename) + return languages self.language_file = None self.t = {} # ## no language by default return languages diff --git a/gluon/main.py b/gluon/main.py index 2f69c6ba..7ddef895 100644 --- a/gluon/main.py +++ b/gluon/main.py @@ -28,6 +28,7 @@ import socket import tempfile import random import string +import urllib2 from fileutils import abspath, write_file, parse_version from settings import global_settings from admin import add_path_first, create_missing_folders, create_missing_app_folders @@ -541,10 +542,9 @@ def wsgibase(environ, responder): # ################################################## if request.cid: - if response.flash and not 'web2py-component-flash' in http_response.headers: http_response.headers['web2py-component-flash'] = \ - str(response.flash).replace('\n','') + urllib2.quote(str(response.flash).replace('\n','')) if response.js and not 'web2py-component-command' in http_response.headers: http_response.headers['web2py-component-command'] = \ response.js.replace('\n','') diff --git a/gluon/rewrite.py b/gluon/rewrite.py index b6ee5f6a..39201a62 100644 --- a/gluon/rewrite.py +++ b/gluon/rewrite.py @@ -397,6 +397,16 @@ def load_routers(all_apps): router.languages = set(router.languages) else: router.languages = set() + if router.functions: + if isinstance(router.functions, (set, tuple, list)): + functions = set(router.functions) + if isinstance(router.default_function, str): + functions.add(router.default_function) # legacy compatibility + router.functions = { router.default_controller: functions } + for controller in router.functions: + router.functions[controller] = set(router.functions[controller]) + else: + router.functions = dict() if app != 'BASE': for base_only in ROUTER_BASE_KEYS: router.pop(base_only, None) @@ -412,16 +422,6 @@ def load_routers(all_apps): if router.controllers: router.controllers.add('static') router.controllers.add(router.default_controller) - if router.functions: - if isinstance(router.functions, (set, tuple, list)): - functions = set(router.functions) - if isinstance(router.default_function, str): - functions.add(router.default_function) # legacy compatibility - router.functions = { router.default_controller: functions } - for controller in router.functions: - router.functions[controller] = set(router.functions[controller]) - else: - router.functions = dict() if isinstance(routers.BASE.applications, str) and routers.BASE.applications == 'ALL': routers.BASE.applications = list(all_apps) diff --git a/gluon/scheduler.py b/gluon/scheduler.py index e189c1d8..49b94121 100644 --- a/gluon/scheduler.py +++ b/gluon/scheduler.py @@ -334,6 +334,8 @@ class Scheduler(MetaScheduler): self.heartbeat = heartbeat self.worker_name = worker_name or socket.gethostname()+'#'+str(web2py_uuid()) self.max_empty_runs = max_empty_runs + self.is_a_ticker = False + self.do_assign_tasks = False from gluon import current current._scheduler = self @@ -388,6 +390,7 @@ class Scheduler(MetaScheduler): Field('first_heartbeat','datetime'), Field('last_heartbeat','datetime'), Field('status',requires=IS_IN_SET(WORKER_STATUS)), + Field('is_ticker', 'boolean', default=False), migrate=migrate) db.commit() @@ -397,34 +400,30 @@ class Scheduler(MetaScheduler): def pop_task(self): now = datetime.datetime.now() db, ts = self.db, self.db.scheduler_task - try: - logging.debug(' grabbing all queued tasks') - all_available = db(ts.status.belongs((QUEUED,RUNNING)))\ - ((ts.times_runnow)\ - (ts.next_run_time<=now)\ - (ts.enabled==True)\ - (ts.group_name.belongs(self.group_names))\ - (ts.assigned_worker_name.belongs((None,'',self.worker_name))) #None? - number_grabbed = all_available.update( - assigned_worker_name=self.worker_name,status=ASSIGNED) - db.commit() - except: - number_grabbed = None - db.rollback() - if number_grabbed: - logging.debug(' grabbed %s tasks' % number_grabbed) - grabbed = db(ts.assigned_worker_name==self.worker_name)\ - (ts.status==ASSIGNED) - task = grabbed.select(limitby=(0,1), orderby=ts.next_run_time).first() + if self.is_a_ticker and self.do_assign_tasks: + #I'm a ticker, and 5 loops passed without reassigning tasks, let's do + #that and loop again + db.commit() #?don't know if it's useful, let's be completely sure + while True: + try: + self.assign_tasks() + db.commit() + break + except: + db.rollback() + logging.error('TICKER: error assigning tasks') + return None + grabbed = db(ts.assigned_worker_name==self.worker_name)\ + (ts.status==ASSIGNED) - logging.debug(' releasing all but one (running)') - if task: - task.update_record(status=RUNNING,last_run_time=now) - grabbed.update(assigned_worker_name='',status=QUEUED) - db.commit() + task = grabbed.select(limitby=(0,1), orderby=ts.next_run_time).first() + if task: + task.update_record(status=RUNNING,last_run_time=now) + #noone will touch my task! + db.commit() + logging.debug(' work to do %s' % task.id) else: + logging.debug('nothing to do') return None next_run_time = task.last_run_time + datetime.timedelta(seconds=task.period) times_run = task.times_run + 1 @@ -469,11 +468,13 @@ class Scheduler(MetaScheduler): if task_report.status == COMPLETED: d = dict(status = task.run_again and QUEUED or COMPLETED, next_run_time = task.next_run_time, - times_run = task.times_run, - assigned_worker_name = '') + times_run = task.times_run) + #I'd like to know who worked my task, reviewing some logs... + #,assigned_worker_name = '') else: d = dict( - assigned_worker_name = '', + #same as before... + #assigned_worker_name = '', status = {'FAILED':'FAILED', 'TIMEOUT':'TIMEOUT', 'STOPPED':'QUEUED'}[task_report.status]) @@ -498,20 +499,82 @@ class Scheduler(MetaScheduler): .update(last_heartbeat = now, status = ACTIVE): sw.insert(status = ACTIVE,worker_name = self.worker_name, first_heartbeat = now,last_heartbeat = now) - if counter % 10 == 0: - # deallocate jobs assigned to inactive workers and requeue them - logging.debug(' freeing workers that have not sent heartbeat') - inactive_workers = db(sw.last_heartbeat self.worker_name) & (sw.is_ticker == True)).select().first() + if not ticker: + db(sw.worker_name == self.worker_name).update(is_ticker = True) + logging.info("TICKER: I'm a ticker (%s)" % self.worker_name) + return True + else: + logging.info("%s is a ticker, I'm a poor worker" % ticker.worker_name) + return False + + def assign_tasks(self): + db = self.db + sw, ts = db.scheduler_worker, db.scheduler_task + now = datetime.datetime.now() + all_workers = db(sw.id>0).select() + workers = [row.worker_name for row in all_workers] + all_available = db(ts.status.belongs((QUEUED,ASSIGNED)))\ + ((ts.times_runnow)\ + (ts.next_run_time<=now)\ + (ts.enabled==True)\ + (ts.group_name.belongs(self.group_names)) #\ + #(ts.assigned_worker_name <> self.worker_name) + limit = len(workers) * 50 + #if there are a moltitude of tasks, let's assign a maximum of 50 tasks per worker. + #this can be adjusted with some added intelligence (like esteeming how many tasks will + #a worker complete before the ticker reassign them around, but the gain is quite small + #50 is quite a sweet spot also for fast tasks, with sane heartbeat values + #NB: ticker reassign tasks every 5 cycles, so if a worker completes his 50 tasks in less + #than heartbeat*5 seconds, it won't pick new tasks until heartbeat*5 seconds pass. + tasks = all_available.select(limitby=(0,limit), orderby=ts.next_run_time) + #everything until now is going fine. If a worker is currently elaborating a long task, + #all other tasks assigned to him needs to be reassigned "freely" to other workers, that may be free. + #this shuffles up things a bit, in order to maintain the idea of a semi-linear scalability + #let's freeze it up + db.commit() + #it's useful to reduce computation times of reassigning tasks if there is only one worker around + if len(workers) == 1: + all_available.update(status=ASSIGNED, assigned_worker_name=workers[0]) + #let's break up the queue evenly among workers + else: + for i, task in enumerate(tasks): + worker = workers[i % len(workers)] + task.update_record(status=ASSIGNED, assigned_worker_name=workers[i % len(workers)]) + db.commit() + #I didn't report tasks but I'm working nonetheless!!!! + if len(tasks) > 0: + self.empty_runs = 0 + logging.info('TICKER: workers are %s' % len(workers)) + logging.info('TICKER: tasks are %s' % len(tasks)) + def sleep(self): time.sleep(self.heartbeat) # should only sleep until next available task @@ -586,5 +649,3 @@ def main(): if __name__=='__main__': main() - - diff --git a/gluon/serializers.py b/gluon/serializers.py index ee8501b4..5e44cc51 100644 --- a/gluon/serializers.py +++ b/gluon/serializers.py @@ -64,11 +64,11 @@ def json(value,default=custom_json): def csv(value): return '' -def ics(events, title=None, link=None, timeshift=0): +def ics(events, title=None, link=None, timeshift=0, **ignored): import datetime title = title or '(unkown)' if link and not callable(link): - link = lambda item: link +'/%s' % link['id'] + link = lambda item,prefix=link: prefix.replace('[id]',str(item['id'])) s = 'BEGIN:VCALENDAR' s += '\nVERSION:2.0' s += '\nX-WR-CALNAME:%s' % title @@ -95,14 +95,14 @@ def rss(feed): if not 'entries' in feed and 'items' in feed: feed['entries'] = feed['items'] now=datetime.datetime.now() - rss = rss2.RSS2(title = feed.get('title','(notitle)'), - link = feed.get('link',None), - description = feed.get('description',''), + rss = rss2.RSS2(title = str(feed.get('title','(notitle)')), + link = str(feed.get('link',None)), + description = str(feed.get('description','')), lastBuildDate = feed.get('created_on', now), items = [rss2.RSSItem( - title=entry.get('title','(notitle)'), - link=entry('link',None), - description=entry.get('description',''), + title=str(entry.get('title','(notitle)')), + link=str(entry.get('link',None)), + description=str(entry.get('description','')), pubDate=entry.get('created_on', now) ) for entry in feed.get('entries',[])]) return rss2.dumps(rss) diff --git a/gluon/shell.py b/gluon/shell.py index 8d534f9f..cb74da36 100644 --- a/gluon/shell.py +++ b/gluon/shell.py @@ -140,10 +140,14 @@ def env( def exec_pythonrc(): pythonrc = os.environ.get('PYTHONSTARTUP') if pythonrc and os.path.isfile(pythonrc): + def execfile_getlocals(file): + execfile(file) + return locals() try: - execfile(pythonrc) + return execfile_getlocals(pythonrc) except NameError: pass + return dict() def run( @@ -200,8 +204,10 @@ def run( if f: exec ('print %s()' % f, _env) - elif startfile: - exec_pythonrc() + return + + _env.update(exec_pythonrc()) + if startfile: try: execfile(startfile, _env) if import_models: BaseAdapter.close_all_instances('commit') @@ -209,7 +215,6 @@ def run( print traceback.format_exc() if import_models: BaseAdapter.close_all_instances('rollback') elif python_code: - exec_pythonrc() try: exec(python_code, _env) if import_models: BaseAdapter.close_all_instances('commit') @@ -253,7 +258,6 @@ def run( else: readline.set_completer(rlcompleter.Completer(_env).complete) readline.parse_and_bind('tab:complete') - exec_pythonrc() code.interact(local=_env) diff --git a/gluon/sqlhtml.py b/gluon/sqlhtml.py index 78942d11..47cfd9f0 100644 --- a/gluon/sqlhtml.py +++ b/gluon/sqlhtml.py @@ -1130,6 +1130,23 @@ class SQLFORM(FORM): hideerror=hideerror, ) + if not ret and self.record and self.errors: + ### if there are errors in update mode + # and some errors refers to an already uploaded file + # delete error if + # - user not trying to upload a new file + # - there is existing file and user is not trying to delete it + # this is because removing the file may not pass validation + for key in self.errors.keys(): + if key in self.table \ + and self.table[key].type == 'upload' \ + and request_vars.get(key, None) in (None, '') \ + and self.record[key] \ + and not key + UploadWidget.ID_DELETE_SUFFIX in request_vars: + del self.errors[key] + if not self.errors: + ret = True + self.deleted = \ request_vars.get(self.FIELDNAME_REQUEST_DELETE, False) @@ -1598,7 +1615,7 @@ class SQLFORM(FORM): def buttons(edit=False,view=False,record=None): buttons = DIV(gridbutton('buttonback', 'Back', referrer), _class='form_header row_buttons %(header)s %(cornertop)s' % ui) - if edit: + if edit and (not callable(edit) or edit(record)): args = ['edit',table._tablename,request.args[-1]] buttons.append(gridbutton('buttonedit', 'Edit', url(args=args))) @@ -1949,6 +1966,7 @@ class SQLFORM(FORM): def smartgrid(table, constraints=None, linked_tables=None, links=None, links_in_grid=True, args=None, user_signature=True, + divider='>', breadcrumbs_class='', **kwargs): """ @auth.requires_login() @@ -1979,7 +1997,7 @@ class SQLFORM(FORM): linked_tables is a optional list of tablenames of tables to be linked """ - from gluon import current, A, URL, DIV, H3, redirect + from gluon import current, A, URL, DIV, H3, UL, LI, SPAN, redirect request, T = current.request, current.T if args is None: args = [] db = table._db @@ -2020,14 +2038,14 @@ class SQLFORM(FORM): else: name = format % record except TypeError: name = id - breadcrumbs += [A(T(db[referee]._plural), + breadcrumbs += [LI(A(T(db[referee]._plural), _class=trap_class(), _href=URL(args=request.args[:nargs])), - ' > ', - A(name,_class=trap_class(), + SPAN(divider,_class='divider')), + LI(A(name,_class=trap_class(), _href=URL(args=request.args[:nargs]+[ 'view',referee,id],user_signature=True)), - ' > '] + SPAN(divider,_class='divider'))] nargs+=2 else: break @@ -2074,9 +2092,10 @@ class SQLFORM(FORM): user_signature=user_signature,**kwargs) if isinstance(grid,DIV): header = table._plural + (field and ' for '+field.name or '') - breadcrumbs.append(A(T(header),_class=trap_class(), - _href=URL(args=request.args[:nargs]))) - grid.insert(0,DIV(H3(*breadcrumbs),_class='web2py_breadcrumbs')) + breadcrumbs.append(LI(A(T(header),_class=trap_class(), + _href=URL(args=request.args[:nargs])), _class='active')) + grid.insert(0,DIV(UL(*breadcrumbs, **{'_class':breadcrumbs_class}), + _class='web2py_breadcrumbs')) return grid diff --git a/gluon/tests/test_router.py b/gluon/tests/test_router.py index e258e88f..c8097298 100644 --- a/gluon/tests/test_router.py +++ b/gluon/tests/test_router.py @@ -611,6 +611,42 @@ class TestRouter(unittest.TestCase): self.assertEqual(filter_url('http://d.com/app2/ctr/index/arg'), "/app2/ctr/index ['arg']") self.assertEqual(filter_url('http://d.com/app2/ctr/arg'), "/app2/ctr/arg") + def test_router_functions2(self): + ''' + Test more functions=[something] + ''' + router_functions = dict( + BASE = dict( + default_application = 'init', + applications = 'INIT', + default_controller = 'default', + controllers = ['default', 'ctr'], + default_function = 'index', + functions = ['index','user','register','basicRegister', + 'download','call','data','error'] + ), + ) + + load(rdict=router_functions) + + # outbound + self.assertEqual(str(URL(a='init', c='default', f='index', args=['arg1'])), "/arg1") + self.assertEqual(str(URL(a='init', c='default', f='user', args=['arg1'])), "/user/arg1") + self.assertEqual(str(URL(a='init', c='default', f='user', args=['index'])), "/user/index") + self.assertEqual(str(URL(a='init', c='default', f='index', args=['index'])), "/index/index") + self.assertEqual(str(URL(a='init', c='default', f='index', args=['init'])), "/init") + self.assertEqual(str(URL(a='init', c='default', f='index', args=['ctr'])), "/index/ctr") + self.assertEqual(str(URL(a='init', c='ctr', f='index', args=['arg'])), "/ctr/index/arg") + self.assertEqual(str(URL(a='init', c='ctr', f='ctrf1', args=['arg'])), "/ctr/ctrf1/arg") + self.assertEqual(str(URL(a='init', c='ctr', f='ctrf1', args=['ctrf2'])), "/ctr/ctrf1/ctrf2") + + # inbound + self.assertEqual(filter_url('http://d.com/arg'), "/init/default/index ['arg']") + self.assertEqual(filter_url('http://d.com/user'), "/init/default/user") + self.assertEqual(filter_url('http://d.com/user/arg'), "/init/default/user ['arg']") + self.assertEqual(filter_url('http://d.com/ctr'), "/init/ctr/index") + self.assertEqual(filter_url('http://d.com/ctr/ctrf1/arg'), "/init/ctr/ctrf1 ['arg']") + def test_router_hyphen(self): ''' Test hyphen conversion