diff --git a/.gitignore b/.gitignore index aabd7486658..de95095bf11 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ www/build .sass-cache/ www/lib e2e/build +/desktop diff --git a/AppXManifest.xml b/AppXManifest.xml new file mode 100644 index 00000000000..d31855a1b76 --- /dev/null +++ b/AppXManifest.xml @@ -0,0 +1,44 @@ + + + + + Moodle Desktop + Moodle Pty Ltd. + The official app for Moodle. + assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + Moodle Mobile URI Scheme + + + + + + diff --git a/config.xml b/config.xml index 762cadb9a29..b25195875f3 100644 --- a/config.xml +++ b/config.xml @@ -1,77 +1,89 @@ - - Moodle Mobile - Official Moodle Mobile app - Juan Leyva - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Moodle Mobile + + Moodle Mobile official app + + + Moodle Mobile team + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/package.json b/package.json index 553a2c9c0d5..d8d37a8dabb 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,11 @@ { - "name": "mm2", - "version": "1.0.0", - "description": "Moodle Mobile 2: The official mobile app for Moodle.", + "name": "com.moodle.moodlemobile", + "version": "3.3.0", + "description": "The official app for Moodle.", + "author": { + "name": "Moodle Pty Ltd.", + "email": "mobile@moodle.com" + }, "repository": { "type": "git", "url": "https://github.com/moodlehq/moodlemobile2.git" @@ -14,22 +18,25 @@ } ], "dependencies": { + "electron-windows-notifications": "^1.1.13", + "electron-builder-squirrel-windows": "^19.3.0" }, "devDependencies": { "appium": "^1.6.0", "bower": "^1.3.3", + "electron-rebuild": "^1.5.11", "gulp": "^3.9.1", - "gulp-clean-css": "^3.0.3", - "gulp-concat": "^2.6.0", - "gulp-rename": "^1.2.0", - "gulp-sass": "^2.3.2", "gulp-clean": "^0.3.2", + "gulp-clean-css": "^3.0.3", "gulp-clip-empty-files": "^0.1.1", + "gulp-concat": "^2.6.0", "gulp-concat-util": "^0.5.2", "gulp-file": "^0.3.0", "gulp-insert": "^0.5.0", "gulp-ng-annotate": "^2.0.0", "gulp-remove-empty-lines": "0.0.8", + "gulp-rename": "^1.2.0", + "gulp-sass": "^2.3.2", "gulp-slash": "^1.1.3", "gulp-strip-comments": "^2.4.3", "gulp-tap": "^0.1.3", @@ -121,6 +128,45 @@ "android": "ionic run android", "serve.e2e": "ionic serve -b -a", "serve.dev": "ionic serve", - "e2e": "protractor e2e/build/protractor.conf.js" + "e2e": "protractor e2e/build/protractor.conf.js", + "desktop.pack": "build --dir", + "desktop.dist": "build", + "windows.store": "electron-windows-store --input-directory .\\desktop\\dist\\win-unpacked --output-directory .\\desktop\\store --flatten true -a .\\resources\\desktop -m .\\AppXManifest.xml --package-version 0.0.0.0 --package-name MoodleDesktop" + }, + "main": "www/electron.js", + "build": { + "appId": "com.moodle.moodlemobile", + "productName": "MoodleDesktop", + "files": [ + "!desktop", + "!**/e2e", + "!hooks", + "!platforms", + "!plugins", + "!resources", + "!**/*.scss" + ], + "directories": { + "output": "desktop/dist" + }, + "protocols": [ + { + "name": "Moodle Mobile URL", + "schemes": [ + "moodlemobile" + ], + "role": "Viewer" + } + ], + "compression": "maximum", + "electronVersion": "1.6.11", + "mac": { + "category": "public.app-category.education", + "icon": "resources/desktop/icon.icns" + }, + "win": { + "target": "appx", + "icon": "resources/desktop/icon.ico" + } } } diff --git a/resources/android/icon.png b/resources/android/icon.png old mode 100644 new mode 100755 index b98d8a19f2a..23e01833453 Binary files a/resources/android/icon.png and b/resources/android/icon.png differ diff --git a/resources/android/icon/drawable-hdpi-icon.png b/resources/android/icon/drawable-hdpi-icon.png index 7cf11c2ab6f..d20db6c0a09 100644 Binary files a/resources/android/icon/drawable-hdpi-icon.png and b/resources/android/icon/drawable-hdpi-icon.png differ diff --git a/resources/android/icon/drawable-ldpi-icon.png b/resources/android/icon/drawable-ldpi-icon.png index 18cbb4dbd57..f96ff0b7157 100644 Binary files a/resources/android/icon/drawable-ldpi-icon.png and b/resources/android/icon/drawable-ldpi-icon.png differ diff --git a/resources/android/icon/drawable-mdpi-icon.png b/resources/android/icon/drawable-mdpi-icon.png index 85492e12e16..1911c9d650d 100644 Binary files a/resources/android/icon/drawable-mdpi-icon.png and b/resources/android/icon/drawable-mdpi-icon.png differ diff --git a/resources/android/icon/drawable-xhdpi-icon.png b/resources/android/icon/drawable-xhdpi-icon.png index 408ce3ab19c..b87391cffce 100644 Binary files a/resources/android/icon/drawable-xhdpi-icon.png and b/resources/android/icon/drawable-xhdpi-icon.png differ diff --git a/resources/android/icon/drawable-xxhdpi-icon.png b/resources/android/icon/drawable-xxhdpi-icon.png index 68d01f62dc1..3bc10a5e21c 100644 Binary files a/resources/android/icon/drawable-xxhdpi-icon.png and b/resources/android/icon/drawable-xxhdpi-icon.png differ diff --git a/resources/android/icon/drawable-xxxhdpi-icon.png b/resources/android/icon/drawable-xxxhdpi-icon.png index 5a73b291c35..91640a3cde5 100644 Binary files a/resources/android/icon/drawable-xxxhdpi-icon.png and b/resources/android/icon/drawable-xxxhdpi-icon.png differ diff --git a/resources/desktop/Square150x150Logo.png b/resources/desktop/Square150x150Logo.png new file mode 100644 index 00000000000..dd059984b4a Binary files /dev/null and b/resources/desktop/Square150x150Logo.png differ diff --git a/resources/desktop/Square44x44Logo.png b/resources/desktop/Square44x44Logo.png new file mode 100644 index 00000000000..b1ad9e9bdc2 Binary files /dev/null and b/resources/desktop/Square44x44Logo.png differ diff --git a/resources/desktop/StoreLogo.png b/resources/desktop/StoreLogo.png new file mode 100644 index 00000000000..fa5cebb178b Binary files /dev/null and b/resources/desktop/StoreLogo.png differ diff --git a/resources/desktop/Wide310x150Logo.png b/resources/desktop/Wide310x150Logo.png new file mode 100644 index 00000000000..70e54eb7375 Binary files /dev/null and b/resources/desktop/Wide310x150Logo.png differ diff --git a/resources/desktop/icon.icns b/resources/desktop/icon.icns new file mode 100644 index 00000000000..4e3c10b84e4 Binary files /dev/null and b/resources/desktop/icon.icns differ diff --git a/resources/desktop/icon.ico b/resources/desktop/icon.ico new file mode 100644 index 00000000000..c65354c8136 Binary files /dev/null and b/resources/desktop/icon.ico differ diff --git a/resources/ios/icon.png b/resources/ios/icon.png index 2f5b179c7bc..ddcce9da81b 100644 Binary files a/resources/ios/icon.png and b/resources/ios/icon.png differ diff --git a/resources/ios/icon/icon-40.png b/resources/ios/icon/icon-40.png index 5f586ad9cdd..9311b8b3f69 100644 Binary files a/resources/ios/icon/icon-40.png and b/resources/ios/icon/icon-40.png differ diff --git a/resources/ios/icon/icon-40@2x.png b/resources/ios/icon/icon-40@2x.png index 7b1f2478c51..63f826ea1bd 100644 Binary files a/resources/ios/icon/icon-40@2x.png and b/resources/ios/icon/icon-40@2x.png differ diff --git a/resources/ios/icon/icon-40@3x.png b/resources/ios/icon/icon-40@3x.png index bc5c9ba0c20..8d8da619985 100644 Binary files a/resources/ios/icon/icon-40@3x.png and b/resources/ios/icon/icon-40@3x.png differ diff --git a/resources/ios/icon/icon-50.png b/resources/ios/icon/icon-50.png index 810b1fa020b..02f6868c01c 100644 Binary files a/resources/ios/icon/icon-50.png and b/resources/ios/icon/icon-50.png differ diff --git a/resources/ios/icon/icon-50@2x.png b/resources/ios/icon/icon-50@2x.png index d500206f169..f131e00094e 100644 Binary files a/resources/ios/icon/icon-50@2x.png and b/resources/ios/icon/icon-50@2x.png differ diff --git a/resources/ios/icon/icon-60.png b/resources/ios/icon/icon-60.png index 2ab0816738c..854c33f6c09 100644 Binary files a/resources/ios/icon/icon-60.png and b/resources/ios/icon/icon-60.png differ diff --git a/resources/ios/icon/icon-60@2x.png b/resources/ios/icon/icon-60@2x.png index bc5c9ba0c20..8d8da619985 100644 Binary files a/resources/ios/icon/icon-60@2x.png and b/resources/ios/icon/icon-60@2x.png differ diff --git a/resources/ios/icon/icon-60@3x.png b/resources/ios/icon/icon-60@3x.png index 4c3d9fe188c..b94721b25cd 100644 Binary files a/resources/ios/icon/icon-60@3x.png and b/resources/ios/icon/icon-60@3x.png differ diff --git a/resources/ios/icon/icon-72.png b/resources/ios/icon/icon-72.png index 93f8d10b773..9204a054b40 100644 Binary files a/resources/ios/icon/icon-72.png and b/resources/ios/icon/icon-72.png differ diff --git a/resources/ios/icon/icon-72@2x.png b/resources/ios/icon/icon-72@2x.png index e0915e1bff8..5dff7993c18 100644 Binary files a/resources/ios/icon/icon-72@2x.png and b/resources/ios/icon/icon-72@2x.png differ diff --git a/resources/ios/icon/icon-76.png b/resources/ios/icon/icon-76.png index f57b285daac..87c4cc3f2bf 100644 Binary files a/resources/ios/icon/icon-76.png and b/resources/ios/icon/icon-76.png differ diff --git a/resources/ios/icon/icon-76@2x.png b/resources/ios/icon/icon-76@2x.png index 0d753ccd2f5..3345289a548 100644 Binary files a/resources/ios/icon/icon-76@2x.png and b/resources/ios/icon/icon-76@2x.png differ diff --git a/resources/ios/icon/icon-83.5@2x.png b/resources/ios/icon/icon-83.5@2x.png index 37c031c37a9..779bb361ae9 100644 Binary files a/resources/ios/icon/icon-83.5@2x.png and b/resources/ios/icon/icon-83.5@2x.png differ diff --git a/resources/ios/icon/icon-small.png b/resources/ios/icon/icon-small.png index 0ceb97036ea..457fe4a6580 100644 Binary files a/resources/ios/icon/icon-small.png and b/resources/ios/icon/icon-small.png differ diff --git a/resources/ios/icon/icon-small@2x.png b/resources/ios/icon/icon-small@2x.png index 450216cf66c..f7e20964b63 100644 Binary files a/resources/ios/icon/icon-small@2x.png and b/resources/ios/icon/icon-small@2x.png differ diff --git a/resources/ios/icon/icon-small@3x.png b/resources/ios/icon/icon-small@3x.png index 1f75d32fa50..95b5d64681b 100644 Binary files a/resources/ios/icon/icon-small@3x.png and b/resources/ios/icon/icon-small@3x.png differ diff --git a/resources/ios/icon/icon.png b/resources/ios/icon/icon.png index 1540b259568..2414ad2b8d4 100644 Binary files a/resources/ios/icon/icon.png and b/resources/ios/icon/icon.png differ diff --git a/resources/ios/icon/icon@2x.png b/resources/ios/icon/icon@2x.png index 023384d9db2..a0bbf3d384d 100644 Binary files a/resources/ios/icon/icon@2x.png and b/resources/ios/icon/icon@2x.png differ diff --git a/scss/app.scss b/scss/app.scss index 3a670e093c7..5d1afb1a84d 100644 --- a/scss/app.scss +++ b/scss/app.scss @@ -50,6 +50,14 @@ $mm-color: $orange; $mm-color-light: lighten($mm-color, 10%); $mm-color-dark: darken($mm-color, 10%); +$mm-color-init-screen: #ff5c00; +$mm-color-init-screen-alt: #ff7600; +$mm-init-screen-spinner-color: $white; +$mm-init-screen-logo-width: 60%; +$mm-init-screen-logo-max-width: 300px; + +$mm-fixed-url: false; + $mm-buttons-color: $positive; // Change Ionic default elements colors. @@ -57,20 +65,31 @@ $base-color: $black !default; $base-background-color: $gray-light !default; $item-default-text: $black; -$sheet-options-text-color: $positive; +$sheet-options-text-color: $mm-buttons-color; + +$item-default-bg: $white; +$item-divider-bg: $gray-lighter; +$item-disabled-color: $gray-dark !default; + +$button-light-border: $gray; // Header. $bar-content-bg: $mm-color !default; $bar-content-border: transparent !default; $bar-content-text: $white !default; -$item-default-bg: $white; -$item-divider-bg: $gray-lighter; -$item-disabled-color: $gray-dark !default; +$bar-side-menu-height: 80px !default; +$bar-side-menu-color: $bar-content-bg !default; +$bar-side-menu-border-color: $bar-content-border !default; +$bar-side-menu-text-color: $bar-content-text !default; -$button-light-border: $gray; +$bar-side-menu-item-border-color: $button-light-border; +$bar-side-menu-item-divider-color: $item-divider-bg; +$bar-side-menu-item-background-color: $item-default-bg; +$bar-side-menu-item-text-color: $item-default-text; +$bar-side-menu-item-icon-color: $gray-darker; -$toggle-on-default-bg: $blue; +$toggle-on-default-bg: $mm-buttons-color; $tabs-off-opacity: 0.6; $tabs-striped-off-opacity: $tabs-off-opacity; @@ -82,6 +101,11 @@ $button-default-border: $mm-buttons-color !default; $button-default-active-bg: $mm-buttons-color !default; $button-default-active-border: $mm-buttons-color !default; +$button-positive-bg: $mm-buttons-color !default; +$button-positive-border: darken($mm-buttons-color, 10%) !default; +$button-positive-active-bg: darken($mm-buttons-color, 10%) !default; +$button-positive-active-border: darken($mm-buttons-color, 10%) !default; + // The path to the font icons. $ionicons-font-path: "../lib/ionic/release/fonts" !default; @@ -92,7 +116,7 @@ $ionicons-font-path: "../lib/ionic/release/fonts" !default; color: $gray-darker; &.positive { - color: $positive; + color: $mm-buttons-color; } &.assertive { color: $assertive; @@ -112,7 +136,7 @@ $ionicons-font-path: "../lib/ionic/release/fonts" !default; &.activated, &.active .icon, &.activated .icon { - color: $positive; + color: $mm-buttons-color; &.assertive { color: $assertive; @@ -144,7 +168,7 @@ $ionicons-font-path: "../lib/ionic/release/fonts" !default; color: $assertive; } -// Setting the default button to button-outline positive. +// Setting the default button to button-outline $mm-buttons-color. .button { &.button-light, &.button-stable, diff --git a/www/addons/badges/lang/sr-cr.json b/www/addons/badges/lang/sr-cr.json new file mode 100644 index 00000000000..dde1e852627 --- /dev/null +++ b/www/addons/badges/lang/sr-cr.json @@ -0,0 +1,12 @@ +{ + "badgedetails": "Подаци о беџу", + "badges": "Беџеви", + "contact": "Контакт", + "dateawarded": "Датум издавања", + "expirydate": "Датум истека", + "issuancedetails": "Беџ истиче", + "issuerdetails": "Подаци о издавачу", + "issuername": "Име/назив издавача беџа", + "nobadges": "Нема доступних беџева", + "recipientdetails": "Детаљи о примаоцу" +} \ No newline at end of file diff --git a/www/addons/badges/lang/sr-lt.json b/www/addons/badges/lang/sr-lt.json new file mode 100644 index 00000000000..7c2a996f0ba --- /dev/null +++ b/www/addons/badges/lang/sr-lt.json @@ -0,0 +1,12 @@ +{ + "badgedetails": "Podaci o bedžu", + "badges": "Bedževi", + "contact": "Kontakt", + "dateawarded": "Datum izdavanja", + "expirydate": "Datum isteka", + "issuancedetails": "Bedž ističe", + "issuerdetails": "Podaci o izdavaču", + "issuername": "Ime/naziv izdavača bedža", + "nobadges": "Nema dostupnih bedževa", + "recipientdetails": "Detalji o primaocu" +} \ No newline at end of file diff --git a/www/addons/badges/lang/sv.json b/www/addons/badges/lang/sv.json index 4c67f9031ef..878282c5e4f 100644 --- a/www/addons/badges/lang/sv.json +++ b/www/addons/badges/lang/sv.json @@ -1,6 +1,6 @@ { "badgedetails": "Detaljer för märke", - "badges": "Badges", + "badges": "Märken", "contact": "Kontakt", "dateawarded": "Utfärdandedatum", "expirydate": "Förfallodatum", diff --git a/www/addons/badges/lang/tr.json b/www/addons/badges/lang/tr.json index b540e7cabae..5c79f345058 100644 --- a/www/addons/badges/lang/tr.json +++ b/www/addons/badges/lang/tr.json @@ -1,6 +1,6 @@ { "badgedetails": "Nişan ayrıntıları", - "badges": "Rozetler", + "badges": "Nişanlar", "contact": "İletişim", "dateawarded": "Verilen tarih", "expirydate": "Bitiş Tarihi", diff --git a/www/addons/calendar/controllers/list.js b/www/addons/calendar/controllers/list.js index 5ef1ab47781..30f897430f1 100644 --- a/www/addons/calendar/controllers/list.js +++ b/www/addons/calendar/controllers/list.js @@ -21,9 +21,9 @@ angular.module('mm.addons.calendar') * @ngdoc controller * @name mmaCalendarListCtrl */ -.controller('mmaCalendarListCtrl', function($scope, $stateParams, $log, $state, $mmaCalendar, $mmUtil, $ionicHistory, $mmEvents, +.controller('mmaCalendarListCtrl', function($scope, $stateParams, $log, $state, $mmaCalendar, $mmUtil, $timeout, $mmEvents, mmaCalendarDaysInterval, $ionicScrollDelegate, $mmLocalNotifications, $mmCourses, mmaCalendarDefaultNotifTimeChangedEvent, - $ionicPopover, $q, $translate) { + $ionicPopover, $q, $translate, $ionicPlatform) { $log = $log.getInstance('mmaCalendarListCtrl'); @@ -38,10 +38,10 @@ angular.module('mm.addons.calendar') }; $scope.events = []; + $scope.eventToLoad = 1; - if ($stateParams.eventid) { - // We arrived here via notification click, let's clear history and redirect to event details. - $ionicHistory.clearHistory(); + if ($stateParams.eventid && !$ionicPlatform.isTablet()) { + // There is an event to load and it's a phone device, open the event in a new state. $state.go('site.calendar-event', {id: $stateParams.eventid}); } @@ -69,7 +69,6 @@ angular.module('mm.addons.calendar') emptyEventsTimes++; if (emptyEventsTimes > 5) { // Stop execution if we retrieve empty list 6 consecutive times. $scope.canLoadMore = false; - $scope.eventsLoaded = true; if (refresh) { $scope.events = []; } @@ -90,7 +89,6 @@ angular.module('mm.addons.calendar') // Filter events with same ID. Repeated events are returned once per WS call, show them only once. $scope.events = $mmUtil.mergeArraysWithoutDuplicates($scope.events, events, 'id'); } - $scope.eventsLoaded = true; $scope.canLoadMore = true; // Schedule notifications for the events retrieved (might have new events). @@ -101,7 +99,6 @@ angular.module('mm.addons.calendar') scrollView.resize(); }, function(error) { $mmUtil.showErrorModalDefault(error, 'mma.calendar.errorloadevents', true); - $scope.eventsLoaded = true; $scope.canLoadMore = false; // Set to false to prevent infinite calls with infinite-loading. }); } @@ -121,7 +118,30 @@ angular.module('mm.addons.calendar') $scope.notificationsEnabled = $mmLocalNotifications.isAvailable(); // Get first events. - fetchData(); + fetchData().then(function() { + if ($stateParams.eventid && $ionicPlatform.isTablet()) { + // There is an event to load and it's a tablet device. Search the position of the event in the list and load it. + var found = false; + + for (var i = 0; i < $scope.events.length; i++) { + if ($scope.events[i].id == $stateParams.eventid) { + $scope.eventToLoad = i + 1; + found = true; + break; + } + } + + if (!found) { + // Event not found in the list, open it in a new state. Use a $timeout to open the state after the + // split view is loaded. + $timeout(function() { + $state.go('site.calendar-event', {id: $stateParams.eventid}); + }); + } + } + }).finally(function() { + $scope.eventsLoaded = true; + }); // Init popover. $ionicPopover.fromTemplateUrl('addons/calendar/templates/course_picker.html', { diff --git a/www/addons/calendar/lang/ar.json b/www/addons/calendar/lang/ar.json index 9bece3c914d..23e2ee91b94 100644 --- a/www/addons/calendar/lang/ar.json +++ b/www/addons/calendar/lang/ar.json @@ -3,5 +3,5 @@ "errorloadevent": "خطأ في تحميل الحدث", "errorloadevents": "خطأ في تحميل الأحداث", "noevents": "لا يوجد أي أحداث", - "notifications": "إشعارات" + "notifications": "الإشعارات" } \ No newline at end of file diff --git a/www/addons/calendar/lang/da.json b/www/addons/calendar/lang/da.json index 70693816a85..6826baea7eb 100644 --- a/www/addons/calendar/lang/da.json +++ b/www/addons/calendar/lang/da.json @@ -3,5 +3,5 @@ "errorloadevent": "Fejl ved indlæsning af begivenhed.", "errorloadevents": "Fejl ved indlæsning af begivenheder.", "noevents": "Der er ingen begivenheder", - "notifications": "Beskeder" + "notifications": "Notifikationer" } \ No newline at end of file diff --git a/www/addons/calendar/lang/el.json b/www/addons/calendar/lang/el.json index 744426a674d..9a2040a3e51 100644 --- a/www/addons/calendar/lang/el.json +++ b/www/addons/calendar/lang/el.json @@ -1,5 +1,6 @@ { "calendarevents": "Ημερολόγιο συμβάντων", + "defaultnotificationtime": "Προεπιλεγμένος χρόνος ειδοποίησης", "errorloadevent": "Σφάλμα στην φόρτωση συμβάντου.", "errorloadevents": "Σφάλμα στην φόρτωση συμβάντων.", "noevents": "Δεν υπάρχουν συμβάντα", diff --git a/www/addons/calendar/lang/es.json b/www/addons/calendar/lang/es.json index 39bf009cfb6..993aec44200 100644 --- a/www/addons/calendar/lang/es.json +++ b/www/addons/calendar/lang/es.json @@ -1,5 +1,6 @@ { "calendarevents": "Eventos de calendario", + "defaultnotificationtime": "Tiempo de notificación por defecto", "errorloadevent": "Error cargando el evento.", "errorloadevents": "Error cargando los eventos.", "noevents": "No hay eventos", diff --git a/www/addons/calendar/lang/es_mx.json b/www/addons/calendar/lang/es_mx.json deleted file mode 100644 index 43fb72dee96..00000000000 --- a/www/addons/calendar/lang/es_mx.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "notifications": "Notificaciones" -} \ No newline at end of file diff --git a/www/addons/calendar/lang/fa.json b/www/addons/calendar/lang/fa.json index 109ac4e7ec6..76813733c1d 100644 --- a/www/addons/calendar/lang/fa.json +++ b/www/addons/calendar/lang/fa.json @@ -3,6 +3,6 @@ "defaultnotificationtime": "زمان پیش‌فرض اطلاع‌رسانی", "errorloadevent": "خطا در بارگیری رویداد.", "errorloadevents": "خطا در بارگیری رویدادها.", - "noevents": "هیچ رویدادی نیست", - "notifications": "هشدارها" + "noevents": "هیچ مهلتی برای فعالیت‌های آتی وجود ندارد", + "notifications": "تذکرات" } \ No newline at end of file diff --git a/www/addons/calendar/lang/he.json b/www/addons/calendar/lang/he.json index 3702664d6e1..368fb1895c4 100644 --- a/www/addons/calendar/lang/he.json +++ b/www/addons/calendar/lang/he.json @@ -2,6 +2,6 @@ "calendarevents": "אירועי לוח שנה", "errorloadevent": "שגיאה בטעינת האירוע.", "errorloadevents": "שגיאה בטעינת האירועים.", - "noevents": "לא קיימות פעילויות עתידיות להן מועד הגשה", - "notifications": "עדכונים והודעות" + "noevents": "אין אירועים", + "notifications": "התראות" } \ No newline at end of file diff --git a/www/addons/calendar/lang/ja.json b/www/addons/calendar/lang/ja.json index 5064bdee92f..b6e5457e412 100644 --- a/www/addons/calendar/lang/ja.json +++ b/www/addons/calendar/lang/ja.json @@ -1,4 +1,8 @@ { - "noevents": "到来する活動期限はありません。", + "calendarevents": "カレンダーイベント", + "defaultnotificationtime": "デフォルト通知時間", + "errorloadevent": "イベントの読み込み時にエラーがありました。", + "errorloadevents": "イベントの読み込み時にエラーがありました。", + "noevents": "イベントはありません", "notifications": "通知" } \ No newline at end of file diff --git a/www/addons/calendar/lang/pl.json b/www/addons/calendar/lang/pl.json index 4116997d19c..4f391781a66 100644 --- a/www/addons/calendar/lang/pl.json +++ b/www/addons/calendar/lang/pl.json @@ -1,4 +1,4 @@ { - "noevents": "Brak zdarzeń", + "noevents": "Brak nadchodzących terminów zadań", "notifications": "Powiadomienia" } \ No newline at end of file diff --git a/www/addons/calendar/lang/pt_br.json b/www/addons/calendar/lang/pt_br.json deleted file mode 100644 index 3037d7d8cf5..00000000000 --- a/www/addons/calendar/lang/pt_br.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "noevents": "Sem eventos", - "notifications": "Notificação" -} \ No newline at end of file diff --git a/www/addons/calendar/lang/sr-cr.json b/www/addons/calendar/lang/sr-cr.json new file mode 100644 index 00000000000..dba4ebcd807 --- /dev/null +++ b/www/addons/calendar/lang/sr-cr.json @@ -0,0 +1,8 @@ +{ + "calendarevents": "Догађаји у календару", + "defaultnotificationtime": "Подразумевано време за слање обавештења", + "errorloadevent": "Грешка приликом учитавања догађаја.", + "errorloadevents": "Грешка приликом учитавања догађаја.", + "noevents": "Нема догађаја", + "notifications": "Обавештења" +} \ No newline at end of file diff --git a/www/addons/calendar/lang/sr-lt.json b/www/addons/calendar/lang/sr-lt.json new file mode 100644 index 00000000000..7db382ef521 --- /dev/null +++ b/www/addons/calendar/lang/sr-lt.json @@ -0,0 +1,8 @@ +{ + "calendarevents": "Događaji u kalendaru", + "defaultnotificationtime": "Podrazumevano vreme za slanje obaveštenja", + "errorloadevent": "Greška prilikom učitavanja događaja.", + "errorloadevents": "Greška prilikom učitavanja događaja.", + "noevents": "Nema događaja", + "notifications": "Nema događaja" +} \ No newline at end of file diff --git a/www/addons/calendar/lang/zh_cn.json b/www/addons/calendar/lang/zh_cn.json deleted file mode 100644 index 5fc1088f46f..00000000000 --- a/www/addons/calendar/lang/zh_cn.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "noevents": "没有事件", - "notifications": "通知" -} \ No newline at end of file diff --git a/www/addons/calendar/lang/zh_tw.json b/www/addons/calendar/lang/zh_tw.json deleted file mode 100644 index 24e3b1a572b..00000000000 --- a/www/addons/calendar/lang/zh_tw.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "notifications": "通知" -} \ No newline at end of file diff --git a/www/addons/calendar/templates/list.html b/www/addons/calendar/templates/list.html index 7ec4466f335..23f07180988 100644 --- a/www/addons/calendar/templates/list.html +++ b/www/addons/calendar/templates/list.html @@ -5,7 +5,7 @@ - + diff --git a/www/addons/competency/lang/ar.json b/www/addons/competency/lang/ar.json index 5952485e905..79ce4fda7f6 100644 --- a/www/addons/competency/lang/ar.json +++ b/www/addons/competency/lang/ar.json @@ -1,11 +1,11 @@ { - "activities": "الأنشطة", - "duedate": "تاريخ تقديم مهمة", + "activities": "أنشطة", + "duedate": "موعد التسليم", "errornocompetenciesfound": "لا يوجد أي قدرات موجودة", "myplans": "خططي للتعلم", "nocompetencies": "لا يوجد أي قدرات", "path": "مسار", "progress": "تقدّم الطالب", - "status": "الحالة", + "status": "الوضع", "template": "قالب" } \ No newline at end of file diff --git a/www/addons/competency/lang/bg.json b/www/addons/competency/lang/bg.json index 3b3a332e5fb..37d407ff786 100644 --- a/www/addons/competency/lang/bg.json +++ b/www/addons/competency/lang/bg.json @@ -6,6 +6,6 @@ "myplans": "Моите учебни планове", "noplanswerecreated": "Не бяха създадени учебни планове.", "path": "Път", - "status": "Състояние", + "status": "Състояние на значка", "template": "Шаблон" } \ No newline at end of file diff --git a/www/addons/competency/lang/ca.json b/www/addons/competency/lang/ca.json index 70962efd930..60ba1a02774 100644 --- a/www/addons/competency/lang/ca.json +++ b/www/addons/competency/lang/ca.json @@ -3,7 +3,7 @@ "competenciesmostoftennotproficientincourse": "Competències que més sovint no s'assoleixen en aquest curs", "coursecompetencies": "Competències del curs", "crossreferencedcompetencies": "Competències referenciades", - "duedate": "Data de venciment", + "duedate": "Venciment", "errornocompetenciesfound": "No s'han trobat competències", "evidence": "Evidència", "learningplancompetencies": "Competències del pla d'aprenentatge", @@ -14,13 +14,13 @@ "nocrossreferencedcompetencies": "No hi ha competències amb referències a aquesta.", "noevidence": "Cap evidència", "noplanswerecreated": "No s'ha creat cap pla d'aprenentatge.", - "path": "Camí", + "path": "Ruta:", "proficient": "Superada", - "progress": "Progrés de l'estudiant", - "rating": "Valoració", + "progress": "Progrés", + "rating": "Qualificació", "reviewstatus": "Estat de la revisió", - "status": "Estat", - "template": "Plantilla", + "status": "Estat de la insígnia", + "template": "Plantilla de pla d'aprenentatge", "xcompetenciesproficientoutofy": "{{$a.x}} de {{$a.y}} competències superades", "xcompetenciesproficientoutofyincourse": "Heu superat {{$a.x}} de {{$a.y}} competències en aquest curs." } \ No newline at end of file diff --git a/www/addons/competency/lang/cs.json b/www/addons/competency/lang/cs.json index 95324b05ccc..c935260c6c1 100644 --- a/www/addons/competency/lang/cs.json +++ b/www/addons/competency/lang/cs.json @@ -5,7 +5,7 @@ "coursecompetencyratingsarenotpushedtouserplans": "Hodnocení kompetencí v tomto kurzu nemají vliv na studijní plány.", "coursecompetencyratingsarepushedtouserplans": "Hodnocení kompetencí v tomto kurzu jsou okamžitě aktualizovány v studijních plánech.", "crossreferencedcompetencies": "Průřezové kompetence", - "duedate": "Termín odevzdání", + "duedate": "Datum platnosti", "errornocompetenciesfound": "Nebyly nalezeny žádné kompetence", "evidence": "Evidence", "learningplancompetencies": "Kompetence studijního plánu", @@ -16,13 +16,13 @@ "nocrossreferencedcompetencies": "K této kompetenci nebyly spojeny další průřezové kompetence.", "noevidence": "Bez záznamu", "noplanswerecreated": "Nebyly vytvořeny žádné studijní plány.", - "path": "Cesta", + "path": "Cesta:", "proficient": "Splněno", - "progress": "Pokrok studenta", + "progress": "Pokrok", "rating": "Hodnocení", "reviewstatus": "Stav revize", - "status": "Stav", - "template": "Šablona", + "status": "Stav odznaku", + "template": "Šablona studijního plánu", "xcompetenciesproficientoutofy": "máte splněno {{$a.x}} z {{$a.y}} kompetencí", "xcompetenciesproficientoutofyincourse": "V tomto kurzu máte splněno {{$a.x}} z {{$a.y}} kompetencí." } \ No newline at end of file diff --git a/www/addons/competency/lang/da.json b/www/addons/competency/lang/da.json index 57b4efe1f8c..454bb170072 100644 --- a/www/addons/competency/lang/da.json +++ b/www/addons/competency/lang/da.json @@ -4,20 +4,20 @@ "coursecompetencyratingsarenotpushedtouserplans": "Kompetencebedømmelser på dette kursus påvirker ikke læringsplaner.", "coursecompetencyratingsarepushedtouserplans": "Kompetencebedømmelser på dette kursus opdateres straks i læringsplaner.", "crossreferencedcompetencies": "Kryds-refererede kompetencer", - "duedate": "Afleveringsdato", + "duedate": "Forfaldsdato", "errornocompetenciesfound": "Ingen kompetencer fundet", "evidence": "Vidnesbyrd", "learningplancompetencies": "Læringsplankompetencer", "learningplans": "Læringsplaner", "myplans": "Mine læringsplaner", "noactivities": "Ingen aktiviteter", - "nocompetencies": "Ingen kompetencer er oprettet i denne ramme.", + "nocompetencies": "Ingen kompetencer", "nocrossreferencedcompetencies": "Ingen andre kompetencer er krydsrefereret til denne kompetence.", "noevidence": "Ingen vidnesbyrd", "noplanswerecreated": "Der blev ikke oprettet nogen læringsplaner.", - "path": "Sti", - "progress": "Studerendes fremskridt", + "path": "Sti:", + "progress": "Progression", "rating": "Bedømmelse", - "status": "Status", - "template": "Skabelon" + "status": "Badgestatus", + "template": "Læringsplanskabelon" } \ No newline at end of file diff --git a/www/addons/competency/lang/de.json b/www/addons/competency/lang/de.json index 2c43a7fb415..30b34122700 100644 --- a/www/addons/competency/lang/de.json +++ b/www/addons/competency/lang/de.json @@ -5,9 +5,9 @@ "coursecompetencyratingsarenotpushedtouserplans": "Kompetenzbewertungen in diesem Kurs beeinflussen keine Lernpläne.", "coursecompetencyratingsarepushedtouserplans": "Kompetenzbewertungen in diesem Kurs werden sofort in den Lernplänen aktualisiert.", "crossreferencedcompetencies": "Querverwiesene Kompetenzen", - "duedate": "Fälligkeitsdatum", + "duedate": "Termin", "errornocompetenciesfound": "Keine Kompetenzen gefunden", - "evidence": "Evidenz", + "evidence": "Beleg", "learningplancompetencies": "Kompetenzen des Lernplans", "learningplans": "Lernpläne", "myplans": "Meine Lernpläne", @@ -16,13 +16,13 @@ "nocrossreferencedcompetencies": "Keine anderen Kompetenzen wurden zu dieser Kompetenz referiert.", "noevidence": "Keine Belege", "noplanswerecreated": "Bisher sind keine Lernpläne angelegt.", - "path": "Pfad", + "path": "Pfad:", "proficient": "Erfahren", - "progress": "Bearbeitungsstand", - "rating": "Bewertung", + "progress": "Fortschritt", + "rating": "Wertung", "reviewstatus": "Überprüfungsstatus", - "status": "Status", - "template": "Vorlage", + "status": "Existierende Einschreibungen erlauben", + "template": "Lernplanvorlage", "xcompetenciesproficientoutofy": "{{$a.x}} von {{$a.y}} Kompetenzen sind eingeübt", "xcompetenciesproficientoutofyincourse": "Du bist in {{$a.x}} von {{$a.y}} Kompetenzen geübt" } \ No newline at end of file diff --git a/www/addons/competency/lang/el.json b/www/addons/competency/lang/el.json index 3a61231a7af..940c9116122 100644 --- a/www/addons/competency/lang/el.json +++ b/www/addons/competency/lang/el.json @@ -1,10 +1,10 @@ { "activities": "Δραστηριότητες", - "duedate": "Καταληκτική ημερομηνία", + "duedate": "Ημερομηνία εκπνοής", "errornocompetenciesfound": "Δεν βρέθηκαν ικανότητες", "nocompetencies": "Δεν βρέθηκαν ικανότητες", "path": "Διαδρομή", "progress": "Πρόοδος μαθητών", - "status": "Κατάσταση", + "status": "Επιτρέπεται η πρόσβαση στους επισκέπτες", "template": "Πρότυπο" } \ No newline at end of file diff --git a/www/addons/competency/lang/es-mx.json b/www/addons/competency/lang/es-mx.json index 276f784e4f3..89fed0897ca 100644 --- a/www/addons/competency/lang/es-mx.json +++ b/www/addons/competency/lang/es-mx.json @@ -5,7 +5,7 @@ "coursecompetencyratingsarenotpushedtouserplans": "Las valoraciones de competencia en este curso no afectan a los planes de aprendizaje.", "coursecompetencyratingsarepushedtouserplans": "Las valoraciones de competencia en este curso son actualizadas inmediatamente dentro de planes de aprendizaje.", "crossreferencedcompetencies": "Competencias con referencias-cruzadas", - "duedate": "Fecha de entrega", + "duedate": "Vencimiento", "errornocompetenciesfound": "No se encontraron competencias", "evidence": "Evidencia", "learningplancompetencies": "Competencias del plan de aprendizaje", @@ -16,13 +16,13 @@ "nocrossreferencedcompetencies": "No se han referenciado cruzadamente otras competencias con esta competencia.", "noevidence": "Sin evidencia", "noplanswerecreated": "No se crearon planes de aprendizaje.", - "path": "Ruta", + "path": "Ruta:", "proficient": "Dominio/pericia", - "progress": "Progreso del estudiante", - "rating": "Valuación (rating)", + "progress": "Progreso", + "rating": "Valoración", "reviewstatus": "Revisar estatus", - "status": "Estatus", - "template": "Plantilla", + "status": "Estatus de insignias", + "template": "Plantilla de plan de aprendizaje", "xcompetenciesproficientoutofy": "{{$a.x}} de un total de {{$a.y}} competencias se tienen dominadas", "xcompetenciesproficientoutofyincourse": "Usted es capaz/perito/experto en {{$a.x}} de un total de {{$a.y}} competencias en este curso." } \ No newline at end of file diff --git a/www/addons/competency/lang/es.json b/www/addons/competency/lang/es.json index b87c3dda451..e6a18fa8d33 100644 --- a/www/addons/competency/lang/es.json +++ b/www/addons/competency/lang/es.json @@ -5,7 +5,7 @@ "coursecompetencyratingsarenotpushedtouserplans": "Las calificaciones de competencias de este curso no afectan los planes de aprendizaje.", "coursecompetencyratingsarepushedtouserplans": "Las calificaciones de competencias en este curso actualizan de inmediato los planes de aprendizaje.", "crossreferencedcompetencies": "Competencias referenciadas", - "duedate": "Fecha de entrega", + "duedate": "Vencimiento", "errornocompetenciesfound": "No se encontraron competencias", "evidence": "Evidencia", "learningplancompetencies": "Competencias del plan de aprendizaje", @@ -17,10 +17,10 @@ "noevidence": "Sin evidencias", "path": "Ruta", "proficient": "Superada", - "progress": "Progreso del estudiante", - "rating": "Clasificación", + "progress": "Avance", + "rating": "Calificación", "reviewstatus": "Estado de la revisión", - "status": "Estado", + "status": "Estado de la insignia", "template": "Plantilla", "xcompetenciesproficientoutofy": "{{$a.x}} de {{$a.y}} competencias superadas", "xcompetenciesproficientoutofyincourse": "Has superado {{$a.x}} de las {{$a.y}} competencias del curso." diff --git a/www/addons/competency/lang/eu.json b/www/addons/competency/lang/eu.json index 3b4e8511411..b039b18b496 100644 --- a/www/addons/competency/lang/eu.json +++ b/www/addons/competency/lang/eu.json @@ -12,11 +12,11 @@ "nocompetencies": "Gaitasunik ez", "noevidence": "Ez dago ebidentziarik", "noplanswerecreated": "Ez da ikasketa-planik sortu.", - "path": "Bidea", + "path": "Bidea:", "proficient": "Gai", - "progress": "Ikaslearen aurrerapena", + "progress": "Aurrerapena", "rating": "Puntuazioa", "reviewstatus": "Berrikusi egora", - "status": "Egoera", - "template": "Txantiloia" + "status": "Dominen egoera", + "template": "Ikasketa-planerako txantiloia" } \ No newline at end of file diff --git a/www/addons/competency/lang/fa.json b/www/addons/competency/lang/fa.json index 7bec744c8a6..768c777500c 100644 --- a/www/addons/competency/lang/fa.json +++ b/www/addons/competency/lang/fa.json @@ -4,7 +4,7 @@ "coursecompetencyratingsarenotpushedtouserplans": "امتیازهای شایستگی‌ها در این درس تاثیری در برنامه‌های یادگیری ندارند.", "coursecompetencyratingsarepushedtouserplans": "امتیازهای شایستگی‌ها در این درس بلافاصله در برنامه‌های یادگیری به‌روز می‌شوند.", "crossreferencedcompetencies": "شایستگی‌های دارای ارجاع متقابل", - "duedate": "مهلت تحویل", + "duedate": "مهلت", "errornocompetenciesfound": "هیچ شایستگی‌ای پیدا نشد", "evidence": "مدرک", "learningplancompetencies": "شایستگی‌های برنامه یادگیری", @@ -13,13 +13,13 @@ "nocrossreferencedcompetencies": "هیچ شایستگی دیگری به این شایستگی به‌طور متقابل ارجاع داده نشده است.", "noevidence": "بدون مدرک", "noplanswerecreated": "هیچ برنامهٔ یادگیری‌ای ساخته نشده است.", - "path": "مسیر", + "path": "مسیر:", "proficient": "کسب مهارت", - "progress": "پیشروی شاگردان", + "progress": "پیشروی", "rating": "امتیاز", "reviewstatus": "بازبینی وضعیت", - "status": "وضعیت", - "template": "الگو", + "status": "وضعیت مدال", + "template": "الگوی برنامه یادگیری", "xcompetenciesproficientoutofy": "در {{$a.x}} شایستگی از مجموع {{$a.y}} شایستگی مهارت کسب شده است", "xcompetenciesproficientoutofyincourse": "شما در {{$a.x}} شایستگی از {{$a.y}} شایستگی ماهر هستید." } \ No newline at end of file diff --git a/www/addons/competency/lang/fr.json b/www/addons/competency/lang/fr.json index 54703a62fc1..e6510df8b0b 100644 --- a/www/addons/competency/lang/fr.json +++ b/www/addons/competency/lang/fr.json @@ -5,7 +5,7 @@ "coursecompetencyratingsarenotpushedtouserplans": "Les évaluations de compétences de ce cours n'ont pas d'influence sur les plans de formation.", "coursecompetencyratingsarepushedtouserplans": "Les évaluations de compétences de ce cours sont immédiatement reportées dans les plans de formation.", "crossreferencedcompetencies": "Compétences transversales", - "duedate": "Date de remise", + "duedate": "Délai d'achèvement", "errornocompetenciesfound": "Aucune compétence trouvée", "evidence": "Preuve", "learningplancompetencies": "Compétences du plan de formation", @@ -16,13 +16,13 @@ "nocrossreferencedcompetencies": "Aucune autre compétence n'est transversale pour cette compétence.", "noevidence": "Aucune preuve d'acquis", "noplanswerecreated": "Aucun plan de formation n'a été créé.", - "path": "Chemin", + "path": "Chemin :", "proficient": "Compétence acquise", - "progress": "Suivi des activités des participants", + "progress": "Progrès", "rating": "Évaluation", "reviewstatus": "Statut de validation", - "status": "Statut", - "template": "Modèle", + "status": "Statut du badge", + "template": "Modèle de plan de formation", "xcompetenciesproficientoutofy": "{{$a.x}} compétences sur {{$a.y}} sont acquises", "xcompetenciesproficientoutofyincourse": "Vous avez acquis {{$a.x}} compétences sur {{$a.y}} dans ce cours." } \ No newline at end of file diff --git a/www/addons/competency/lang/he.json b/www/addons/competency/lang/he.json index ffae1727aab..0a89741eb32 100644 --- a/www/addons/competency/lang/he.json +++ b/www/addons/competency/lang/he.json @@ -5,8 +5,8 @@ "coursecompetencyratingsarenotpushedtouserplans": "השלמת מיומנויות בקורס זה לא מתעדכנות בתוכניות־הלימוד", "coursecompetencyratingsarepushedtouserplans": "מצב רכישת מיומנות כתוצאה מהשלמת פעילות בקורס, מתעדכן באופן מידי בתוכניות־הלימוד.", "crossreferencedcompetencies": "מקושר למיומנויות", - "duedate": "תאריך סופי", - "evidence": "סימוכין", + "duedate": "עד לתאריך", + "evidence": "ראיה לבקיאות", "learningplancompetencies": "מיומנויות תוכנית־הלימוד", "learningplans": "תוכניות־לימוד", "myplans": "תוכניות הלימודים שלי", @@ -15,13 +15,13 @@ "nocrossreferencedcompetencies": "אף מיומנות לא מקושרת למיומנות זו.", "noevidence": "טרם צורפה ראיה לבקיאות", "noplanswerecreated": "טרם נוצרו תוכניות־לימוד.", - "path": "נתיב:", + "path": "נתיב", "proficient": "בקיאות", - "progress": "מעקב התקדמות למידה", - "rating": "דירוג", + "progress": "התקדמות", + "rating": "דרוג", "reviewstatus": "סקירת מצב", - "status": "מצב", - "template": "תבנית", + "status": "סטטוס ההישג", + "template": "תבנית תוכנית־לימוד", "xcompetenciesproficientoutofy": "בקיאות ב {{$a.x}} מיומנויות מתוך {{$a.y}}", "xcompetenciesproficientoutofyincourse": "רכשתם בקיאות ב {{$a.x}} מתוך {{$a.y}} המיומנויות בקורס זה." } \ No newline at end of file diff --git a/www/addons/competency/lang/hu.json b/www/addons/competency/lang/hu.json index 101f0f9a6a0..eb64c67f47c 100644 --- a/www/addons/competency/lang/hu.json +++ b/www/addons/competency/lang/hu.json @@ -5,7 +5,7 @@ "coursecompetencyratingsarenotpushedtouserplans": "A kurzus készségbesorolásai nem érintik a tanulási terveket.", "coursecompetencyratingsarepushedtouserplans": "A kurzus készségbesorolásai azonnal frissülnek a tanulási tervekben.", "crossreferencedcompetencies": "Kereszthivatkozott készségek", - "duedate": "Határidő", + "duedate": "Esedékesség", "evidence": "Bizonyíték", "learningplancompetencies": "Tanulási tervhez tartozó készségek", "learningplans": "Tanulási tervek", @@ -15,13 +15,13 @@ "nocrossreferencedcompetencies": "A készséghez kereszthivatkozással nem kapcsolódik más készség.", "noevidence": "Nincs bizonyíték", "noplanswerecreated": "Nem jött létre tanulási terv.", - "path": "Útvonal", + "path": "Útvonal:", "proficient": "Sikeres", - "progress": "A tanuló előmenetele", - "rating": "Értékelés", + "progress": "Előmenetel", + "rating": "Besorolás", "reviewstatus": "Ellenőrzés állapota", - "status": "Állapot", - "template": "Sablon", + "status": "A kitűző állapota", + "template": "Tanulási tervsablon", "xcompetenciesproficientoutofy": "{{$a.x}} / {{$a.y}} készség eredményes", "xcompetenciesproficientoutofyincourse": "Ön a kurzusban {{$a.y}} közül {{$a.x}} készség tekintetében eredményesnek bizonyul." } \ No newline at end of file diff --git a/www/addons/competency/lang/it.json b/www/addons/competency/lang/it.json index 9c5d5159c01..d9cf5441319 100644 --- a/www/addons/competency/lang/it.json +++ b/www/addons/competency/lang/it.json @@ -5,9 +5,9 @@ "coursecompetencyratingsarenotpushedtouserplans": "Le valutazioni delle competenze nel corso non si riflettono nei piani di formazione.", "coursecompetencyratingsarepushedtouserplans": "Le valutazione delle competenze nel corso si riflettono immediatamente nei piani di formazione.", "crossreferencedcompetencies": "Competenze con riferimento incrociato", - "duedate": "Termine consegne", + "duedate": "Data di termine", "errornocompetenciesfound": "Non sono state trovate competenze", - "evidence": "Verifica", + "evidence": "Attestazione", "learningplancompetencies": "Competenze del piano di formazione", "learningplans": "Piani di formazione", "myplans": "I miei piani di formazione", @@ -16,13 +16,13 @@ "nocrossreferencedcompetencies": "Non ci sono competenze con riferimenti incrociati a questa competenza", "noevidence": "Non sono presenti attestazioni.", "noplanswerecreated": "Non sono stati creati piani di formazione", - "path": "Percorso", + "path": "Percorso:", "proficient": "Esperto", - "progress": "Situazione dello studente", + "progress": "Avanzamento", "rating": "Valutazione", "reviewstatus": "Stato della revisione", - "status": "Stato", - "template": "Modello", + "status": "Stato badge", + "template": "Modello di piano di formazione", "xcompetenciesproficientoutofy": "{{$a.x}} competenze su {{$a.y}} sono a livello di esperto", "xcompetenciesproficientoutofyincourse": "Possiedi un livello di esperto in {{$a.x}} competenze su {{$a.y}} competenze di questo corso." } \ No newline at end of file diff --git a/www/addons/competency/lang/ja.json b/www/addons/competency/lang/ja.json index 5b45ea08016..d959d9ab61a 100644 --- a/www/addons/competency/lang/ja.json +++ b/www/addons/competency/lang/ja.json @@ -5,23 +5,24 @@ "coursecompetencyratingsarenotpushedtouserplans": "このコース内でのコンピテンシー評定は学習プランに影響しません。", "coursecompetencyratingsarepushedtouserplans": "このコース内でのコンピテンシー評定は学習プラン内ですぐに更新されます。", "crossreferencedcompetencies": "クロスリファレンスコンピテンシー", - "duedate": "終了日時", + "duedate": "期限", + "errornocompetenciesfound": "コンピテンシーが見つかりません", "evidence": "エビデンス", "learningplancompetencies": "学習プランコンピテンシー", "learningplans": "学習プラン", "myplans": "マイ学習プラン", "noactivities": "活動なし", - "nocompetencies": "このフレームワークにコンピテンシーは作成されていません。", + "nocompetencies": "コンピテンシーなし", "nocrossreferencedcompetencies": "このコンピテンシーに相互参照されている他のコンピテンシーはありません。", "noevidence": "エビデンスなし", "noplanswerecreated": "学習プランは作成されませんでした。", - "path": "パス", + "path": "パス:", "proficient": "熟達", - "progress": "学生の進捗", - "rating": "評価", + "progress": "進捗", + "rating": "評定", "reviewstatus": "レビューステータス", - "status": "ステータス", - "template": "テンプレート", + "status": "バッジステータス", + "template": "学習プランテンプレート", "xcompetenciesproficientoutofy": "{{$a.x}} / {{$a.y}} のコンピテンシーで熟達しています。", "xcompetenciesproficientoutofyincourse": "あなたはこのコースに関して {{$a.x}} / {{$a.y}} のコンピテンシーで熟達しています。" } \ No newline at end of file diff --git a/www/addons/competency/lang/lt.json b/www/addons/competency/lang/lt.json index bfd76f8a42c..e7f4c88b879 100644 --- a/www/addons/competency/lang/lt.json +++ b/www/addons/competency/lang/lt.json @@ -1,8 +1,9 @@ { - "activities": "Veikla", + "activities": "Veiklos", "coursecompetencies": "Kurso kompetencijos", "coursecompetencyratingsarenotpushedtouserplans": "Kompetencijų reitingai šiame kurse neturi įtakos mokymosi planams.", - "duedate": "Data pristatymui", + "crossreferencedcompetencies": "Kryžminės kompetencijos", + "duedate": "Terminas", "errornocompetenciesfound": "Kompetencijų nerasta", "evidence": "Įrodymas", "learningplancompetencies": "Mokymosi plano kompetencijos", @@ -10,10 +11,15 @@ "myplans": "Mano mokymosi planai", "noactivities": "Nėra veiklų", "nocompetencies": "Nėra kompetencijų", + "nocrossreferencedcompetencies": "Jokios kitos kompetencijos nebuvo susietos kryžmine nuoroda su šia kompetencija.", + "noevidence": "Nėra įrodymų", "noplanswerecreated": "Nebuvo sukurta mokymosi planų.", "path": "Kelias", - "progress": "Besimokančiojo pažanga", - "rating": "Vertinimas", - "status": "Būsena", - "template": "Šablonas" + "proficient": "Įgūdis", + "progress": "Progresas", + "rating": "Reitingas", + "reviewstatus": "Peržiūros būsena", + "status": "Pasiekimo būsena", + "template": "Mokymosi plano šablonas", + "xcompetenciesproficientoutofyincourse": "Įgijote {{$a.x}} iš {{$a.y}} kompetenciją šiame kurse." } \ No newline at end of file diff --git a/www/addons/competency/lang/nl.json b/www/addons/competency/lang/nl.json index 5dff19cfe87..f03e99ab177 100644 --- a/www/addons/competency/lang/nl.json +++ b/www/addons/competency/lang/nl.json @@ -5,7 +5,7 @@ "coursecompetencyratingsarenotpushedtouserplans": "Competentiebeoordelingen in deze cursus hebben geen invloed op studieplannnen.", "coursecompetencyratingsarepushedtouserplans": "Competentiebeoordelingen in deze cursus worden onmiddellijk aangepast in studieplannen.", "crossreferencedcompetencies": "Competenties met kruisverwijzingen", - "duedate": "Uiterste inleverdatum", + "duedate": "Klaar tegen", "errornocompetenciesfound": "Geen competenties gevonden", "evidence": "Bewijs", "learningplancompetencies": "Studieplan competenties", @@ -16,13 +16,13 @@ "nocrossreferencedcompetencies": "Er zijn geen andere competenties met een kruisverwijzing naar deze competentie.", "noevidence": "Geen bewijs", "noplanswerecreated": "Er zijn nog geen studieplannen gemaakt", - "path": "Pad", + "path": "Pad:", "proficient": "Geslaagd", - "progress": "Vordering leerling", + "progress": "Vordering", "rating": "Beoordeling", "reviewstatus": "Beoordelingsstatus", - "status": "Status", - "template": "Sjabloon", + "status": "Badge status", + "template": "Studieplansjabloon", "xcompetenciesproficientoutofy": "{{$a.x}} van de {{$a.y}} competenties zijn bekwaam", "xcompetenciesproficientoutofyincourse": "Je bent bekwaam in {{$a.x}} van de {{$a.y}} competenties in deze cursus." } \ No newline at end of file diff --git a/www/addons/competency/lang/pl.json b/www/addons/competency/lang/pl.json index 2b72a64195a..f548cb4520d 100644 --- a/www/addons/competency/lang/pl.json +++ b/www/addons/competency/lang/pl.json @@ -1,7 +1,7 @@ { "activities": "Aktywności", "coursecompetencies": "Kompetencje kursu", - "duedate": "Termin oddania", + "duedate": "Termin", "evidence": "Dowód", "learningplancompetencies": "Kompetencje planu nauczania", "learningplans": "Plany nauczania", @@ -10,10 +10,10 @@ "nocompetencies": "Nie utworzono żadnych kompetencji w tych ramach kwalifikacji.", "noevidence": "Brak dowodów", "noplanswerecreated": "Nie utworzono planów uczenia się.", - "path": "Ścieżka", - "progress": "Postępy studenta w nauce", + "path": "Ścieżka:", + "progress": "Postęp", "rating": "Ocena", "reviewstatus": "Status przeglądu", - "status": "Status", - "template": "Szablon" + "status": "Status odznak", + "template": "Szablon planu uczenia się." } \ No newline at end of file diff --git a/www/addons/competency/lang/pt-br.json b/www/addons/competency/lang/pt-br.json index 268860975f8..dc30bfcf0d3 100644 --- a/www/addons/competency/lang/pt-br.json +++ b/www/addons/competency/lang/pt-br.json @@ -5,7 +5,7 @@ "coursecompetencyratingsarenotpushedtouserplans": "Avaliações de competência neste curso não afetam os planos de aprendizagem.", "coursecompetencyratingsarepushedtouserplans": "Avaliações de competência neste curso são atualizadas imediatamente nos planos de aprendizagem.", "crossreferencedcompetencies": "Competências referenciadas", - "duedate": "Data de entrega", + "duedate": "Data de encerramento", "errornocompetenciesfound": "Nenhuma competência encontrada", "evidence": "Evidência", "learningplancompetencies": "Competências do plano de aprendizagem", @@ -16,13 +16,13 @@ "nocrossreferencedcompetencies": "Nenhuma outra competência foi referenciada a esta competência.", "noevidence": "Nenhuma evidência", "noplanswerecreated": "Nenhum plano de aprendizagem foi criado.", - "path": "Caminho", + "path": "Caminho:", "proficient": "Proficiente", - "progress": "Progresso do aluno", + "progress": "Progresso", "rating": "Avaliação", "reviewstatus": "Estado da revisão", - "status": "Status", - "template": "Modelo", + "status": "Status do emblema", + "template": "Modelo de plano de aprendizagem", "xcompetenciesproficientoutofy": "{{$a.x}} de {{$a.y}} competências são proficiêntes", "xcompetenciesproficientoutofyincourse": "Você é proficiente em {{$a.x}} de {{$a.y}} competências neste curso." } \ No newline at end of file diff --git a/www/addons/competency/lang/pt.json b/www/addons/competency/lang/pt.json index 9acc0bd20d8..f8d90d2f944 100644 --- a/www/addons/competency/lang/pt.json +++ b/www/addons/competency/lang/pt.json @@ -5,9 +5,9 @@ "coursecompetencyratingsarenotpushedtouserplans": "As avaliações das competências nesta disciplina não afetam os planos de aprendizagem.", "coursecompetencyratingsarepushedtouserplans": "As avaliações das competências nesta disciplina são automaticamente atualizadas nos planos de aprendizagem.", "crossreferencedcompetencies": "Competências referenciadas", - "duedate": "Data limite para submeter trabalhos", + "duedate": "Data de fim", "errornocompetenciesfound": "Competências não encontradas", - "evidence": "Evidência", + "evidence": "Comprovativo", "learningplancompetencies": "Competências do plano de aprendizagem", "learningplans": "Planos de aprendizagem", "myplans": "Os meus planos de aprendizagem", @@ -16,13 +16,13 @@ "nocrossreferencedcompetencies": "Nenhuma competência foi referenciada a esta competência.", "noevidence": "Não foi adicionado nenhum comprovativo", "noplanswerecreated": "Nenhum plano de aprendizagem foi criado.", - "path": "Caminho", + "path": "Localização:", "proficient": "Proficiente", - "progress": "Progresso do aluno", + "progress": "Progresso", "rating": "Avaliação", "reviewstatus": "Estado da revisão", - "status": "Estado", - "template": "Modelo", + "status": "Estado da Medalha", + "template": "Modelo de plano de aprendizagem", "xcompetenciesproficientoutofy": "Tem proficiência em {{$a.x}} de {{$a.y}} competências", "xcompetenciesproficientoutofyincourse": "Tem proficiência em {{$a.x}} de {{$a.y}} competências nesta disciplina" } \ No newline at end of file diff --git a/www/addons/competency/lang/ro.json b/www/addons/competency/lang/ro.json index 63d6243c09f..9dec53a5b19 100644 --- a/www/addons/competency/lang/ro.json +++ b/www/addons/competency/lang/ro.json @@ -1,10 +1,10 @@ { - "activities": "Activităţi", + "activities": "Activități", "duedate": "Termen de predare", "evidence": "Evidență", "path": "Cale", "progress": "Progres student", "rating": "Rating", - "status": "Status", + "status": "Status ecuson", "template": "Șablon" } \ No newline at end of file diff --git a/www/addons/competency/lang/ru.json b/www/addons/competency/lang/ru.json index d268e9046ac..b4dd1160c36 100644 --- a/www/addons/competency/lang/ru.json +++ b/www/addons/competency/lang/ru.json @@ -1,12 +1,12 @@ { - "activities": "Элементы курса", + "activities": "Элементы", "competenciesmostoftennotproficientincourse": "Компетенции, которые чаще всего оказываются не освоенными в этом курсе", "coursecompetencies": "Компетенции курса", "coursecompetencyratingsarenotpushedtouserplans": "Рейтинги компетенций из этого курса не влияют на учебные планы.", "coursecompetencyratingsarepushedtouserplans": "Рейтинги компетенций из этого курса сразу же обновляются в учебных планах.", "crossreferencedcompetencies": "Перекрестные компетенции", - "duedate": "Последний срок сдачи", - "evidence": "Подтверждение", + "duedate": "Срок выполнения", + "evidence": "Доказательство", "learningplancompetencies": "Компетенции учебного плана", "learningplans": "Учебные планы", "myplans": "Мои учебные планы", @@ -15,13 +15,13 @@ "nocrossreferencedcompetencies": "Нет других компетенций, перекрестно ссылающихся на эту компетенцию.", "noevidence": "Нет доказательств", "noplanswerecreated": "Учебные планы не были созданы.", - "path": "Путь", + "path": "Путь:", "proficient": "Освоено", - "progress": "Достижения студента", + "progress": "В процессе", "rating": "Рейтинг", "reviewstatus": "Статус пересмотра", - "status": "Статус", - "template": "Шаблон", + "status": "Статус значка", + "template": "Шаблон учебного плана", "xcompetenciesproficientoutofy": "{{$a.x}} из {{$a.y}} компетенций освоены", "xcompetenciesproficientoutofyincourse": "Вы освоили {{$a.x}} из {{$a.y}} компетенций в этом курсе." } \ No newline at end of file diff --git a/www/addons/competency/lang/sr-cr.json b/www/addons/competency/lang/sr-cr.json new file mode 100644 index 00000000000..d9f5a2c019b --- /dev/null +++ b/www/addons/competency/lang/sr-cr.json @@ -0,0 +1,28 @@ +{ + "activities": "Активности", + "competenciesmostoftennotproficientincourse": "Компетенције које најчешће нису усавршене на овом курсу", + "coursecompetencies": "Компетенције курса", + "coursecompetencyratingsarenotpushedtouserplans": "Рангирање компетенција на овом курсу на утиче на планове учења.", + "coursecompetencyratingsarepushedtouserplans": "Рангирање компетенција на овом курсу се аутоматски ажурира у плановима учења.", + "crossreferencedcompetencies": "Унакрсно повезане компетенције", + "duedate": "Крајњи рок", + "errornocompetenciesfound": "Није пронађена ниједна компетенција", + "evidence": "Доказ", + "learningplancompetencies": "Компетенције плана учења", + "learningplans": "Планови учења", + "myplans": "Моји планови учења", + "noactivities": "Нема активности", + "nocompetencies": "Нема компетенција", + "nocrossreferencedcompetencies": "Ниједна друга компетенција није унакрсно повезана са овом компетенцијом.", + "noevidence": "Нема доказа", + "noplanswerecreated": "Није креиран ниједан план учења.", + "path": "Путања", + "proficient": "Стручан", + "progress": "Напредовање полазника", + "rating": "Оцена", + "reviewstatus": "Прегледај статус", + "status": "Статус", + "template": "Шаблон", + "xcompetenciesproficientoutofy": "{{$a.x}} од {{$a.y}} компетенција су на највишем нивоу стручности", + "xcompetenciesproficientoutofyincourse": "Стручни сте у {{$a.x}} од {{$a.y}} компетенција на овом курсу." +} \ No newline at end of file diff --git a/www/addons/competency/lang/sr-lt.json b/www/addons/competency/lang/sr-lt.json new file mode 100644 index 00000000000..2a3c179861a --- /dev/null +++ b/www/addons/competency/lang/sr-lt.json @@ -0,0 +1,28 @@ +{ + "activities": "Aktivnosti", + "competenciesmostoftennotproficientincourse": "Kompetencije koje najčešće nisu usavršene na ovom kursu", + "coursecompetencies": "Kompetencije kursa", + "coursecompetencyratingsarenotpushedtouserplans": "Rangiranje kompetencija na ovom kursu na utiče na planove učenja.", + "coursecompetencyratingsarepushedtouserplans": "Rangiranje kompetencija na ovom kursu se automatski ažurira u planovima učenja.", + "crossreferencedcompetencies": "Unakrsno povezane kompetencije", + "duedate": "Krajnji rok", + "errornocompetenciesfound": "Nije pronađena nijedna kompetencija", + "evidence": "Dokaz", + "learningplancompetencies": "Kompetencije plana učenja", + "learningplans": "Planovi učenja", + "myplans": "Moji planovi učenja", + "noactivities": "Nema aktivnosti", + "nocompetencies": "Nema kompetencija", + "nocrossreferencedcompetencies": "Nijedna druga kompetencija nije unakrsno povezana sa ovom kompetencijom.", + "noevidence": "Nema dokaza", + "noplanswerecreated": "Nije kreiran nijedan plan učenja.", + "path": "Putanja", + "proficient": "Stručan", + "progress": "Napredovanje polaznika", + "rating": "Ocena", + "reviewstatus": "Pregledaj status", + "status": "Status", + "template": "Šablon", + "xcompetenciesproficientoutofy": "{{$a.x}} od {{$a.y}} kompetencija su na najvišem nivou stručnosti", + "xcompetenciesproficientoutofyincourse": "Stručni ste u {{$a.x}} od {{$a.y}} kompetencija na ovom kursu." +} \ No newline at end of file diff --git a/www/addons/competency/lang/sv.json b/www/addons/competency/lang/sv.json index a87634db442..15a7a9216ef 100644 --- a/www/addons/competency/lang/sv.json +++ b/www/addons/competency/lang/sv.json @@ -5,8 +5,8 @@ "coursecompetencyratingsarenotpushedtouserplans": "Bedömning av kompetenser i denna kurs kommer inte att påverka studieplaner.", "coursecompetencyratingsarepushedtouserplans": "Bedömning av kompetenser i denna kurs uppdateras omedelbart i studieplanerna.", "crossreferencedcompetencies": "Korsrefererade kompetenser.", - "duedate": "Stoppdatum/tid", - "evidence": "Bevis", + "duedate": "Sista inskickningsdatum", + "evidence": "Verifiering", "learningplancompetencies": "Kompetenser i studieplaner", "learningplans": "Studieplaner", "myplans": "Mina studieplaner", @@ -15,13 +15,13 @@ "nocrossreferencedcompetencies": "Inga andra kompetenser har korsrefererats till denna kompetens.", "noevidence": "Inga verifieringar", "noplanswerecreated": "Inga studieplaner var skapade.", - "path": "Sökväg", + "path": "Sökväg:", "proficient": "Kunnig", - "progress": "Kursdeltagares progression", - "rating": "Betygssättning/omdömen", + "progress": "Utveckling", + "rating": "Bedömning", "reviewstatus": "Granska status", - "status": "Status", - "template": "Mall", + "status": "Status för märke", + "template": "Mall för studieplan", "xcompetenciesproficientoutofy": "{{$a.x}} av {{$a.y}} kompetenser är uppnådda", "xcompetenciesproficientoutofyincourse": "Du har uppnått {{$a.x}} av {{$a.y}} kompetenser i denna kurs.." } \ No newline at end of file diff --git a/www/addons/competency/lang/tr.json b/www/addons/competency/lang/tr.json index aaf5e15f532..4253ce29f6c 100644 --- a/www/addons/competency/lang/tr.json +++ b/www/addons/competency/lang/tr.json @@ -5,8 +5,8 @@ "coursecompetencyratingsarenotpushedtouserplans": "Bu dersin yetkinlik dereceleri öğrenme planlarını etkilemez.", "coursecompetencyratingsarepushedtouserplans": "Bu dersin yetkinlik dereceleri öğrenme planlarında anında güncellenir.", "crossreferencedcompetencies": "Çapraz referanslı yetkinlikler", - "duedate": "Son teslim tarihi", - "evidence": "Kanıt", + "duedate": "Bitiş tarihi", + "evidence": "Öğrenme kanıtı", "learningplancompetencies": "Öğrenme planı yetkinlikleri", "learningplans": "Öğrenme planları", "myplans": "Benim öğrenme planlarım", @@ -15,13 +15,13 @@ "nocrossreferencedcompetencies": "Bu yetkinliğe çapraz referanslı başka yetkinlik bulunmamaktadır.", "noevidence": "Öğrenme kanıtı yok", "noplanswerecreated": "Hiçbir öğrenme planı oluşturulmadı.", - "path": "Yol", + "path": "Yol:", "proficient": "Yeterli", - "progress": "Öğrenci ilerlemesi", + "progress": "İlerleme", "rating": "Derecelendirme", "reviewstatus": "İnceleme durumu", - "status": "Durum", - "template": "Şablon", + "status": "Nişan Durumu", + "template": "Öğrenme planı şablonu", "xcompetenciesproficientoutofy": "{{$a.y}} yetkinliğinden {{$a.x}} dışarıda yeterli", "xcompetenciesproficientoutofyincourse": "Bu derste {{$a.y}} yetkinliğin dışında {{$a.x}} yeterliliğe sahibisiniz." } \ No newline at end of file diff --git a/www/addons/competency/lang/uk.json b/www/addons/competency/lang/uk.json index d764c9bda7c..376f4e9d48f 100644 --- a/www/addons/competency/lang/uk.json +++ b/www/addons/competency/lang/uk.json @@ -1,13 +1,13 @@ { - "activities": "Види діяльності", + "activities": "Діяльності", "competenciesmostoftennotproficientincourse": "Компетентності, які найчастіше не досягаються у цьому курсі", "coursecompetencies": "Компетентності курсу", "coursecompetencyratingsarenotpushedtouserplans": "Оцінювання компетентностей цього курсу не впливають на навчальні плани", "coursecompetencyratingsarepushedtouserplans": "Оцінювання компетентностей цього курсу будуть зразу передані в навчальні плани.", "crossreferencedcompetencies": "Пов'язані компетентності", - "duedate": "Кінцевий термін здачі", + "duedate": "Кінцевий термін", "errornocompetenciesfound": "Не знайдено компетенції", - "evidence": "Докази", + "evidence": "Підтвердження", "learningplancompetencies": "Компетентності навчального плану", "learningplans": "Навчальний план", "myplans": "Мої навчальні плани", @@ -16,13 +16,13 @@ "nocrossreferencedcompetencies": "Жодна інша компетентність не пов'язана з даною", "noevidence": "Жодного підтвердження", "noplanswerecreated": "Жодного навчального плану не було створено", - "path": "Шлях", + "path": "Шлях:", "proficient": "Набута компетентність", - "progress": "Прогрес студента", - "rating": "Оцінка", + "progress": "Прогрес", + "rating": "Оцінювання", "reviewstatus": "Статус підтвердження", - "status": "Статус", - "template": "Шаблон", + "status": "Статус відзнаки", + "template": "Шаблон навчального плану", "xcompetenciesproficientoutofy": "{{$a.x}} компетентностей з {{$a.y}} набуті", "xcompetenciesproficientoutofyincourse": "Ви набули {{$a.x}} компетентностей з {{$a.y}} наявних у цьому курсі" } \ No newline at end of file diff --git a/www/addons/competency/lang/zh-cn.json b/www/addons/competency/lang/zh-cn.json index e22e787d956..48f9fe6ae99 100644 --- a/www/addons/competency/lang/zh-cn.json +++ b/www/addons/competency/lang/zh-cn.json @@ -2,15 +2,15 @@ "activities": "活动", "competenciesmostoftennotproficientincourse": "在这门课程中你有太多不精通的能力", "coursecompetencies": "课程能力", - "duedate": "截止时间", + "duedate": "截止日", "evidence": "凭据", "noactivities": "没有设置活动", "path": "路径", "proficient": "精通", "progress": "学生进度", "rating": "正在评分", - "status": "状态", - "template": "模板", + "status": "勋章状态", + "template": "学习计划模板", "xcompetenciesproficientoutofy": "{{$a.y}}个能力中的{{$a.x}}是精通的", "xcompetenciesproficientoutofyincourse": "你精通这门课程{{$a.y}}个能力中的{{$a.x}}个。" } \ No newline at end of file diff --git a/www/addons/competency/lang/zh-tw.json b/www/addons/competency/lang/zh-tw.json index fe0b027bb70..9106adffc4f 100644 --- a/www/addons/competency/lang/zh-tw.json +++ b/www/addons/competency/lang/zh-tw.json @@ -5,7 +5,7 @@ "coursecompetencyratingsarenotpushedtouserplans": "在這一課程的核心能力評等不會影響學習計畫", "coursecompetencyratingsarepushedtouserplans": "在這一課程的核心能力評等在學習計畫上會立即更新", "crossreferencedcompetencies": "交互參照的核心能力", - "duedate": "規定繳交時間", + "duedate": "到期日", "errornocompetenciesfound": "找不到能使用的功能", "evidence": "證據", "learningplancompetencies": "學習計畫核心能力", @@ -16,13 +16,13 @@ "nocrossreferencedcompetencies": "沒有其他核心能力被交互參照這一核心能力", "noevidence": "沒有證據", "noplanswerecreated": "沒有學習計畫被建立", - "path": "路徑", + "path": "路徑:", "proficient": "精熟", - "progress": "學生進度", - "rating": "評比", + "progress": "進度", + "rating": "評等", "reviewstatus": "審查狀況", - "status": "狀態", - "template": "範本", + "status": "獎章狀態", + "template": "學習計畫樣版", "xcompetenciesproficientoutofy": "在{{$a.y}}個核心能力中有{{$a.x}}個已經精熟", "xcompetenciesproficientoutofyincourse": "在此課程中有{{$a.y}}個核心能力,你已經精熟{{$a.x}}個。" } \ No newline at end of file diff --git a/www/addons/coursecompletion/lang/ar.json b/www/addons/coursecompletion/lang/ar.json index 7faf3c038ac..f88bc955bca 100644 --- a/www/addons/coursecompletion/lang/ar.json +++ b/www/addons/coursecompletion/lang/ar.json @@ -1,19 +1,19 @@ { - "complete": "كامل", + "complete": "مكتمل", "completecourse": "مقرر مكتمل", - "completed": "تم", + "completed": "تم إكمال المقرر", "completiondate": "تاريخ إكمال المقرر", "couldnotloadreport": "لا يمكن تحميل تقرير إكمال المقرر، الرجاء المحاولة في وقت آخر", - "coursecompletion": "إكمال المقرر الدراسي", - "criteria": "معايير", - "criteriagroup": "مجموعة المعايير", + "coursecompletion": "إكمال المقرر", + "criteria": "المعايير", + "criteriagroup": "معايير المجموعة", "criteriarequiredall": "كل المعايير في الأسفل مطلوبة", - "criteriarequiredany": "أي معيار في الأسفل مطلوب", + "criteriarequiredany": "أي معايير في الأسفل مطلوبة", "inprogress": "قيد التنفيذ", - "manualselfcompletion": "إكمال يدوي ذاتي", + "manualselfcompletion": "إكمال ذاتي يدوي", "notyetstarted": "لم يبدأ بعد", - "pending": "معلق", - "required": "مفروض", + "pending": "قيد الانتظار", + "required": "مطلوب", "requiredcriteria": "المعايير المطلوبة", "requirement": "المتطلبات", "status": "الحالة", diff --git a/www/addons/coursecompletion/lang/bg.json b/www/addons/coursecompletion/lang/bg.json index e60bae81321..245ed87b13c 100644 --- a/www/addons/coursecompletion/lang/bg.json +++ b/www/addons/coursecompletion/lang/bg.json @@ -1,14 +1,14 @@ { - "complete": "Завършен", - "completed": "Завършено", - "coursecompletion": "Завършване на курса", + "complete": "Отговорен", + "completed": "Завършена", + "coursecompletion": "Напредване в курса", "criteria": "Критерии", "criteriagroup": "Група критерии", "criteriarequiredall": "Всички критерии по-долу са задължителни", "criteriarequiredany": "Някои критерии по-долу са задължителни", "inprogress": "Не е приключен", "manualselfcompletion": "Ръчно самоотбелязване на завършването", - "required": "Задължително", - "status": "Състояние", + "required": "Задължителен", + "status": "Състояние на значка", "viewcoursereport": "Вижте отчет за курса" } \ No newline at end of file diff --git a/www/addons/coursecompletion/lang/da.json b/www/addons/coursecompletion/lang/da.json index 21281be057e..9d2cdeb93a0 100644 --- a/www/addons/coursecompletion/lang/da.json +++ b/www/addons/coursecompletion/lang/da.json @@ -1,20 +1,20 @@ { - "complete": "Færdiggør", + "complete": "Fuldfør", "completecourse": "Fuldfør kursus", - "completed": "Gennemført", + "completed": "Fuldført", "completiondate": "Afslutningsdato", "couldnotloadreport": "Kunne ikke indlæse rapporten vedrørende kursusfuldførelse, prøv igen senere.", - "coursecompletion": "Kursusgennemførelse", - "criteria": "Kriterie", - "criteriagroup": "Kriteriegruppe", - "criteriarequiredall": "Alle kriterier herunder er påkrævet", - "criteriarequiredany": "Ethvert kriterium herunder er påkrævet", - "inprogress": "Igangværende", - "manualselfcompletion": "Manuel selvregistrering af gennemførelse", - "notyetstarted": "Ikke begyndt endnu", - "pending": "Behandles", - "required": "Påkrævet", - "requiredcriteria": "Påkrævede kriterier", + "coursecompletion": "Kursusfuldførelse", + "criteria": "Kriterier", + "criteriagroup": "Gruppe af kriterier", + "criteriarequiredall": "Alle nedenstående kriterier er påkrævet", + "criteriarequiredany": "Hvilken som helst af nedenstående kriterier er påkrævet", + "inprogress": "I gang", + "manualselfcompletion": "Manuel markering af færdiggørelse", + "notyetstarted": "Endnu ikke startet", + "pending": "Afventer", + "required": "Krævet", + "requiredcriteria": "Krævet kriterie", "requirement": "Krav", "status": "Status", "viewcoursereport": "Se kursusrapport" diff --git a/www/addons/coursecompletion/lang/el.json b/www/addons/coursecompletion/lang/el.json index 555b60517bd..a6fb10fd47b 100644 --- a/www/addons/coursecompletion/lang/el.json +++ b/www/addons/coursecompletion/lang/el.json @@ -10,7 +10,7 @@ "criteriarequiredall": "Όλα τα παρακάτω κριτήρια είναι υποχρεωτικά", "criteriarequiredany": "Οποιοδήποτε από τα παρακάτω κριτήρια είναι υποχρεωτικά", "inprogress": "Σε εξέλιξη", - "manualselfcompletion": "Χειροκίνητη αυτό-ολοκλήρωση", + "manualselfcompletion": "Μη αυτόματη ολοκλήρωση", "notyetstarted": "Δεν έχει ξεκινήσει ακόμα", "pending": "Εκκρεμής", "required": "Απαιτείται", diff --git a/www/addons/coursecompletion/lang/fa.json b/www/addons/coursecompletion/lang/fa.json index b9ddd4aaa56..2f308382aff 100644 --- a/www/addons/coursecompletion/lang/fa.json +++ b/www/addons/coursecompletion/lang/fa.json @@ -1,7 +1,7 @@ { "complete": "کامل", - "completed": "تکمیل‌شده", - "coursecompletion": "تکمیل درس", + "completed": "کامل شده", + "coursecompletion": "کاربر باید این درس را تکمیل کند.", "criteria": "ضابطه", "criteriagroup": "گروه ضوابط", "criteriarequiredall": "تمام ضوابط زیر باید برآورده شوند", @@ -10,8 +10,8 @@ "manualselfcompletion": "علامت زدن به عنوان کامل توسط خود افراد", "notyetstarted": "هنوز شروع نشده است", "pending": "معلق", - "required": "لازم است", + "required": "الزامی بودن", "requiredcriteria": "ضوابط مورد نیاز", - "status": "وضعیت", - "viewcoursereport": "مشاهدهٔ گزارش درس" + "status": "وضعیت مدال", + "viewcoursereport": "مشاهده گزارش درس" } \ No newline at end of file diff --git a/www/addons/coursecompletion/lang/he.json b/www/addons/coursecompletion/lang/he.json index 3036661befc..dca12273f76 100644 --- a/www/addons/coursecompletion/lang/he.json +++ b/www/addons/coursecompletion/lang/he.json @@ -1,19 +1,19 @@ { - "complete": "הושלם", + "complete": "השלמה", "completecourse": "השלמת קורס", "completed": "הושלם", "completiondate": "תאריך השלמה", - "coursecompletion": "השלמת הקורס", - "criteria": "תנאי", - "criteriagroup": "קבוצת תנאים", - "criteriarequiredall": "כל התנאים המצויינים מטה נדרשים", - "criteriarequiredany": "לפחות אחד מהתנאים המצויינים מטה נדרשים", + "coursecompletion": "השלמת קורס", + "criteria": "מדד־הערכה", + "criteriagroup": "קבוצת מדדיי־הערכה", + "criteriarequiredall": "כל מדדיי־הערכה להלן נדרשים", + "criteriarequiredany": "אחד ממדדיי־הערכה להלן נדרש", "inprogress": "בתהליך", - "manualselfcompletion": "השלמה עצמאית ידנית", - "notyetstarted": "עדיין לא התחיל", - "pending": "בתהליך למידה", - "required": "דרוש", - "requiredcriteria": "תנאי נדרש", + "manualselfcompletion": "הזנת השלמה עצמית", + "notyetstarted": "עדיין לא החל", + "pending": "בהמתנה", + "required": "נדרש", + "requiredcriteria": "מדד־הערכה נדרש", "requirement": "דרישה", "status": "מצב", "viewcoursereport": "צפיה בדוח הקורס" diff --git a/www/addons/coursecompletion/lang/hu.json b/www/addons/coursecompletion/lang/hu.json index d07a78bbda4..361a4bf7069 100644 --- a/www/addons/coursecompletion/lang/hu.json +++ b/www/addons/coursecompletion/lang/hu.json @@ -1,17 +1,17 @@ { - "complete": "Teljes", - "completed": "Teljesítve", - "coursecompletion": "Kurzus teljesítése", + "complete": "Kész", + "completed": "Kész", + "coursecompletion": "A tanulóknak teljesíteni kell ezt a kurzust", "criteria": "Követelmények", "criteriagroup": "Követelménycsoport", "criteriarequiredall": "Az összes alábbi követelmény teljesítendő", "criteriarequiredany": "Bármely alábbi követelmény teljesítendő", - "inprogress": "Folyamatban", + "inprogress": "Folyamatban lévő", "manualselfcompletion": "Saját teljesítés kézzel", "notyetstarted": "Még nem kezdődött el", "pending": "Függőben", "required": "Kitöltendő", "requiredcriteria": "Előírt követelmények", - "status": "Állapot", + "status": "A kitűző állapota", "viewcoursereport": "Kurzusjelentés megtekintése" } \ No newline at end of file diff --git a/www/addons/coursecompletion/lang/ja.json b/www/addons/coursecompletion/lang/ja.json index f53547d1c99..344ea673aea 100644 --- a/www/addons/coursecompletion/lang/ja.json +++ b/www/addons/coursecompletion/lang/ja.json @@ -1,17 +1,21 @@ { - "complete": "詳細", - "completed": "完了", + "complete": "完了", + "completecourse": "コース完了", + "completed": "完了しました", + "completiondate": "完了した日", + "couldnotloadreport": "コース完了の読み込みができませんでした。後でもう一度試してください。", "coursecompletion": "コース完了", "criteria": "クライテリア", "criteriagroup": "クライテリアグループ", - "criteriarequiredall": "下記のクライテリアすべてが必須である", - "criteriarequiredany": "下記いくつかのクライテリアが必須である", + "criteriarequiredall": "以下すべてのクライテリアが必要", + "criteriarequiredany": "以下のクライテリアいずれかが必要", "inprogress": "進行中", - "manualselfcompletion": "手動による自己完了", - "notyetstarted": "未開始", - "pending": "保留", - "required": "必須", - "requiredcriteria": "必須クライテリア", - "status": "ステータス", - "viewcoursereport": "コースレポートを表示する" + "manualselfcompletion": "手動自己完了", + "notyetstarted": "まだ開始されていない", + "pending": "保留中", + "required": "必要な", + "requiredcriteria": "必要なクライテリア", + "requirement": "要求", + "status": "状態", + "viewcoursereport": "コースレポートを見る" } \ No newline at end of file diff --git a/www/addons/coursecompletion/lang/pl.json b/www/addons/coursecompletion/lang/pl.json index db69489a520..c5ffb7263b7 100644 --- a/www/addons/coursecompletion/lang/pl.json +++ b/www/addons/coursecompletion/lang/pl.json @@ -1,17 +1,17 @@ { - "complete": "Pełna wersja", - "completed": "Ukończony", - "coursecompletion": "Ukończenie kursu", + "complete": "Zakończone", + "completed": "zakończony", + "coursecompletion": "Użytkownicy muszą ukończyć ten kurs.", "criteria": "Kryteria", "criteriagroup": "Grupa kryteriów", "criteriarequiredall": "Wszystkie poniższe kryteria są wymagane", "criteriarequiredany": "Wszystkie poniższe kryteria są wymagane", - "inprogress": "W toku", + "inprogress": "Aktualne", "manualselfcompletion": "Samodzielne oznaczenie ukończenia", "notyetstarted": "Jeszcze nie rozpoczęto", - "pending": "Oczekujący", + "pending": "Oczekujące", "required": "Wymagane", "requiredcriteria": "Wymagane kryteria", - "status": "Status", + "status": "Status odznak", "viewcoursereport": "Zobacz raport kursu" } \ No newline at end of file diff --git a/www/addons/coursecompletion/lang/ro.json b/www/addons/coursecompletion/lang/ro.json index 46b9f21bb93..7a195f67c33 100644 --- a/www/addons/coursecompletion/lang/ro.json +++ b/www/addons/coursecompletion/lang/ro.json @@ -1,21 +1,21 @@ { - "complete": "Complet", + "complete": "Finalizează", "completecourse": "Curs complet", - "completed": "Complet", + "completed": "Finalizare", "completiondate": "Data limita până la completarea acțiunii", "couldnotloadreport": "Raportul cu privire la situația completării cursului nu se poate încărca, încercați mai târziu.", - "coursecompletion": "Completarea cursului", + "coursecompletion": "Absolvire curs", "criteria": "Criterii", - "criteriagroup": "Criterii pentru grup", - "criteriarequiredall": "Indeplinirea următoarelor criterii este obligatorie", - "criteriarequiredany": "Oricare din urmatoarele criterii sunt obligatorii", - "inprogress": "În progres", - "manualselfcompletion": "Autocompletare", - "notyetstarted": "Înca nu a început", - "pending": "În asteptare", - "required": "Obligatoriu", - "requiredcriteria": "Criterii obligatorii", + "criteriagroup": "Grup criterii", + "criteriarequiredall": "Toate criteriile de mai jos sunt necesare", + "criteriarequiredany": "Oricare dintre criteriile de mai jos sunt necesare", + "inprogress": "În curs", + "manualselfcompletion": "Auto-finalizare manuală", + "notyetstarted": "Nu a fost încă început", + "pending": "În așteptare", + "required": "Necesar", + "requiredcriteria": "Criteriu necesar", "requirement": "Cerințe", - "status": "Situație", - "viewcoursereport": "Vizualizați raportul despre curs" + "status": "Status", + "viewcoursereport": "Vezi raportul cursului" } \ No newline at end of file diff --git a/www/addons/coursecompletion/lang/sr-cr.json b/www/addons/coursecompletion/lang/sr-cr.json new file mode 100644 index 00000000000..610e78602a3 --- /dev/null +++ b/www/addons/coursecompletion/lang/sr-cr.json @@ -0,0 +1,21 @@ +{ + "complete": "Заврши", + "completecourse": "Заврши курс", + "completed": "Завршено", + "completiondate": "Датум завршетка", + "couldnotloadreport": "Није могуће учитати извештај о завршетку курса. Молимо вас, покушајте поново касније.", + "coursecompletion": "Завршетак курса", + "criteria": "Критеријуми", + "criteriagroup": "Група критеријума", + "criteriarequiredall": "Сви доле наведени критеријуми су неопходни", + "criteriarequiredany": "Било који од доле наведених критеријума је неопходан", + "inprogress": "У току", + "manualselfcompletion": "Ручни самостални завршетак", + "notyetstarted": "Још није започето", + "pending": "На чекању", + "required": "Неопходно", + "requiredcriteria": "Неопходни критеријуми", + "requirement": "Услов", + "status": "Статус", + "viewcoursereport": "Прикажи извештај са курса" +} \ No newline at end of file diff --git a/www/addons/coursecompletion/lang/sr-lt.json b/www/addons/coursecompletion/lang/sr-lt.json new file mode 100644 index 00000000000..6553f9f3960 --- /dev/null +++ b/www/addons/coursecompletion/lang/sr-lt.json @@ -0,0 +1,21 @@ +{ + "complete": "Završi", + "completecourse": "Završi kurs", + "completed": "Završeno", + "completiondate": "Datum završetka", + "couldnotloadreport": "Nije moguće učitati izveštaj o završetku kursa. Molimo vas, pokušajte ponovo kasnije.", + "coursecompletion": "Završetak kursa", + "criteria": "Kriterijumi", + "criteriagroup": "Grupa kriterijuma", + "criteriarequiredall": "Svi dole navedeni kriterijumi su neophodni", + "criteriarequiredany": "Bilo koji od dole navedenih kriterijuma je neophodan", + "inprogress": "U toku", + "manualselfcompletion": "Ručni samostalni završetak", + "notyetstarted": "Još nije započeto", + "pending": "Na čekanju", + "required": "Neophodno", + "requiredcriteria": "Neophodni kriterijumi", + "requirement": "Uslov", + "status": "Status", + "viewcoursereport": "Prikaži izveštaj sa kursa" +} \ No newline at end of file diff --git a/www/addons/coursecompletion/lang/tr.json b/www/addons/coursecompletion/lang/tr.json index 89efac25b4d..3aedfd0238d 100644 --- a/www/addons/coursecompletion/lang/tr.json +++ b/www/addons/coursecompletion/lang/tr.json @@ -1,17 +1,17 @@ { - "complete": "Tamamlanmış", - "completed": "Bitirmeli", - "coursecompletion": "Ders tamamlama", + "complete": "Tamamlandı", + "completed": "Tamamlandı", + "coursecompletion": "Kurs tamamlama", "criteria": "Ölçüt", "criteriagroup": "Ölçüt Grubu", "criteriarequiredall": "Aşağıdaki ölçütlerin tümü gereklidir", "criteriarequiredany": "Aşağıdaki herhangi bir kriter gereklidir", - "inprogress": "Devam ediyor", + "inprogress": "Devam etmekte", "manualselfcompletion": "Kendi kendine elle tamamlama", "notyetstarted": "Henüz başlamadı", "pending": "Bekliyor", "required": "Gerekli", "requiredcriteria": "Gerekli Ölçüt", - "status": "Durum", + "status": "Nişan Durumu", "viewcoursereport": "Kurs raporunu görüntüle" } \ No newline at end of file diff --git a/www/addons/coursecompletion/lang/uk.json b/www/addons/coursecompletion/lang/uk.json index 86fa3eecf17..790fda5169e 100644 --- a/www/addons/coursecompletion/lang/uk.json +++ b/www/addons/coursecompletion/lang/uk.json @@ -10,7 +10,7 @@ "criteriarequiredall": "Всі критерії нижче обов'язкові", "criteriarequiredany": "Будь-яка критерія нижче обов'язкова", "inprogress": "В процесі...", - "manualselfcompletion": "Завершення самостійно", + "manualselfcompletion": "Самостійне завершення", "notyetstarted": "Не розпочато", "pending": "В очікуванні", "required": "Необхідно", diff --git a/www/addons/coursecompletion/lang/zh-cn.json b/www/addons/coursecompletion/lang/zh-cn.json index f46cbe0662d..eedfdd029f5 100644 --- a/www/addons/coursecompletion/lang/zh-cn.json +++ b/www/addons/coursecompletion/lang/zh-cn.json @@ -1,17 +1,17 @@ { - "complete": "完全", - "completed": "完成", - "coursecompletion": "修完课程", + "complete": "完成", + "completed": "已完成", + "coursecompletion": "课程进度跟踪", "criteria": "条件", "criteriagroup": "条件组", "criteriarequiredall": "必须满足以下条件", "criteriarequiredany": "必须满足下列任一条件", - "inprogress": "处理中", + "inprogress": "进行中", "manualselfcompletion": "手动自设完成", "notyetstarted": "还未开始", - "pending": "等待中", - "required": "必需的", + "pending": "待决", + "required": "必须回答", "requiredcriteria": "必备条件", - "status": "状态", + "status": "勋章状态", "viewcoursereport": "查看课程报告" } \ No newline at end of file diff --git a/www/addons/files/controllers/list.js b/www/addons/files/controllers/list.js index 3dd985cc11d..79f1066cf54 100644 --- a/www/addons/files/controllers/list.js +++ b/www/addons/files/controllers/list.js @@ -49,8 +49,9 @@ angular.module('mm.addons.files') return promise.then(function(files) { $scope.files = files.entries; $scope.count = files.count; - }).catch(function() { - $mmUtil.showErrorModal('mma.files.couldnotloadfiles', true); + }).catch(function(error) { + $mmUtil.showErrorModalDefault(error, 'mma.files.couldnotloadfiles', true); + return $q.reject(); }); } diff --git a/www/addons/files/lang/ar.json b/www/addons/files/lang/ar.json index 2ab44cda49c..3521b2b6f32 100644 --- a/www/addons/files/lang/ar.json +++ b/www/addons/files/lang/ar.json @@ -4,5 +4,5 @@ "files": "ملفات", "privatefiles": "ملفات خاصة", "sitefiles": "ملفات الموقع", - "uploadfiles": "إرسل ملفات التغذية الراجعة" + "uploadfiles": "رفع ملفات" } \ No newline at end of file diff --git a/www/addons/files/lang/da.json b/www/addons/files/lang/da.json index 5f9d7d54b3b..1453d08f9f7 100644 --- a/www/addons/files/lang/da.json +++ b/www/addons/files/lang/da.json @@ -2,12 +2,12 @@ "admindisableddownload": "Bemærk venligst at din Moodleadministrator har deaktiveret download af filer. Du kan se filerne men ikke downloade dem.", "clicktoupload": "Klik på knappen nedenfor for at uploade filer til dine private filer.", "couldnotloadfiles": "Fillisten kunne ikke hentes", - "emptyfilelist": "Der er ingen filer at vise", + "emptyfilelist": "Der er ingen filer at vise.", "erroruploadnotworking": "Desværre er det p.t. ikke muligt at uploade filer til dit site.", "files": "Filer", "myprivatefilesdesc": "Filerne som er tilgængelige i dit private område på dette Moodlewebsted.", "privatefiles": "Private filer", "sitefiles": "Site filer", "sitefilesdesc": "De andre filer som er tilgængelige for dig på denne Moodlewebside.", - "uploadfiles": "Send feedbackfiler" + "uploadfiles": "Upload filer" } \ No newline at end of file diff --git a/www/addons/files/lang/de.json b/www/addons/files/lang/de.json index 39a046af215..337b5b880d1 100644 --- a/www/addons/files/lang/de.json +++ b/www/addons/files/lang/de.json @@ -1,11 +1,11 @@ { "admindisableddownload": "Das Herunterladen von Dateien ist deaktiviert. Sie können nur die Dateiliste sehen.", - "clicktoupload": "Tippen Sie auf die Taste, um Dateien in 'Meine Dateien' hochzuladen.", - "couldnotloadfiles": "Die Dateiliste konnte nicht geladen werden.", + "clicktoupload": "Tippen Sie auf die Taste, um Dateien in den Bereich 'Meine Dateien' hochzuladen.", + "couldnotloadfiles": "Die Liste der Dateien konnte nicht geladen werden.", "emptyfilelist": "Keine Dateien", "erroruploadnotworking": "Im Moment können keine Dateien zur Website hochgeladen werden.", "files": "Dateien", - "myprivatefilesdesc": "Diese Dateien liegen in Ihrem persönlichen Bereich auf dieser Website.", + "myprivatefilesdesc": "Dateien, die in Ihrem persönlichen Bereich auf dieser Website liegen.", "privatefiles": "Meine Dateien", "sitefiles": "Dateien", "sitefilesdesc": "Weitere Dateien, die für Sie in anderen Bereichen der Website verfügbar sind.", diff --git a/www/addons/files/lang/es.json b/www/addons/files/lang/es.json index d67044531b0..cca19793086 100644 --- a/www/addons/files/lang/es.json +++ b/www/addons/files/lang/es.json @@ -4,7 +4,7 @@ "couldnotloadfiles": "La lista de archivos no ha podido cargarse.", "emptyfilelist": "No hay archivos que mostrar", "erroruploadnotworking": "Desafortunadamente en estos momentos no es posible subir archivos al sitio.", - "files": "Archivos", + "files": "Ficheros", "myprivatefilesdesc": "Los archivos que están disponibles en su área privada en este sitio Moodle.", "privatefiles": "Ficheros privados", "sitefiles": "Archivos del sitio", diff --git a/www/addons/files/lang/he.json b/www/addons/files/lang/he.json index 6f612548ac8..0ed31567503 100644 --- a/www/addons/files/lang/he.json +++ b/www/addons/files/lang/he.json @@ -2,7 +2,7 @@ "admindisableddownload": "יש לשים לב כי מנהל/ת אתר המוודל שלך, ביטל/ה את אפשרות להורדת הקבצים. באפשרותך לעיין בקבצים אך לא להורידם.", "clicktoupload": "להעלאת הקבצים לקבצים הפרטיים שלך, יש להקליק על הכפתור למטה.", "couldnotloadfiles": "לא ניתן לטעון את רשימת הקבצים.", - "emptyfilelist": "אין קבצים להציג", + "emptyfilelist": "אין קבצים להצגה.", "files": "קבצים", "myprivatefilesdesc": "הקבצים הזמינים לך באזור הפרטי באתר מוודל זה.", "privatefiles": "הקבצים שלי", diff --git a/www/addons/files/lang/ja.json b/www/addons/files/lang/ja.json index 0f3df892d31..de63504d659 100644 --- a/www/addons/files/lang/ja.json +++ b/www/addons/files/lang/ja.json @@ -1,7 +1,13 @@ { - "emptyfilelist": "表示するファイルはありません。", + "admindisableddownload": "あなたのMoodle管理者に、ファイルのダウンロードを無効にするよう知らせてください。そうすれば、ファイルをデバイスにダウンロードせず閲覧のみにすることができます。", + "clicktoupload": "ファイルをあなたのプライベートファイル領域にアップロードするには、下のボタンをクリックしてください。", + "couldnotloadfiles": "以下のファイルが読み込みできませんでした。", + "emptyfilelist": "表示するファイルがありません。", + "erroruploadnotworking": "残念ながら、現在、あなたのサイトにファイルをアップロードすることはできません。", "files": "ファイル", + "myprivatefilesdesc": "ファイルはMoodleサイト上のあなたのプライベート領域にあります。", "privatefiles": "プライベートファイル", "sitefiles": "サイトファイル", - "uploadfiles": "フィードバックファイルを送信する" + "sitefilesdesc": "本Moodleサイトであなたが利用できる他のファイル", + "uploadfiles": "アップロードファイル" } \ No newline at end of file diff --git a/www/addons/files/lang/pt.json b/www/addons/files/lang/pt.json index 3e1ce1acbd4..e37a1840902 100644 --- a/www/addons/files/lang/pt.json +++ b/www/addons/files/lang/pt.json @@ -4,7 +4,7 @@ "couldnotloadfiles": "Não foi possível carregar a lista de ficheiros", "emptyfilelist": "Não há ficheiros", "erroruploadnotworking": "Infelizmente não é possível carregar ficheiros para o seu site.", - "files": "Ficheiros", + "files": "Anexos", "myprivatefilesdesc": "Ficheiros disponíveis na sua área privada neste site Moodle", "privatefiles": "Ficheiros privados", "sitefiles": "Ficheiros do site", diff --git a/www/addons/files/lang/ro.json b/www/addons/files/lang/ro.json index 30500b91c47..d8113b20c3d 100644 --- a/www/addons/files/lang/ro.json +++ b/www/addons/files/lang/ro.json @@ -2,8 +2,8 @@ "admindisableddownload": "Atenție! Administratorul platformei a dezactivat descărcarea de fișiere; puteți accesa fișierele dar nu le puteți descărca.", "clicktoupload": "Apăsați butonul de mai jos pentru a încarcă fișierele în contul dumneavoastră.", "couldnotloadfiles": "Lista fișierelor nu a putut fi încărcată.", - "emptyfilelist": "Nu sunt fișiere disponibile.", - "files": "Fişiere", + "emptyfilelist": "Nu există fișiere", + "files": "Fișiere", "myprivatefilesdesc": "Fișierele disponibile din zona personală, pe care o dețineți pe acest site.", "privatefiles": "Fișiere private", "sitefiles": "Fişiere site", diff --git a/www/addons/files/lang/sr-cr.json b/www/addons/files/lang/sr-cr.json new file mode 100644 index 00000000000..7e6b552125d --- /dev/null +++ b/www/addons/files/lang/sr-cr.json @@ -0,0 +1,13 @@ +{ + "admindisableddownload": "Имајте у виду да је ваш Moodle администратор онемогућио преузимање датотека. Датотеке можете да прегледате, али не и да их преузмете.", + "clicktoupload": "Кликните на доње дугме како бисте отпремили датотеке међу своје приватне датотеке.", + "couldnotloadfiles": "Списак датотека не може бити учитан.", + "emptyfilelist": "Нема датотека за приказ.", + "erroruploadnotworking": "Нажалост, тренутно није могуће отпремити датотеке на ваш сајт.", + "files": "Датотеке", + "myprivatefilesdesc": "Датотеке које су доступне у вашем приватном простору на овом Moodle сајту.", + "privatefiles": "Приватне датотеке", + "sitefiles": "Датотеке сајта", + "sitefilesdesc": "Остале датотеке које су доступне на овом Moodle сајту.", + "uploadfiles": "Отпреми датотеке" +} \ No newline at end of file diff --git a/www/addons/files/lang/sr-lt.json b/www/addons/files/lang/sr-lt.json new file mode 100644 index 00000000000..8779139baab --- /dev/null +++ b/www/addons/files/lang/sr-lt.json @@ -0,0 +1,13 @@ +{ + "admindisableddownload": "Imajte u vidu da je vaš Moodle administrator onemogućio preuzimanje datoteka. Datoteke možete da pregledate, ali ne i da ih preuzmete.", + "clicktoupload": "Kliknite na donje dugme kako biste otpremili datoteke među svoje privatne datoteke.", + "couldnotloadfiles": "Spisak datoteka ne može biti učitan.", + "emptyfilelist": "Nema datoteka za prikaz.", + "erroruploadnotworking": "Nažalost, trenutno nije moguće otpremiti datoteke na vaš sajt.", + "files": "Datoteke", + "myprivatefilesdesc": "Datoteke koje su dostupne u vašem privatnom prostoru na ovom Moodle sajtu.", + "privatefiles": "Privatne datoteke", + "sitefiles": "Datoteke sajta", + "sitefilesdesc": "Ostale datoteke koje su dostupne na ovom Moodle sajtu.", + "uploadfiles": "Otpremi datoteke" +} \ No newline at end of file diff --git a/www/addons/files/lang/uk.json b/www/addons/files/lang/uk.json index cb8988a3eaf..083a9f56194 100644 --- a/www/addons/files/lang/uk.json +++ b/www/addons/files/lang/uk.json @@ -1,5 +1,5 @@ { - "admindisableddownload": "Зверніть увагу, що ваш адміністратор Moodle відключив завантаження файлів, ви можете переглядати файли, але не завантажувати їх.", + "admindisableddownload": "Зверніть увагу, що ваш адміністратор Moodle відключив завантаження файлів. Ви можете переглядати файли, але не завантажувати їх.", "clicktoupload": "Натисніть на кнопку нижче, щоб завантажити ваші особисті файли.", "couldnotloadfiles": "Список файлів не може бути завантажений.", "emptyfilelist": "Немає файлів для показу.", diff --git a/www/addons/files/services/files.js b/www/addons/files/services/files.js index 058c3a9b62e..6f7c543f0bf 100644 --- a/www/addons/files/services/files.js +++ b/www/addons/files/services/files.js @@ -71,20 +71,18 @@ angular.module('mm.addons.files') * - linkId: A hash of the file parameters. */ self.getFiles = function(params) { - var deferred = $q.defer(), - options = {}; + var options = {}; options.cacheKey = getFilesListCacheKey(params); - $mmSite.read('core_files_get_files', params, options).then(function(result) { + return $mmSite.read('core_files_get_files', params, options).then(function(result) { var data = { entries: [], count: 0 }; if (typeof result.files == 'undefined') { - deferred.reject(); - return; + return $q.reject(); } angular.forEach(result.files, function(entry) { @@ -109,27 +107,13 @@ angular.module('mm.addons.files') entry.link = JSON.stringify(entry.link); entry.linkId = md5.createHash(entry.link); - // entry.localpath = ""; - - // if (!entry.isdir && entry.url) { - // // TODO Check $mmSite. - // var uniqueId = $mmSite.id + "-" + md5.createHash(entry.url); - // var path = MM.db.get("files", uniqueId); - // if (path) { - // entry.localpath = path.get("localpath"); - // } - // } data.count += 1; data.entries.push(entry); }); - deferred.resolve(data); - }, function() { - deferred.reject(); + return data; }); - - return deferred.promise; }; /** diff --git a/www/addons/frontpage/lang/da.json b/www/addons/frontpage/lang/da.json index 14f7474bfce..b3d549ab6ff 100644 --- a/www/addons/frontpage/lang/da.json +++ b/www/addons/frontpage/lang/da.json @@ -1,4 +1,4 @@ { "sitehome": "Webstedets forside", - "sitenews": "Sitenyheder" + "sitenews": "Sitemeddelelser" } \ No newline at end of file diff --git a/www/addons/frontpage/lang/es_mx.json b/www/addons/frontpage/lang/es_mx.json deleted file mode 100644 index 30cd142b296..00000000000 --- a/www/addons/frontpage/lang/es_mx.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "sitehome": "Portada" -} \ No newline at end of file diff --git a/www/addons/frontpage/lang/eu.json b/www/addons/frontpage/lang/eu.json index 2a21d6f7aa1..332c7d403ff 100644 --- a/www/addons/frontpage/lang/eu.json +++ b/www/addons/frontpage/lang/eu.json @@ -1,4 +1,4 @@ { "sitehome": "Gunearen hasiera", - "sitenews": "Gunearen berriak" + "sitenews": "Guneko albisteak" } \ No newline at end of file diff --git a/www/addons/frontpage/lang/pt_br.json b/www/addons/frontpage/lang/pt_br.json deleted file mode 100644 index 107c32efb31..00000000000 --- a/www/addons/frontpage/lang/pt_br.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "sitehome": "Página principal" -} \ No newline at end of file diff --git a/www/addons/frontpage/lang/sr-cr.json b/www/addons/frontpage/lang/sr-cr.json new file mode 100644 index 00000000000..de1f7c9cbd7 --- /dev/null +++ b/www/addons/frontpage/lang/sr-cr.json @@ -0,0 +1,4 @@ +{ + "sitehome": "Насловна страница сајта", + "sitenews": "Обавештења сајта" +} \ No newline at end of file diff --git a/www/addons/frontpage/lang/sr-lt.json b/www/addons/frontpage/lang/sr-lt.json new file mode 100644 index 00000000000..685ff10dcef --- /dev/null +++ b/www/addons/frontpage/lang/sr-lt.json @@ -0,0 +1,4 @@ +{ + "sitehome": "Naslovna stranica sajta", + "sitenews": "Obaveštenja sajta" +} \ No newline at end of file diff --git a/www/addons/frontpage/lang/zh_cn.json b/www/addons/frontpage/lang/zh_cn.json deleted file mode 100644 index 20eac284d87..00000000000 --- a/www/addons/frontpage/lang/zh_cn.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "sitehome": "首页" -} \ No newline at end of file diff --git a/www/addons/frontpage/lang/zh_tw.json b/www/addons/frontpage/lang/zh_tw.json deleted file mode 100644 index 6bff0d94024..00000000000 --- a/www/addons/frontpage/lang/zh_tw.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "sitehome": "首頁" -} \ No newline at end of file diff --git a/www/addons/grades/lang/bg.json b/www/addons/grades/lang/bg.json index 49ff4539d55..02c842d1272 100644 --- a/www/addons/grades/lang/bg.json +++ b/www/addons/grades/lang/bg.json @@ -1,3 +1,3 @@ { - "viewgrades": "Виждане на оценките" + "viewgrades": "Разглеждане на оценки" } \ No newline at end of file diff --git a/www/addons/grades/lang/el.json b/www/addons/grades/lang/el.json index c1625a02671..5517b193e17 100644 --- a/www/addons/grades/lang/el.json +++ b/www/addons/grades/lang/el.json @@ -1,4 +1,4 @@ { "nogradesreturned": "Δεν επιστράφηκε κανένας βαθμός", - "viewgrades": "Προβολή βαθμών" + "viewgrades": "Προβολή Βαθμών" } \ No newline at end of file diff --git a/www/addons/grades/lang/fa.json b/www/addons/grades/lang/fa.json index 6c9c03151dd..fd0241c2bc7 100644 --- a/www/addons/grades/lang/fa.json +++ b/www/addons/grades/lang/fa.json @@ -1,3 +1,3 @@ { - "viewgrades": "مشاهدهٔ نمره‌ها" + "viewgrades": "دیدن نمره‌ها" } \ No newline at end of file diff --git a/www/addons/grades/lang/fr.json b/www/addons/grades/lang/fr.json index 37ee094566f..1c1ce861d2d 100644 --- a/www/addons/grades/lang/fr.json +++ b/www/addons/grades/lang/fr.json @@ -1,4 +1,4 @@ { "nogradesreturned": "Aucune note retournée", - "viewgrades": "Afficher les notes" + "viewgrades": "Affichage des notes" } \ No newline at end of file diff --git a/www/addons/grades/lang/he.json b/www/addons/grades/lang/he.json index 63f5df64a1c..f6450d5c884 100644 --- a/www/addons/grades/lang/he.json +++ b/www/addons/grades/lang/he.json @@ -1,4 +1,4 @@ { "nogradesreturned": "לא הוחזרו ציונים", - "viewgrades": "ראה ציונים" + "viewgrades": "תצוגת ציונים" } \ No newline at end of file diff --git a/www/addons/grades/lang/it.json b/www/addons/grades/lang/it.json index 194c13b5f5a..883d830fb4f 100644 --- a/www/addons/grades/lang/it.json +++ b/www/addons/grades/lang/it.json @@ -1,4 +1,4 @@ { "nogradesreturned": "Non è stata ottenuta alcuna valutazione", - "viewgrades": "Visualizza risultati" + "viewgrades": "Visualizza valutazioni" } \ No newline at end of file diff --git a/www/addons/grades/lang/ja.json b/www/addons/grades/lang/ja.json index c49db645dae..23abe78a3be 100644 --- a/www/addons/grades/lang/ja.json +++ b/www/addons/grades/lang/ja.json @@ -1,4 +1,4 @@ { "nogradesreturned": "評点がありません。", - "viewgrades": "評点を表示する" + "viewgrades": "評定を表示する" } \ No newline at end of file diff --git a/www/addons/grades/lang/nl.json b/www/addons/grades/lang/nl.json index 1b33ee8446a..a11f8e821e2 100644 --- a/www/addons/grades/lang/nl.json +++ b/www/addons/grades/lang/nl.json @@ -1,4 +1,4 @@ { "nogradesreturned": "Geen cijfers", - "viewgrades": "Bekijk de cijfers" + "viewgrades": "Bekijk cijfers" } \ No newline at end of file diff --git a/www/addons/grades/lang/pl.json b/www/addons/grades/lang/pl.json index b2abf06357d..0f2f359336e 100644 --- a/www/addons/grades/lang/pl.json +++ b/www/addons/grades/lang/pl.json @@ -1,4 +1,4 @@ { "nogradesreturned": "Brak stopni", - "viewgrades": "Pokaż oceny" + "viewgrades": "Podgląd ocen" } \ No newline at end of file diff --git a/www/addons/grades/lang/ru.json b/www/addons/grades/lang/ru.json index fac7633651b..733ed0c23e6 100644 --- a/www/addons/grades/lang/ru.json +++ b/www/addons/grades/lang/ru.json @@ -1,4 +1,4 @@ { "nogradesreturned": "Нет оценок", - "viewgrades": "Посмотреть оценки" + "viewgrades": "Просмотр оценок" } \ No newline at end of file diff --git a/www/addons/grades/lang/sr-cr.json b/www/addons/grades/lang/sr-cr.json new file mode 100644 index 00000000000..88b8e81b468 --- /dev/null +++ b/www/addons/grades/lang/sr-cr.json @@ -0,0 +1,4 @@ +{ + "nogradesreturned": "Нема добијених оцена", + "viewgrades": "Приказ оцена" +} \ No newline at end of file diff --git a/www/addons/grades/lang/sr-lt.json b/www/addons/grades/lang/sr-lt.json new file mode 100644 index 00000000000..bc161c7fd6e --- /dev/null +++ b/www/addons/grades/lang/sr-lt.json @@ -0,0 +1,4 @@ +{ + "nogradesreturned": "Nema dobijenih ocena", + "viewgrades": "Prikaz ocena" +} \ No newline at end of file diff --git a/www/addons/grades/lang/uk.json b/www/addons/grades/lang/uk.json index 86c7bf00584..32dd4de48eb 100644 --- a/www/addons/grades/lang/uk.json +++ b/www/addons/grades/lang/uk.json @@ -1,4 +1,4 @@ { "nogradesreturned": "Немає оцінок", - "viewgrades": "Подивитися оцінки" + "viewgrades": "Перегляд оцінок" } \ No newline at end of file diff --git a/www/addons/grades/lang/zh-tw.json b/www/addons/grades/lang/zh-tw.json index 9a7313f470a..7dedc8d3d0c 100644 --- a/www/addons/grades/lang/zh-tw.json +++ b/www/addons/grades/lang/zh-tw.json @@ -1,4 +1,4 @@ { "nogradesreturned": "未找到成績", - "viewgrades": "檢視分數" + "viewgrades": "檢視成績" } \ No newline at end of file diff --git a/www/addons/messageoutput/airnotifier/lang/ja.json b/www/addons/messageoutput/airnotifier/lang/ja.json new file mode 100644 index 00000000000..3746717dab7 --- /dev/null +++ b/www/addons/messageoutput/airnotifier/lang/ja.json @@ -0,0 +1,3 @@ +{ + "processorsettingsdesc": "デバイスの設定" +} \ No newline at end of file diff --git a/www/addons/messageoutput/airnotifier/lang/sr-cr.json b/www/addons/messageoutput/airnotifier/lang/sr-cr.json new file mode 100644 index 00000000000..fda693e8ae3 --- /dev/null +++ b/www/addons/messageoutput/airnotifier/lang/sr-cr.json @@ -0,0 +1,3 @@ +{ + "processorsettingsdesc": "Конфигуриши уређаје" +} \ No newline at end of file diff --git a/www/addons/messageoutput/airnotifier/lang/sr-lt.json b/www/addons/messageoutput/airnotifier/lang/sr-lt.json new file mode 100644 index 00000000000..4419d93d89a --- /dev/null +++ b/www/addons/messageoutput/airnotifier/lang/sr-lt.json @@ -0,0 +1,3 @@ +{ + "processorsettingsdesc": "Komfiguriši uređaj" +} \ No newline at end of file diff --git a/www/addons/messages/lang/ar.json b/www/addons/messages/lang/ar.json index a047f3dfa6a..5d656811d75 100644 --- a/www/addons/messages/lang/ar.json +++ b/www/addons/messages/lang/ar.json @@ -10,10 +10,10 @@ "messages": "رسائل", "mustbeonlinetosendmessages": "لابد أن تكون متصل بالأنترنت لكي ترسل أي رسائل", "newmessage": "رسالة جديدة", - "nomessages": "لا توجد رسائل بعد", - "nousersfound": "لا يوجد مستخدمون", + "nomessages": "لا يوجد رسائل", + "nousersfound": "لا يوجد مستخدمين", "removecontact": "ازل عنوان الاتصال", - "send": "إرسل", + "send": "إرسال", "sendmessage": "إرسل رسالة", "type_offline": "غير متصل", "type_online": "متصل", diff --git a/www/addons/messages/lang/bg.json b/www/addons/messages/lang/bg.json index 857ae200454..1cf0cf2e3be 100644 --- a/www/addons/messages/lang/bg.json +++ b/www/addons/messages/lang/bg.json @@ -10,16 +10,16 @@ "errorwhileretrievingcontacts": "Грешка при изчитането на списъка с контакти от сървъра.", "errorwhileretrievingdiscussions": "Грешка при изчитането на дискусиите от сървъра.", "errorwhileretrievingmessages": "Грешка при изчитането на съобщенията от сървъра.", - "message": "Текст на съобщението", + "message": "Вашето мнение", "messagenotsent": "Съобщението не беше изпратено. Моля опитайте пак по-късно.", "messagepreferences": "Предпочитания за съобщенията", "messages": "Съобщения", "mustbeonlinetosendmessages": "Трябва да сте онлайн, за да изпращате съобщения.", "newmessage": "Ново съобщение ...", - "nomessages": "Няма съобщения.", + "nomessages": "Още няма съобщения", "nousersfound": "Не са намерени потребители", "removecontact": "Премахване на контакт", - "send": "изпращане", + "send": "Изпращане", "sendmessage": "Изпращане на съобщение", "type_blocked": "Блокиран", "type_offline": "Офлайн", diff --git a/www/addons/messages/lang/ca.json b/www/addons/messages/lang/ca.json index f4e5e0357b7..78d880054d7 100644 --- a/www/addons/messages/lang/ca.json +++ b/www/addons/messages/lang/ca.json @@ -13,17 +13,18 @@ "errorwhileretrievingdiscussions": "S'ha produït un error mentre es recuperaven els debats del servidor.", "errorwhileretrievingmessages": "S'ha produït un error descarregant els missatges.", "loadpreviousmessages": "Carrega els missatges anteriors", - "message": "Cos del missatge", + "message": "Missatge", "messagenotsent": "El missatge no s'ha enviat. Si us plau, intenteu-ho més tard", + "messagepreferences": "Preferències dels missatges", "messages": "Missatges", "mustbeonlinetosendmessages": "Heu de tenir connexió a la xarxa per a enviar missatges", - "newmessage": "Nou missatge...", + "newmessage": "Missatge nou", "newmessages": "Nous missatges", - "nomessages": "No hi ha missatges.", + "nomessages": "No hi ha missatges encara", "nousersfound": "No s'han trobat usuaris", "removecontact": "Suprimeix contacte", "removecontactconfirm": "El contacte s'eliminarà de la vostra llista de contactes.", - "send": "envia", + "send": "Envia", "sendmessage": "Envia missatge", "type_blocked": "Bloquejat", "type_offline": "Fora de línia", diff --git a/www/addons/messages/lang/cs.json b/www/addons/messages/lang/cs.json index fe2c22c0fc3..d3aa98a5834 100644 --- a/www/addons/messages/lang/cs.json +++ b/www/addons/messages/lang/cs.json @@ -24,8 +24,8 @@ "nousersfound": "Nebyl nalezen žádný uživatel", "removecontact": "Odebrat kontakt", "removecontactconfirm": "Kontakt bude odstraněn ze seznamu kontaktů.", - "send": "odeslat", - "sendmessage": "Odeslat zprávu", + "send": "Odeslat", + "sendmessage": "Poslat zprávu", "type_blocked": "Blokováno", "type_offline": "Offline", "type_online": "Online", diff --git a/www/addons/messages/lang/da.json b/www/addons/messages/lang/da.json index 160591f104a..c05ede1157e 100644 --- a/www/addons/messages/lang/da.json +++ b/www/addons/messages/lang/da.json @@ -11,16 +11,16 @@ "errorwhileretrievingcontacts": "Fejl ved hentning af kontakter fra serveren", "errorwhileretrievingdiscussions": "Fejl ved hentning af diskussioner fra serveren", "errorwhileretrievingmessages": "Fejl ved hentning af beskeder fra serveren.", - "message": "Beskedtekst", + "message": "Meddelelse", "messagenotsent": "Beskeden blev ikke sendt, prøv igen senere.", "messagepreferences": "Indstillinger for beskeder", "messages": "Beskeder", "mustbeonlinetosendmessages": "Du skal være online for at sende beskeder", - "newmessage": "Ny besked", - "nomessages": "Ingen beskeder endnu", + "newmessage": "Ny besked...", + "nomessages": "Ingen besked.", "nousersfound": "Ingen brugere fundet", "removecontact": "Fjern kontakt", - "send": "send", + "send": "Send", "sendmessage": "Send besked", "type_blocked": "Blokeret", "type_offline": "Offline", diff --git a/www/addons/messages/lang/de.json b/www/addons/messages/lang/de.json index 1f91de7f2a3..6a5fde2d14d 100644 --- a/www/addons/messages/lang/de.json +++ b/www/addons/messages/lang/de.json @@ -2,7 +2,7 @@ "addcontact": "Kontakt hinzufügen", "blockcontact": "Kontakt sperren", "blockcontactconfirm": "Sie beenden den Mitteilungsempfang von diesem Kontakt.", - "blocknoncontacts": "Weitere Personen sperren", + "blocknoncontacts": "Mitteilungen nur für Kontakte zulassen", "contactlistempty": "Die Kontaktliste ist leer.", "contactname": "Name", "contacts": "Kontakte", @@ -15,7 +15,7 @@ "loadpreviousmessages": "Vorherige Mitteilungen laden", "message": "Mitteilung", "messagenotsent": "Die Mitteilung wurde nicht gesendet. Versuchen Sie es später noch einmal.", - "messagepreferences": "Mitteilungen konfigurieren", + "messagepreferences": "Mitteilungen", "messages": "Mitteilungen", "mustbeonlinetosendmessages": "Sie müssen online sein, um Mitteilungen zu senden", "newmessage": "Neue Mitteilung ...", diff --git a/www/addons/messages/lang/el.json b/www/addons/messages/lang/el.json index 3476b0c695a..894c8fd4a8c 100644 --- a/www/addons/messages/lang/el.json +++ b/www/addons/messages/lang/el.json @@ -1,6 +1,7 @@ { "addcontact": "Προσθήκη επαφής", "blockcontact": "Φραγμός επαφής", + "blockcontactconfirm": "Θα σταματήσετε να λαμβάνετε μηνύματα από αυτήν την επαφή.", "blocknoncontacts": "Φραγή όλων των νέων μηνυμάτων που προέρχονται από χρήστες που δεν βρίσκονται στη λίστα επαφών σας.", "contactlistempty": "Η λίστα επαφών είναι κενή", "contactname": "Όνομα επαφής", @@ -9,15 +10,18 @@ "errorwhileretrievingcontacts": "Σφάλμα κατά την ανάκτηση των επαφών από το διακομιστή.", "errorwhileretrievingdiscussions": "Σφάλμα κατά την ανάκτηση των συζητήσεων από το διακομιστή.", "errorwhileretrievingmessages": "Σφάλμα κατά την ανάκτηση των μηνυμάτων από το διακομιστή.", - "message": "Σώμα μηνύματος", + "loadpreviousmessages": "Φορτώστε τα προηγούμενα μηνύματα", + "message": "Μήνυμα", "messagenotsent": "Το μήνυμα δεν στάλθηκε, δοκιμάστε ξανά αργότερα.", "messagepreferences": "Προτιμήσεις μηνύματος", "messages": "Μηνύματα", "mustbeonlinetosendmessages": "Πρέπει να είστε συνδεδεμένοι για να στείλετε μηνύματα", "newmessage": "Νέο μήνυμα...", + "newmessages": "Νέα μηνύματα", "nomessages": "Κανένα μήνυμα.", "nousersfound": "Δεν βρέθηκαν χρήστες", "removecontact": "Αφαίρεσε την επαφή", + "removecontactconfirm": "Η επαφή θα καταργηθεί από τη λίστα επαφών σας.", "send": "Αποστολή", "sendmessage": "Αποστολή μηνύματος", "type_blocked": "Μπλοκαρισμένοι", diff --git a/www/addons/messages/lang/es-mx.json b/www/addons/messages/lang/es-mx.json index b7a7a579a99..666045c556a 100644 --- a/www/addons/messages/lang/es-mx.json +++ b/www/addons/messages/lang/es-mx.json @@ -13,18 +13,18 @@ "errorwhileretrievingdiscussions": "Error al recuperar las discusiones del servidor.", "errorwhileretrievingmessages": "Error al recuperar los mensajes del servidor.", "loadpreviousmessages": "Cargar mensajes anteriores", - "message": "Cuerpo del mensaje", + "message": "Mensaje", "messagenotsent": "El mensaje no fue enviado; por favor inténtelo nuevamente después.", "messagepreferences": "Preferencias de Mensaje", "messages": "Mensajes", "mustbeonlinetosendmessages": "Usted debe de estar en-linea para enviar mensajes", - "newmessage": "Nuevo mensaje...", + "newmessage": "Nuevo mensaje", "newmessages": "Nuevos mensajes", - "nomessages": "Sin mensajes.", + "nomessages": "Aún no hay mensajes", "nousersfound": "No se encontraron usuarios", "removecontact": "Eliminar contacto", "removecontactconfirm": "El contacto será quitado de su lista de contactos.", - "send": "enviar", + "send": "Enviar", "sendmessage": "Enviar mensaje", "type_blocked": "Bloqueado", "type_offline": "Fuera-de-línea", diff --git a/www/addons/messages/lang/es.json b/www/addons/messages/lang/es.json index 9f18c4105e8..129117cec61 100644 --- a/www/addons/messages/lang/es.json +++ b/www/addons/messages/lang/es.json @@ -1,6 +1,7 @@ { "addcontact": "Añadir contacto", "blockcontact": "Bloquear contacto", + "blockcontactconfirm": "Usted dejará de recibir mensajes de este contacto.", "blocknoncontacts": "Bloquear mensajes de usuarios que no figuren en mi lista de contactos", "contactlistempty": "Lista de contactos vacía", "contactname": "Nombre del contacto", @@ -11,16 +12,19 @@ "errorwhileretrievingcontacts": "Error al recuperar los contactos del servidor.", "errorwhileretrievingdiscussions": "Error al recuperar las discusiones del servidor.", "errorwhileretrievingmessages": "Error al recuperar los mensajes del servidor.", - "message": "Cuerpo del mensaje", + "loadpreviousmessages": "Cargar mensajes anteriores", + "message": "Mensaje", "messagenotsent": "El mensaje no fue enviado; por favor inténtelo nuevamente después.", "messagepreferences": "Preferencias de mensajes", "messages": "Mensajes", "mustbeonlinetosendmessages": "Debe conectarse para enviar mensajes", "newmessage": "Nuevo mensaje...", + "newmessages": "Nuevos mensajes", "nomessages": "No hay mensajes en espera", "nousersfound": "No se encuentran usuarios", "removecontact": "Eliminar contacto", - "send": "enviar", + "removecontactconfirm": "El contacto se eliminará de su lista de contactos.", + "send": "Enviar", "sendmessage": "Enviar mensaje", "type_blocked": "Bloqueado", "type_offline": "Desconectado", diff --git a/www/addons/messages/lang/es_mx.json b/www/addons/messages/lang/es_mx.json deleted file mode 100644 index 8de8efc8eff..00000000000 --- a/www/addons/messages/lang/es_mx.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "addcontact": "Añadir como contacto", - "blockcontact": "Bloquear contacto", - "contactlistempty": "La lista de contactos está vacía", - "contactname": "Nombre del contacto", - "contacts": "Contactos", - "messages": "mi Messenger", - "nomessages": "No hay mensajes en espera", - "removecontact": "Eliminar contacto", - "send": "Enviar", - "sendmessage": "Enviar un mensaje", - "unblockcontact": "Desbloquear contacto" -} \ No newline at end of file diff --git a/www/addons/messages/lang/eu.json b/www/addons/messages/lang/eu.json index ed18c8f0e65..7b4d166b262 100644 --- a/www/addons/messages/lang/eu.json +++ b/www/addons/messages/lang/eu.json @@ -13,7 +13,7 @@ "errorwhileretrievingdiscussions": "Errorea elkarrizketak zerbitzaritik jasotzean.", "errorwhileretrievingmessages": "Errorea mezuak zerbitzaritik jasotzean.", "loadpreviousmessages": "Kargatu aurreko mezuak", - "message": "Mezuren gurputza", + "message": "Mezua", "messagenotsent": "Mezua ez da bidali, mesedez saiatu beranduago.", "messagepreferences": "Mezuen hobespenak", "messages": "Mezuak", @@ -24,7 +24,7 @@ "nousersfound": "Ez da erabiltzailerik aurkitu", "removecontact": "Ezabatu kontaktua", "removecontactconfirm": "Kontaktua zure kontaktuen zerrendatik ezabatuko da.", - "send": "bidali", + "send": "Bidali", "sendmessage": "Mezua bidali", "type_blocked": "Blokeatuta", "type_offline": "Lineaz kanpo", diff --git a/www/addons/messages/lang/fa.json b/www/addons/messages/lang/fa.json index a6d80f69982..f5155644c97 100644 --- a/www/addons/messages/lang/fa.json +++ b/www/addons/messages/lang/fa.json @@ -6,14 +6,14 @@ "contactname": "نام مخاطب", "contacts": "مخاطبین", "errorwhileretrievingdiscussions": "خطا در دریافت مباحثه‌ها از کارگزار.", - "message": "متن پیام", + "message": "متن", "messagepreferences": "ترجیحات پیام‌دهی", "messages": "پیام‌ها", "newmessage": "پیام جدید", - "nomessages": "هنوز پیامی گفته نشده است", + "nomessages": "هیچ پیغامی منتظر جواب نیست", "nousersfound": "کاربری پیدا نشد", "removecontact": "حذف کردن مخاطب", - "send": "فرستادن", + "send": "ارسال", "sendmessage": "ارسال پیام", "unblockcontact": "خارج کردن مخاطب از حالت مسدود" } \ No newline at end of file diff --git a/www/addons/messages/lang/fr.json b/www/addons/messages/lang/fr.json index 159b6fe52a9..90f17d9f58f 100644 --- a/www/addons/messages/lang/fr.json +++ b/www/addons/messages/lang/fr.json @@ -13,10 +13,10 @@ "errorwhileretrievingdiscussions": "Erreur lors de la récupération des discussions depuis le serveur.", "errorwhileretrievingmessages": "Erreur lors de la récupération des messages depuis le serveur.", "loadpreviousmessages": "Charger les messages antérieurs", - "message": "Corps du message", + "message": "Message", "messagenotsent": "Ce message n'a pas été envoyé. Veuillez essayer plus tard.", "messagepreferences": "Préférences des messages", - "messages": "Messages", + "messages": "Messages personnels", "mustbeonlinetosendmessages": "Vous devez être en ligne pour envoyer des messages", "newmessage": "Nouveau message...", "newmessages": "Nouveaux messages", @@ -25,7 +25,7 @@ "removecontact": "Supprimer ce contact", "removecontactconfirm": "Le contact sera retiré de votre liste.", "send": "Envoyer", - "sendmessage": "Envoyer message", + "sendmessage": "Envoyer message personnel", "type_blocked": "Bloqué", "type_offline": "Hors ligne", "type_online": "En ligne", diff --git a/www/addons/messages/lang/he.json b/www/addons/messages/lang/he.json index fb473cf8205..b0db251c2c8 100644 --- a/www/addons/messages/lang/he.json +++ b/www/addons/messages/lang/he.json @@ -10,17 +10,17 @@ "errorwhileretrievingcontacts": "שגיאה בזמן טעינת אנשי קשר מהשרת.", "errorwhileretrievingdiscussions": "שגיאה בזמן טעינת הדיונים מהשרת.", "errorwhileretrievingmessages": "שגיאה בזמן טעינת המסרים מהשרת.", - "message": "גוף ההודעה", + "message": "הודעה", "messagenotsent": "מסר זה לא נשלח, אנא נסה שוב מאוחר יותר.", "messagepreferences": "העדפות מסרים", - "messages": "הודעות", + "messages": "מסרים", "mustbeonlinetosendmessages": "עליך להיות מחובר/ת בכדי לשלוח מסר.", - "newmessage": "הודעה חדשה", - "nomessages": "אין הודעות עדיין", - "nousersfound": "לתשומת-לב", + "newmessage": "מסר חדש...", + "nomessages": "אין מסרים.", + "nousersfound": "לא נמצאו משתמשים", "removecontact": "הסרת איש הקשר", - "send": "שליחה", - "sendmessage": "שליחת הודעה", + "send": "לשלוח", + "sendmessage": "שליחת מסר", "type_blocked": "חסומים", "type_offline": "לא מחוברים", "type_online": "מחוברים", diff --git a/www/addons/messages/lang/hu.json b/www/addons/messages/lang/hu.json index 324fe26fe60..af6e18a3d8a 100644 --- a/www/addons/messages/lang/hu.json +++ b/www/addons/messages/lang/hu.json @@ -7,14 +7,14 @@ "contacts": "Kapcsolatok", "deletemessage": "Üzenet törlése", "deletemessageconfirmation": "Biztosan törli az üzenetet? Az csak a korábbi üzeneteiből törlődik, az azt küldő vagy fogadó fél továbbra is láthatja.", - "message": "Üzenet törzsszövege", + "message": "Üzenet", "messagepreferences": "Üzenet beállításai", "messages": "Üzenetek", "newmessage": "Új üzenet", - "nomessages": "Még nincs üzenet", + "nomessages": "Nincs üzenet.", "nousersfound": "Nincs felhasználó", "removecontact": "Kapcsolat törlése", - "send": "Elküld", + "send": "küldés", "sendmessage": "Üzenet küldése", "unblockcontact": "Kapcsolat zárolásának feloldása" } \ No newline at end of file diff --git a/www/addons/messages/lang/it.json b/www/addons/messages/lang/it.json index 0762bb1d877..9052dd21da0 100644 --- a/www/addons/messages/lang/it.json +++ b/www/addons/messages/lang/it.json @@ -11,7 +11,7 @@ "errorwhileretrievingcontacts": "Si è verificato un errore durante la ricezione dei contatti dal server.", "errorwhileretrievingdiscussions": "Si è verificato un errore durante la ricezione delle discussioni dal server.", "errorwhileretrievingmessages": "Si è verificato un errore durante la ricezione dei messaggi dal server.", - "message": "Corpo del messaggio", + "message": "Messaggio", "messagenotsent": "Il messaggio non è stato inviato, per favore riprova più tardi.", "messagepreferences": "Preferenze messaggi", "messages": "Messaggi", @@ -20,7 +20,7 @@ "nomessages": "Non ci sono messaggi.", "nousersfound": "Non sono stati trovati utenti", "removecontact": "Cancella contatti", - "send": "invia", + "send": "Invia", "sendmessage": "Invia messaggio", "type_blocked": "Bloccato", "type_offline": "Offline", diff --git a/www/addons/messages/lang/ja.json b/www/addons/messages/lang/ja.json index fdd373a6acd..ab1c8913529 100644 --- a/www/addons/messages/lang/ja.json +++ b/www/addons/messages/lang/ja.json @@ -1,20 +1,36 @@ { "addcontact": "コンタクトに追加する", "blockcontact": "受信拒否", + "blockcontactconfirm": "この連絡先からのメッセージ受信を停止します。", "blocknoncontacts": "不明なユーザをブロックする", - "contactlistempty": "コンタクトリストは空です。", - "contactname": "連絡先", + "contactlistempty": "連絡先リストが空", + "contactname": "連絡先名称", "contacts": "コンタクト", "deletemessage": "メッセージを削除する", "deletemessageconfirmation": "本当にこのメッセージを削除してもよろしいですか? あなたのメッセージング履歴からのみ削除され、メッセージを送受信したユーザはまだ閲覧することができます。", - "message": "メッセージ本文", + "errordeletemessage": "メッセージ消去中にエラーが発生しました。", + "errorwhileretrievingcontacts": "サーバから連絡先を取得中にエラーが発生しました。", + "errorwhileretrievingdiscussions": "サーバからディスカッションを受信中にエラーが発生しました。", + "errorwhileretrievingmessages": "サーバからメッセージを受信中にエラーが発生しました。", + "loadpreviousmessages": "以前のメッセージを読み込み", + "message": "メッセージ", + "messagenotsent": "メッセージは送信されませんでした。後で再び試みてください。", "messagepreferences": "メッセージプリファレンス", "messages": "メッセージ", - "newmessage": "新しいメッセージ", + "mustbeonlinetosendmessages": "メッセージを送信するにはオンラインでなければなりません。", + "newmessage": "新規メッセージ...", + "newmessages": "新規メッセージ...", "nomessages": "メッセージがありません。", - "nousersfound": "ユーザは見つかりませんでした。", + "nousersfound": "ユーザが見つかりません", "removecontact": "コンタクトから削除する", + "removecontactconfirm": "連絡先はあなたの連絡先リストから削除されます。", "send": "送信", "sendmessage": "メッセージを送信する", - "unblockcontact": "コンタクトの拒否を解除する" + "type_blocked": "ブロックされています", + "type_offline": "オフライン", + "type_online": "オンライン", + "type_search": "結果の検索", + "type_strangers": "その他", + "unblockcontact": "コンタクトの拒否を解除する", + "warningmessagenotsent": "ユーザ {{user}} へのメッセージ送信ができませんでした。 {{error}}" } \ No newline at end of file diff --git a/www/addons/messages/lang/lt.json b/www/addons/messages/lang/lt.json index f63f91053b9..99ebd5052e4 100644 --- a/www/addons/messages/lang/lt.json +++ b/www/addons/messages/lang/lt.json @@ -9,16 +9,16 @@ "errorwhileretrievingcontacts": "Klaida nuskaitant kontaktus iš serverio.", "errorwhileretrievingdiscussions": "Klaida nuskaitant diskusijas iš serverio.", "errorwhileretrievingmessages": "Klaida nuskaitant pranešimus iš serverio.", - "message": "Pranešimo tekstas", + "message": "Žinutės tekstas", "messagenotsent": "Žinutė nebuvo išsiųsta, pabandykite vėliau.", "messagepreferences": "Žinučių nuostatos", "messages": "Žinutės", "mustbeonlinetosendmessages": "Norėdamas išsiųsti žinutę, turite prisijungti", - "newmessage": "Nauja žinutė...", - "nomessages": "Žinučių nėra.", + "newmessage": "Nauja žinutė", + "nomessages": "Žinučių dar nėra", "nousersfound": "Vartotojas nerastas", "removecontact": "Pašalinti kontaktą", - "send": "siųsti", + "send": "Siųsti", "sendmessage": "Siųsti žinutę", "type_blocked": "Užblokuota", "type_offline": "Neprisjungęs", diff --git a/www/addons/messages/lang/nl.json b/www/addons/messages/lang/nl.json index c0cb0d61bb3..c8e2675c258 100644 --- a/www/addons/messages/lang/nl.json +++ b/www/addons/messages/lang/nl.json @@ -13,7 +13,7 @@ "errorwhileretrievingdiscussions": "Fout bij het ophalen van discussies van de server.", "errorwhileretrievingmessages": "Fout bij het ophalen van berichten van de server.", "loadpreviousmessages": "Laad vorige berichten", - "message": "Berichtinhoud", + "message": "Bericht", "messagenotsent": "Het bericht is niet verzonden. Probeer het later opnieuw.", "messagepreferences": "Berichten voorkeuren", "messages": "Berichten", @@ -24,7 +24,7 @@ "nousersfound": "Geen gebruikers gevonden", "removecontact": "Verwijder contactpersoon", "removecontactconfirm": "Contact zal verwijderd worden van je contactenlijst.", - "send": "Stuur", + "send": "stuur", "sendmessage": "Stuur bericht", "type_blocked": "Geblokkeerd", "type_offline": "Offline", diff --git a/www/addons/messages/lang/pl.json b/www/addons/messages/lang/pl.json index a0b20dc95eb..6cb4279d4f9 100644 --- a/www/addons/messages/lang/pl.json +++ b/www/addons/messages/lang/pl.json @@ -7,14 +7,14 @@ "contacts": "Kontakty", "deletemessage": "Usuń wiadomość", "deletemessageconfirmation": "Czy jesteś pewien, że chcesz usunąć tę wiadomość? Zostanie ona usunięta wyłącznie z twojej historii wiadomości, użytkownik który ją wysłał lub odebrał nadal będzie mógł ją wyświetlić.", - "message": "Treść wiadomości", + "message": "Wiadomość", "messagepreferences": "Preferencje wiadomości", "messages": "Wiadomości", "newmessage": "Nowa wiadomość", - "nomessages": "Brak wiadomości", + "nomessages": "Brak oczekujących wiadomości", "nousersfound": "Nie znaleziono użytkowników", "removecontact": "Usuń kontakt", - "send": "wyślij", + "send": "Wyślij", "sendmessage": "Wyślij wiadomość", "unblockcontact": "Odblokuj kontakt" } \ No newline at end of file diff --git a/www/addons/messages/lang/pt-br.json b/www/addons/messages/lang/pt-br.json index b7c9da7e6a9..54c1e1b6e2c 100644 --- a/www/addons/messages/lang/pt-br.json +++ b/www/addons/messages/lang/pt-br.json @@ -13,17 +13,18 @@ "errorwhileretrievingdiscussions": "Erro ao recuperar discussão do servidor.", "errorwhileretrievingmessages": "Erro ao recuperar as mensagens do servidor.", "loadpreviousmessages": "Carregar mensagens anteriores", - "message": "Corpo da mensagem", + "message": "Mensagem", "messagenotsent": "A mensagem não foi enviada. Por favor tente novamente mais tarde.", + "messagepreferences": "Preferências de mensagens", "messages": "Mensagens", "mustbeonlinetosendmessages": "Você precisa estar conectado para enviar mensagens.", - "newmessage": "Nova mensagem...", + "newmessage": "Nova Mensagem", "newmessages": "Novas mensagens", - "nomessages": "Não há mensagens.", + "nomessages": "Nenhuma mensagem ainda", "nousersfound": "Nenhum usuário encontrado", "removecontact": "Eliminar contato", "removecontactconfirm": "O contato será removido da sua lista de contatos.", - "send": "enviar", + "send": "Enviar", "sendmessage": "Enviar mensagem", "type_blocked": "Bloqueado", "type_offline": "Offline", diff --git a/www/addons/messages/lang/pt.json b/www/addons/messages/lang/pt.json index b9ae68508bd..0e8975e0f49 100644 --- a/www/addons/messages/lang/pt.json +++ b/www/addons/messages/lang/pt.json @@ -13,14 +13,14 @@ "errorwhileretrievingdiscussions": "Erro ao obter os tópicos de discussão do servidor.", "errorwhileretrievingmessages": "Erro ao obter as mensagens do servidor.", "loadpreviousmessages": "Carregar mensagens antigas", - "message": "Corpo da mensagem", + "message": "Mensagem", "messagenotsent": "A mensagem não foi enviada. Por favor, tente novamente mais tarde.", "messagepreferences": "Preferências das mensagens", "messages": "Mensagens", "mustbeonlinetosendmessages": "Precisa de estar online para enviar mensagens", - "newmessage": "Nova mensagem...", + "newmessage": "Nova mensagem", "newmessages": "Novas mensagens", - "nomessages": "Sem mensagens.", + "nomessages": "Ainda não há mensagens", "nousersfound": "Nenhum utilizador encontrado", "removecontact": "Remover contacto", "removecontactconfirm": "O contacto será removido da sua lista de contactos.", diff --git a/www/addons/messages/lang/pt_br.json b/www/addons/messages/lang/pt_br.json deleted file mode 100644 index fb4e3394639..00000000000 --- a/www/addons/messages/lang/pt_br.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "addcontact": "Adicionar como contato", - "blockcontact": "Bloquear contato", - "contactlistempty": "Lista de contatos vazia", - "contactname": "Nome para contato", - "contacts": "Contatos", - "messages": "Mensagens", - "nomessages": "Não há mensagens pendentes", - "removecontact": "Remover contato", - "send": "Enviar", - "sendmessage": "Envie uma mensagem", - "unblockcontact": "Desbloquear contato" -} \ No newline at end of file diff --git a/www/addons/messages/lang/ro.json b/www/addons/messages/lang/ro.json index b519bbf378f..1ee83c12782 100644 --- a/www/addons/messages/lang/ro.json +++ b/www/addons/messages/lang/ro.json @@ -11,15 +11,15 @@ "errorwhileretrievingcontacts": "A apărut o eroare în găsirea contactelor pe server.", "errorwhileretrievingdiscussions": "A apărut o eroare în găsirea conversațiilor de pe server.", "errorwhileretrievingmessages": "A apărut o eroare în găsirea mesajelor de pe server.", - "message": "Conținut mesaj", + "message": "Mesaj", "messagenotsent": "Mesajul nu a fost expediat, vă rugăm să încercați mai târziu.", "messages": "Mesaje", "mustbeonlinetosendmessages": "Trebuie să fiți online pentru a putea trimite mesaje", "newmessage": "Mesaj nou!", - "nomessages": "Nu aveți mesaje.", - "nousersfound": "Nu au fost găsiți utilizatori", + "nomessages": "Nu a fost trimis încă niciun mesaj", + "nousersfound": "Nu s-au găsit utilizatori", "removecontact": "Şterge prieten din listă", - "send": "Trimis", + "send": "trimis", "sendmessage": "Trimite mesaj", "type_blocked": "Blocat", "type_offline": "Deconectat", diff --git a/www/addons/messages/lang/ru.json b/www/addons/messages/lang/ru.json index be656eda0df..4c6677f9138 100644 --- a/www/addons/messages/lang/ru.json +++ b/www/addons/messages/lang/ru.json @@ -11,7 +11,7 @@ "errorwhileretrievingdiscussions": "Ошибка при получении обсуждения с сервера.", "errorwhileretrievingmessages": "Ошибка при получении сообщения с сервера", "loadpreviousmessages": "Загрузить предыдущее сообщение", - "message": "Текст сообщения", + "message": "Сообщение", "messagenotsent": "Сообщение не было отправлено. Повторите попытку позже.", "messagepreferences": "Настройки сообщений", "messages": "Сообщения", diff --git a/www/addons/messages/lang/sr-cr.json b/www/addons/messages/lang/sr-cr.json new file mode 100644 index 00000000000..18a467fa43c --- /dev/null +++ b/www/addons/messages/lang/sr-cr.json @@ -0,0 +1,34 @@ +{ + "addcontact": "Додај контакт", + "blockcontact": "Блокирај контакт", + "blockcontactconfirm": "Нећете више добијати поруке од ове особе.", + "blocknoncontacts": "Блокирај све нове поруке од корисника који нису на мојој листи контаката", + "contactlistempty": "Листа контаката је празна", + "contactname": "Име особе", + "contacts": "Контакти", + "errordeletemessage": "Грешка приликом брисања поруке.", + "errorwhileretrievingcontacts": "Грешка приликом преузимања контаката са сервера.", + "errorwhileretrievingdiscussions": "Грешка приликом преузимања дискусија са сервера.", + "errorwhileretrievingmessages": "Грешка приликом преузимања порука са сервера.", + "loadpreviousmessages": "Учитај претходне поруке", + "message": "Тело поруке", + "messagenotsent": "Порука није послата. Молимо, покушајте поново касније.", + "messagepreferences": "Параметри порука", + "messages": "Поруке", + "mustbeonlinetosendmessages": "Морате бити онлајн како бисте слали поруке", + "newmessage": "Нове поруке...", + "newmessages": "Нове поруке", + "nomessages": "Нема порука.", + "nousersfound": "Није пронађен ниједан корисник", + "removecontact": "Обриши контакт", + "removecontactconfirm": "Особа ће бити уклоњена са ваше листе контаката.", + "send": "Пошаљи", + "sendmessage": "Пошаљи поруку", + "type_blocked": "Блокиран", + "type_offline": "Офлајн", + "type_online": "Онлајн", + "type_search": "Резултати претраге", + "type_strangers": "Други", + "unblockcontact": "Одблокирај контакт", + "warningmessagenotsent": "Није могуће послати поруку/е кориснику {{user}}. {{error}}" +} \ No newline at end of file diff --git a/www/addons/messages/lang/sr-lt.json b/www/addons/messages/lang/sr-lt.json new file mode 100644 index 00000000000..3d5a353c5f5 --- /dev/null +++ b/www/addons/messages/lang/sr-lt.json @@ -0,0 +1,34 @@ +{ + "addcontact": "Dodaj kontakt", + "blockcontact": "Blokiraj kontakt", + "blockcontactconfirm": "Nećete više dobijati poruke od ove osobe.", + "blocknoncontacts": "Blokiraj sve nove poruke od korisnika koji nisu na mojoj listi kontakata", + "contactlistempty": "Lista kontakata je prazna", + "contactname": "Ime osobe", + "contacts": "Kontakti", + "errordeletemessage": "Greška prilikom brisanja poruke.", + "errorwhileretrievingcontacts": "Greška prilikom preuzimanja kontakata sa servera.", + "errorwhileretrievingdiscussions": "Greška prilikom preuzimanja diskusija sa servera.", + "errorwhileretrievingmessages": "Greška prilikom preuzimanja poruka sa servera.", + "loadpreviousmessages": "Učitaj prethodne poruke", + "message": "Telo poruke", + "messagenotsent": "Poruka nije poslata. Molimo, pokušajte ponovo kasnije.", + "messagepreferences": "Parametri poruka", + "messages": "Poruke", + "mustbeonlinetosendmessages": "Morate biti onlajn kako biste slali poruke", + "newmessage": "Nove poruke...", + "newmessages": "Nove poruke", + "nomessages": "Nema poruka.", + "nousersfound": "Nije pronađen nijedan korisnik", + "removecontact": "Obriši kontakt", + "removecontactconfirm": "Osoba će biti uklonjena sa vaše liste kontakata.", + "send": "Pošalji", + "sendmessage": "Pošalji poruku", + "type_blocked": "Blokiran", + "type_offline": "Oflajn", + "type_online": "Onlajn", + "type_search": "Rezultati pretrage", + "type_strangers": "Drugi", + "unblockcontact": "Odblokiraj kontakt", + "warningmessagenotsent": "Nije moguće poslati poruku/e korisniku {{user}}. {{error}}" +} \ No newline at end of file diff --git a/www/addons/messages/lang/sv.json b/www/addons/messages/lang/sv.json index 301b34c89a3..d17bc0228ef 100644 --- a/www/addons/messages/lang/sv.json +++ b/www/addons/messages/lang/sv.json @@ -11,15 +11,16 @@ "errorwhileretrievingcontacts": "Fel vid hämtning av kontakter från servern.", "errorwhileretrievingdiscussions": "Fel vid hämtning av diskussionerna från servern.", "errorwhileretrievingmessages": "Fel vid hämtning meddelanden från servern.", - "message": "Meddelandets brödtext", + "message": "Meddelande", "messagenotsent": "Meddelandet skickades inte, försök igen senare.", + "messagepreferences": "Välj inställningar för meddelanden", "messages": "Meddelanden", "mustbeonlinetosendmessages": "Du måste vara online för att skicka meddelanden", "newmessage": "Ny meddelande...", "nomessages": "Inga meddelanden", "nousersfound": "Inga användare hittades", "removecontact": "Ta bort kontakt", - "send": "skicka", + "send": "Skicka", "sendmessage": "Skicka meddelande", "type_blocked": "blockerad", "type_offline": "Offline", diff --git a/www/addons/messages/lang/tr.json b/www/addons/messages/lang/tr.json index 72ef991ede5..38d1a3b1e77 100644 --- a/www/addons/messages/lang/tr.json +++ b/www/addons/messages/lang/tr.json @@ -5,11 +5,11 @@ "contactlistempty": "Kişi listeniz şu anda boş", "contactname": "Adı", "contacts": "Kişiler", - "message": "Mesaj gövdesi", + "message": "Mesaj", "messagepreferences": "İleti tercihleri", "messages": "Mesajlar", "newmessage": "Yeni ileti", - "nomessages": "İleti yok.", + "nomessages": "Henüz mesaj yok", "nousersfound": "Kullanıcı bulunamadı", "removecontact": "Kişiyi sil", "send": "Gönder", diff --git a/www/addons/messages/lang/uk.json b/www/addons/messages/lang/uk.json index 21fa4dc7976..10cf5c336d1 100644 --- a/www/addons/messages/lang/uk.json +++ b/www/addons/messages/lang/uk.json @@ -11,7 +11,7 @@ "errorwhileretrievingdiscussions": "Помилка при отриманні обговорення з сервера.", "errorwhileretrievingmessages": "Помилка при отриманні повідомлень від сервера.", "loadpreviousmessages": "Завантаження попередніх повідомлень", - "message": "Текст повідомлення", + "message": "Повідомлення", "messagenotsent": "Повідомлення не було відправлено, будь ласка, спробуйте ще раз пізніше.", "messages": "Повідомлення", "mustbeonlinetosendmessages": "Ви повинні бути онлайн, щоб відправляти повідомлення", @@ -21,7 +21,7 @@ "nousersfound": "Користувачів не знайдено", "removecontact": "Видалити контакт", "removecontactconfirm": "Контакт буде видалено зі списку контактів.", - "send": "Відіслати", + "send": "надіслати", "sendmessage": "Надіслати повідомлення", "type_blocked": "Заблоковано", "type_offline": "Офлайн", @@ -29,5 +29,5 @@ "type_search": "Результати пошуку", "type_strangers": "Інші", "unblockcontact": "Розблокувати контакт", - "warningmessagenotsent": "Неможливо відправити повідомлення до {{user}}. {{error}}" + "warningmessagenotsent": "Неможливо відправити повідомлення до {{user}}. {{error}}" } \ No newline at end of file diff --git a/www/addons/messages/lang/zh-cn.json b/www/addons/messages/lang/zh-cn.json index 38ed871a73d..fa7d759934b 100644 --- a/www/addons/messages/lang/zh-cn.json +++ b/www/addons/messages/lang/zh-cn.json @@ -6,12 +6,12 @@ "contactname": "联系人", "contacts": "联系人", "deletemessage": "删除消息", - "message": "内容", + "message": "正文", "messages": "消息", - "nomessages": "无消息", + "nomessages": "没有新消息", "nousersfound": "未找到用户", "removecontact": "删除联系人", "send": "发送", - "sendmessage": "发消息", + "sendmessage": "发送消息", "unblockcontact": "不再阻拦联系人" } \ No newline at end of file diff --git a/www/addons/messages/lang/zh-tw.json b/www/addons/messages/lang/zh-tw.json index 34693107bc7..60b1bfa8db2 100644 --- a/www/addons/messages/lang/zh-tw.json +++ b/www/addons/messages/lang/zh-tw.json @@ -11,17 +11,17 @@ "errorwhileretrievingcontacts": "從伺服器存取聯絡人時出錯", "errorwhileretrievingdiscussions": "從伺服器存取討論區時出錯", "errorwhileretrievingmessages": "從伺服器存取訊息時出錯", - "message": "訊息主文", + "message": "訊息", "messagenotsent": "訊息未發送, 請稍後再試.", "messagepreferences": "簡訊偏好", - "messages": "訊息", + "messages": "簡訊", "mustbeonlinetosendmessages": "您必須上線才能發送訊息", - "newmessage": "新訊息...", - "nomessages": "沒有任何訊息.", + "newmessage": "新簡訊", + "nomessages": "尚無訊息", "nousersfound": "沒有使用者", "removecontact": "刪除聯絡人", - "send": "傳送", - "sendmessage": "寄送訊息", + "send": "送出", + "sendmessage": "傳送簡訊", "type_blocked": "已停止", "type_offline": "離線", "type_online": "上線", diff --git a/www/addons/messages/lang/zh_cn.json b/www/addons/messages/lang/zh_cn.json deleted file mode 100644 index 708e5a301b9..00000000000 --- a/www/addons/messages/lang/zh_cn.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "addcontact": "添加为联系人", - "blockcontact": "屏蔽联系人", - "contactlistempty": "您的联系人名单是空的", - "contactname": "联系人", - "contacts": "联系人", - "messages": "消息", - "nomessages": "没有新消息", - "removecontact": "删除联系人", - "send": "发送", - "sendmessage": "发送消息", - "unblockcontact": "不再阻拦联系人" -} \ No newline at end of file diff --git a/www/addons/messages/lang/zh_tw.json b/www/addons/messages/lang/zh_tw.json deleted file mode 100644 index b86c20e0f95..00000000000 --- a/www/addons/messages/lang/zh_tw.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "addcontact": "加入通訊錄", - "blockcontact": "封鎖聯絡人", - "contactlistempty": "您的通訊錄是空的", - "contactname": "聯絡人姓名", - "contacts": "通訊錄", - "messages": "我的簡訊", - "nomessages": "沒有待處理的簡訊", - "removecontact": "刪除聯絡人", - "send": "傳送", - "sendmessage": "傳送訊息", - "unblockcontact": "不再封鎖聯絡" -} \ No newline at end of file diff --git a/www/addons/messages/main.js b/www/addons/messages/main.js index 740671284eb..2e7697e54a4 100644 --- a/www/addons/messages/main.js +++ b/www/addons/messages/main.js @@ -29,6 +29,7 @@ angular.module('mm.addons.messages', ['mm.core']) .constant('mmaMessagesReadCronEvent', 'mma-messages_read_cron') .constant('mmaMessagesAutomSyncedEvent', 'mma_messages_autom_synced') .constant('mmaMessagesLimitSearchMessages', 50) +.constant('mmaMessagesPushSimulationComponent', 'mmaMessagesPushSimulation') .config(function($stateProvider, $mmUserDelegateProvider, $mmSideMenuDelegateProvider, mmaMessagesSendMessagePriority, mmaMessagesAddContactPriority, mmaMessagesBlockContactPriority, mmaMessagesPriority, $mmContentLinksDelegateProvider, @@ -87,7 +88,7 @@ angular.module('mm.addons.messages', ['mm.core']) }) .run(function($mmaMessages, $mmEvents, $state, $mmAddonManager, $mmUtil, mmCoreEventLogin, $mmCronDelegate, $mmaMessagesSync, - mmCoreEventOnlineStatusChanged, $mmSitesManager) { + mmCoreEventOnlineStatusChanged, $mmSitesManager, $mmLocalNotifications, $mmApp, mmaMessagesPushSimulationComponent) { // Invalidate messaging enabled WS calls. $mmEvents.on(mmCoreEventLogin, function() { @@ -99,18 +100,7 @@ angular.module('mm.addons.messages', ['mm.core']) if ($mmPushNotificationsDelegate) { $mmPushNotificationsDelegate.registerHandler('mmaMessages', function(notification) { if ($mmUtil.isFalseOrZero(notification.notif)) { - $mmaMessages.isMessagingEnabledForSite(notification.site).then(function() { - $mmSitesManager.isFeatureDisabled('$mmSideMenuDelegate_mmaMessages', notification.site).then(function(disabled) { - if (disabled) { - // Messages are disabled, stop. - return; - } - - $mmaMessages.invalidateDiscussionsCache().finally(function() { - $state.go('redirect', {siteid: notification.site, state: 'site.messages'}); - }); - }); - }); + notificationClicked(notification); return true; } }); @@ -126,4 +116,24 @@ angular.module('mm.addons.messages', ['mm.core']) $mmaMessagesSync.syncAllDiscussions(undefined, true); } }); + + if ($mmApp.isDesktop()) { + // Listen for clicks in simulated push notifications. + $mmLocalNotifications.registerClick(mmaMessagesPushSimulationComponent, notificationClicked); + } + + function notificationClicked(notification) { + $mmaMessages.isMessagingEnabledForSite(notification.site).then(function() { + $mmSitesManager.isFeatureDisabled('$mmSideMenuDelegate_mmaMessages', notification.site).then(function(disabled) { + if (disabled) { + // Messages are disabled, stop. + return; + } + + $mmaMessages.invalidateDiscussionsCache().finally(function() { + $state.go('redirect', {siteid: notification.site, state: 'site.messages'}); + }); + }); + }); + } }); diff --git a/www/addons/messages/services/handlers.js b/www/addons/messages/services/handlers.js index 412b112500f..3ce6f4c4c3e 100644 --- a/www/addons/messages/services/handlers.js +++ b/www/addons/messages/services/handlers.js @@ -25,11 +25,43 @@ angular.module('mm.addons.messages') */ .factory('$mmaMessagesHandlers', function($log, $mmaMessages, $mmSite, $state, $mmUtil, $mmContentLinksHelper, $mmaMessagesSync, $mmSitesManager, mmUserProfileHandlersTypeCommunication, mmUserProfileHandlersTypeAction, $translate, - mmaMessagesReadChangedEvent, $mmEvents, mmaMessagesReadCronEvent, $mmAddonManager, $mmContentLinkHandlerFactory) { + mmaMessagesReadChangedEvent, $mmEvents, mmaMessagesReadCronEvent, $mmAddonManager, $mmContentLinkHandlerFactory, + $mmText, $mmApp, $mmLocalNotifications, $mmEmulatorHelper, mmaMessagesPushSimulationComponent) { $log = $log.getInstance('$mmaMessagesHandlers'); var self = {}; + /** + * Get the latest unread received messages from a site. + * + * @param {String} siteId Site ID. + * @return {Promise} Promise resolved with the notifications. + */ + function fetchMessages(siteId) { + return $mmaMessages.getUnreadReceivedMessages(true, false, true, siteId).then(function(response) { + return response.messages; + }); + } + + /** + * Given a message, return the title and the text for the message. + * + * @param {Object} message Message. + * @return {Promise} Promise resolved with an object with title and text. + */ + function getTitleAndText(message) { + var data = { + title: message.userfromfullname, + }; + + return $mmText.formatText(message.text, true, true).catch(function() { + return message.text; + }).then(function(formattedText) { + data.text = formattedText; + return data; + }); + } + /** * Add contact handler. * @@ -407,6 +439,11 @@ angular.module('mm.addons.messages') siteid: siteId }); } + + if ($mmApp.isDesktop() && $mmLocalNotifications.isAvailable()) { + $mmEmulatorHelper.checkNewNotifications( + mmaMessagesPushSimulationComponent, fetchMessages, getTitleAndText, siteId); + } }; /** @@ -415,7 +452,7 @@ angular.module('mm.addons.messages') * @return {Number} Time between consecutive executions (in ms). */ self.getInterval = function() { - return 600000; // 10 minutes. + return $mmApp.isDesktop() ? 60000 : 600000; // 1 or 10 minutes. }; /** @@ -424,8 +461,9 @@ angular.module('mm.addons.messages') * @return {Boolean} True if is a sync process, false otherwise. */ self.isSync = function() { - // This is done to use only wifi if using the fallback function - return !$mmaMessages.isMessageCountEnabled(); + // This is done to use only wifi if using the fallback function. + // In desktop it is always sync, since it fetches messages to see if there's a new one. + return !$mmaMessages.isMessageCountEnabled() || $mmApp.isDesktop(); }; /** diff --git a/www/addons/messages/services/messages.js b/www/addons/messages/services/messages.js index 41f22f2a6aa..16aa328c250 100644 --- a/www/addons/messages/services/messages.js +++ b/www/addons/messages/services/messages.js @@ -22,7 +22,8 @@ angular.module('mm.addons.messages') * @name $mmaMessages */ .factory('$mmaMessages', function($mmSite, $mmSitesManager, $log, $q, $mmUser, $mmaMessagesOffline, $mmApp, $mmUtil, - mmaMessagesNewMessageEvent, mmaMessagesLimitMessages, mmaMessagesLimitSearchMessages) { + mmaMessagesNewMessageEvent, mmaMessagesLimitMessages, mmaMessagesLimitSearchMessages, $mmEmulatorHelper, + mmaMessagesPushSimulationComponent) { $log = $log.getInstance('$mmaMessages'); var self = {}; @@ -286,9 +287,12 @@ angular.module('mm.addons.messages') * @param {Number} [lfReceivedRead=0] Number of read received messages already fetched, so fetch will be done from this. * @param {Number} [lfSentUnread=0] Number of unread sent messages already fetched, so fetch will be done from this. * @param {Number} [lfSentRead=0] Number of read sent messages already fetched, so fetch will be done from this. + * @param {Boolean} [toDisplay=true] True if messages will be displayed to the user, either in view or in a notification. + * @param {String} [siteId] Site ID. If not defined, use current site. * @return {Promise} Promise resolved with messages and a boolean telling if can load more messages. */ - self.getDiscussion = function(userId, excludePending, lfReceivedUnread, lfReceivedRead, lfSentUnread, lfSentRead) { + self.getDiscussion = function(userId, excludePending, lfReceivedUnread, lfReceivedRead, lfSentUnread, lfSentRead, toDisplay, + siteId) { lfReceivedUnread = lfReceivedUnread || 0; lfReceivedRead = lfReceivedRead || 0; lfSentUnread = lfSentUnread || 0; @@ -315,14 +319,15 @@ angular.module('mm.addons.messages') } // Get message received by current user. - return self._getRecentMessages(params, presets, lfReceivedUnread, lfReceivedRead).then(function(response) { + return self._getRecentMessages(params, presets, lfReceivedUnread, lfReceivedRead, toDisplay, siteId) + .then(function(response) { result.messages = response; params.useridto = userId; params.useridfrom = $mmSite.getUserId(); hasReceived = response.length > 0; // Get message sent by current user. - return self._getRecentMessages(params, presets, lfSentUnread, lfSentRead); + return self._getRecentMessages(params, presets, lfSentUnread, lfSentRead, toDisplay, siteId); }).then(function(response) { result.messages = result.messages.concat(response); hasSent = response.length > 0; @@ -524,25 +529,40 @@ angular.module('mm.addons.messages') * @module mm.addons.messages * @ngdoc method * @name $mmaMessages#_getMessages - * @param {Object} params Parameters to pass to the WS. - * @param {Object} presets Set of presets for the WS. + * @param {Object} params Parameters to pass to the WS. + * @param {Object} preSets Set of presets for the WS. + * @param {Boolean} [toDisplay=true] True if messages will be displayed to the user, either in view or in a notification. + * @param {String} [siteId] Site ID. If not defined, use current site. * @return {Promise} * @protected */ - self._getMessages = function(params, presets) { + self._getMessages = function(params, preSets, toDisplay, siteId) { + toDisplay = typeof toDisplay == 'undefined' ? true : toDisplay; + siteId = siteId || $mmSite.getId(); + params = angular.extend(params, { type: 'conversations', newestfirst: 1, }); - return $mmSite.read('core_message_get_messages', params, presets).then(function(response) { - angular.forEach(response.messages, function(message) { - message.read = params.read == 0 ? 0 : 1; - // Convert times to milliseconds. - message.timecreated = message.timecreated ? message.timecreated * 1000 : 0; - message.timeread = message.timeread ? message.timeread * 1000 : 0; + return $mmSitesManager.getSite(siteId).then(function(site) { + var userId = site.getUserId(); + + return site.read('core_message_get_messages', params, preSets).then(function(response) { + angular.forEach(response.messages, function(message) { + message.read = params.read == 0 ? 0 : 1; + // Convert times to milliseconds. + message.timecreated = message.timecreated ? message.timecreated * 1000 : 0; + message.timeread = message.timeread ? message.timeread * 1000 : 0; + }); + + if ($mmApp.isDesktop() && toDisplay && !params.read && params.useridto == userId && params.limitfrom === 0) { + // Store the last unread received messages. Don't block the user for this. + storeLastReceivedMessageIfNeeded(params.useridfrom, response.messages[0], siteId); + } + + return response; }); - return response; }); }; @@ -556,10 +576,12 @@ angular.module('mm.addons.messages') * @param {Object} preSets Set of presets for the WS. * @param {Number} [limitFromUnread=0] Number of read messages already fetched, so fetch will be done from this number. * @param {Number} [limitFromRead=0] Number of unread messages already fetched, so fetch will be done from this number. + * @param {Boolean} [toDisplay=true] True if messages will be displayed to the user, either in view or in a notification. + * @param {String} [siteId] Site ID. If not defined, use current site. * @return {Promise} * @protected */ - self._getRecentMessages = function(params, preSets, limitFromUnread, limitFromRead) { + self._getRecentMessages = function(params, preSets, limitFromUnread, limitFromRead, toDisplay, siteId) { limitFromUnread = limitFromUnread || 0; limitFromRead = limitFromRead || 0; @@ -568,7 +590,7 @@ angular.module('mm.addons.messages') limitfrom: limitFromUnread }); - return self._getMessages(params, preSets).then(function(response) { + return self._getMessages(params, preSets, toDisplay, siteId).then(function(response) { var messages = response.messages; if (messages) { if (messages.length >= params.limitnum) { @@ -580,7 +602,7 @@ angular.module('mm.addons.messages') params.read = 1; params.limitfrom = limitFromRead; - return self._getMessages(params, preSets).then(function(response) { + return self._getMessages(params, preSets, toDisplay, siteId).then(function(response) { if (response.messages) { messages = messages.concat(response.messages); } @@ -642,11 +664,13 @@ angular.module('mm.addons.messages') * @return {Promise} Promise resolved with the message unread count. */ self.getUnreadConversationsCount = function(userId, siteId) { + var params; + return $mmSitesManager.getSite(siteId).then(function(site) { userId = userId || site.getUserId(); if (site.wsAvailable('core_message_get_unread_conversations_count')) { - var params = { + params = { useridto: userId }, preSets = { @@ -663,14 +687,14 @@ angular.module('mm.addons.messages') } // Fallback call. - var params = { + params = { read: 0, limitfrom: 0, limitnum: mmaMessagesLimitMessages + 1, useridto: userId, useridfrom: 0, }; - return self._getMessages(params).then(function(response) { + return self._getMessages(params, undefined, false, siteId).then(function(response) { // Count the discussions by filtering same senders. var discussions = {}, count; @@ -688,6 +712,40 @@ angular.module('mm.addons.messages') }); }; + /** + * Get the latest unread received messages. + * + * @module mm.addons.messages + * @ngdoc method + * @name $mmaMessages#getUnreadReceivedMessages + * @param {Boolean} [toDisplay=true] True if messages will be displayed to the user, either in view or in a notification. + * @param {Boolean} [forceCache] True if it should return cached data. Has priority over ignoreCache. + * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} [siteId] Site ID. If not defined, use current site. + * @return {Promise} Promise resolved with the message unread count. + */ + self.getUnreadReceivedMessages = function(toDisplay, forceCache, ignoreCache, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + var params = { + read: 0, + limitfrom: 0, + limitnum: mmaMessagesLimitMessages, + useridto: site.getUserId(), + useridfrom: 0 + }, + preSets = {}; + + if (forceCache) { + preSets.omitExpires = true; + } else if (ignoreCache) { + preSets.getFromCache = 0; + preSets.emergencyCache = 0; + } + + return self._getMessages(params, preSets, toDisplay, siteId); + }); + }; + /** * Invalidate all contacts cache. * @@ -1274,6 +1332,33 @@ angular.module('mm.addons.messages') }); } + /** + * Store the last received message if it's newer than the last stored. + * + * @param {Number} userIdFrom ID of the useridfrom retrieved, 0 for all users. + * @param {Object} message Last message received. + * @param {String} siteId Site ID. + * @return {Promise} Promise resolved when done. + */ + function storeLastReceivedMessageIfNeeded(userIdFrom, message, siteId) { + var component = mmaMessagesPushSimulationComponent; + + // Get the last received message. + return $mmEmulatorHelper.getLastReceivedNotification(component, siteId).then(function(lastMessage) { + if (userIdFrom > 0 && (!message || !lastMessage)) { + // Seeing a single discussion. No received message or cannot know if it really is the last received message. Stop. + return; + } + + if (message && lastMessage && message.timecreated <= lastMessage.timecreated) { + // The message isn't newer than the stored message, don't store it. + return; + } + + return $mmEmulatorHelper.storeLastReceivedNotification(component, message, siteId); + }); + } + /** * Unblock a user. * diff --git a/www/addons/mod/assign/lang/ca.json b/www/addons/mod/assign/lang/ca.json index 9d246a7ff12..065ff663e07 100644 --- a/www/addons/mod/assign/lang/ca.json +++ b/www/addons/mod/assign/lang/ca.json @@ -32,7 +32,7 @@ "errorshowinginformation": "No es pot mostrar la informació de la tramesa", "extensionduedate": "Data de venciment de la pròrroga", "feedbacknotsupported": "Aquesta retroacció no està admesa per l'aplicació i podria no contenir tota la informació", - "grade": "Qualifica", + "grade": "Qualificació", "graded": "Qualificada", "gradedby": "Qualificat per", "gradedon": "Qualificat el", diff --git a/www/addons/mod/assign/lang/de.json b/www/addons/mod/assign/lang/de.json index 802d7887f82..02ebc2a9649 100644 --- a/www/addons/mod/assign/lang/de.json +++ b/www/addons/mod/assign/lang/de.json @@ -32,7 +32,7 @@ "errorshowinginformation": "Die Abgabeinformationen können nicht angezeigt werden.", "extensionduedate": "Verlängerung des Fälligkeitsdatums", "feedbacknotsupported": "Dieses Feedback wird von der App nicht unterstützt und könnte möglicherweise Informationen unvollständig enthalten.", - "grade": "Relative Bewertung", + "grade": "Bewertung", "graded": "Bewertet", "gradedby": "Bewertet von", "gradedon": "Bewertet am", diff --git a/www/addons/mod/assign/lang/el.json b/www/addons/mod/assign/lang/el.json index 321937193aa..f05910d0dc3 100644 --- a/www/addons/mod/assign/lang/el.json +++ b/www/addons/mod/assign/lang/el.json @@ -23,15 +23,18 @@ "editsubmission": "Τροποποίηση της υποβολής μου", "erroreditpluginsnotsupported": "Δεν μπορείτε να προσθέσετε ή να επεξεργαστείτε μια υποβολή στην εφαρμογή επειδή ορισμένα plugins δεν υποστηρίζονται για επεξεργασία:", "errorshowinginformation": "Δεν μπορούν να εμφανιστούν οι πληροφορίες υποβολής", + "feedbacknotsupported": "Αυτό το σχόλιο δεν υποστηρίζεται από την εφαρμογή και μπορεί να μην περιέχει όλες τις πληροφορίες", "grade": "Βαθμός", "graded": "Βαθμολογήθηκε", "gradedby": "Βαθμολογήθηκε από", "gradedon": "Βαθμολογήθηκε στις", + "gradenotsynced": "Η βαθμολογία δεν συγχρονίστηκε", "gradingstatus": "Κατάσταση Βαθμολόγησης", "groupsubmissionsettings": "Ρυθμίσεις ομαδικής υποβολής", "latesubmissions": "Εκπρόθεσμες υποβολές", "noattempt": "Καμία προσπάθεια", "nomoresubmissionsaccepted": "Επιτρέπονται μόνο στους συμμετέχοντες που τους έχει χορηγηθεί παράταση", + "noonlinesubmissions": "Δεν απαιτείται κάποια υποβολή", "nosubmission": "Δεν έχει υποβληθεί τίποτα για την εργασία αυτή", "notallparticipantsareshown": "Συμμετέχοντες χωρίς υποβολές δεν προβάλλονται", "notgraded": "Χωρίς βαθμό", diff --git a/www/addons/mod/assign/lang/es.json b/www/addons/mod/assign/lang/es.json index 35e141f70c9..8b1583be23c 100644 --- a/www/addons/mod/assign/lang/es.json +++ b/www/addons/mod/assign/lang/es.json @@ -36,6 +36,7 @@ "graded": "Calificado", "gradedby": "Calificado por", "gradedon": "Calificado sobre", + "gradenotsynced": "Calificación no sincronizada", "gradeoutof": "Calificación sobre {{$a}}", "gradingstatus": "Estado de la calificación", "groupsubmissionsettings": "Configuración de entrega por grupo", diff --git a/www/addons/mod/assign/lang/es_mx.json b/www/addons/mod/assign/lang/es_mx.json deleted file mode 100644 index 5e29ef33e38..00000000000 --- a/www/addons/mod/assign/lang/es_mx.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "addsubmission": "Añadir envío", - "allowsubmissionsfromdate": "Permitir envíos desde", - "attemptnumber": "Número de intento", - "cutoffdate": "Fecha de corte", - "duedate": "Fecha de entrega", - "duedateno": "No hay fecha de entrega", - "submissions": "Entregas", - "viewsubmission": "Ver entrega" -} \ No newline at end of file diff --git a/www/addons/mod/assign/lang/eu.json b/www/addons/mod/assign/lang/eu.json index 1b62e71067f..c5b7f53de20 100644 --- a/www/addons/mod/assign/lang/eu.json +++ b/www/addons/mod/assign/lang/eu.json @@ -32,7 +32,7 @@ "errorshowinginformation": "Ezin dugu bidalketaren informazioa erakutsi", "extensionduedate": "Luzapenaren entregatze-data", "feedbacknotsupported": "Feedback hau ez da onartzen app-an eta baliteke informazio guztia jasota ez egotea.", - "grade": "Nota", + "grade": "Kalifikazioa", "graded": "Kalifikatua", "gradedby": "Nork kalifikatua", "gradedon": "Noiz kalifikatua", diff --git a/www/addons/mod/assign/lang/fr.json b/www/addons/mod/assign/lang/fr.json index 4dc3f9a1b2b..19cfc56bcaf 100644 --- a/www/addons/mod/assign/lang/fr.json +++ b/www/addons/mod/assign/lang/fr.json @@ -15,7 +15,7 @@ "attemptreopenmethod_untilpass": "Automatiquement jusqu'à réussite", "attemptsettings": "Réglages de tentative", "cannoteditduetostatementsubmission": "Vous ne pouvez pas ajouter, ni modifier de données dans l'app, car il n'est actuellement pas possible de récupérer les conditions d'envoi.", - "cannotgradefromapp": "Certaines méthodes d'évaluations ne sont pas encore supportées par l'app et ne peuvent pas être modifiées", + "cannotgradefromapp": "Certaines méthodes d'évaluations ne sont pas encore supportées par l'app et ne peuvent pas être modifiées.", "cannotsubmitduetostatementsubmission": "Vous ne pouvez pas déposer de travail à évaluer dans l'app, car il n'est actuellement pas possible de récupérer les conditions d'envoi.", "confirmsubmission": "Voulez-vous vraiment remettre votre travail pour évaluation ? Vous ne pourrez plus effectuer de changement.", "currentattempt": "Ceci est la tentative {{$a}}.", @@ -57,7 +57,7 @@ "nosubmission": "Rien n'a été déposé pour ce devoir", "notallparticipantsareshown": "Les participants sans travail remis ne sont pas affichés", "noteam": "Membre d'aucun groupe", - "notgraded": "Pas évalué", + "notgraded": "Non évalué", "numberofdraftsubmissions": "Brouillons", "numberofparticipants": "Participants", "numberofsubmissionsneedgrading": "Nécessitant évaluation", @@ -76,10 +76,10 @@ "submissionstatus_": "Pas de travail remis", "submissionstatus_draft": "Brouillon (non remis)", "submissionstatus_marked": "Noté", - "submissionstatus_new": "Aucun travail remis", + "submissionstatus_new": "Non remis", "submissionstatus_reopened": "Rouvert", "submissionstatus_submitted": "Remis pour évaluation", - "submissionstatusheading": "État du travail remis", + "submissionstatusheading": "Statut de remise", "submissionteam": "Groupe", "submitassignment": "Envoyer le devoir", "submitassignment_help": "Une fois ce devoir envoyé, vous ne pourrez plus y effectuer de modification.", diff --git a/www/addons/mod/assign/lang/he.json b/www/addons/mod/assign/lang/he.json index 634624ece1e..05f4ea2748c 100644 --- a/www/addons/mod/assign/lang/he.json +++ b/www/addons/mod/assign/lang/he.json @@ -25,7 +25,7 @@ "editingstatus": "מצב עריכה", "editsubmission": "עריכת ההגשה", "extensionduedate": "הארכת מועד הגשה", - "grade": "ציונים", + "grade": "ציון", "graded": "נבדק", "gradedby": "נבדק על-ידי", "gradedon": "הציון ניתן על", diff --git a/www/addons/mod/assign/lang/it.json b/www/addons/mod/assign/lang/it.json index efc338d796b..bfcebef051d 100644 --- a/www/addons/mod/assign/lang/it.json +++ b/www/addons/mod/assign/lang/it.json @@ -25,7 +25,7 @@ "editingstatus": "Possibilità di modifica", "editsubmission": "Modifica consegna", "extensionduedate": "Data scadenza proroga", - "grade": "Punteggio", + "grade": "Valutazione", "graded": "Valutata", "gradedby": "Valutatore", "gradedon": "Data di valutazione", diff --git a/www/addons/mod/assign/lang/ja.json b/www/addons/mod/assign/lang/ja.json index d7f86ec249e..4837351e4cc 100644 --- a/www/addons/mod/assign/lang/ja.json +++ b/www/addons/mod/assign/lang/ja.json @@ -1,4 +1,5 @@ { + "acceptsubmissionstatement": "提出時宣誓文を受諾してください。", "addattempt": "別の提出を許可する", "addnewattempt": "新しい提出を追加する", "addnewattemptfromprevious": "前回の提出をもとに新しい提出を追加する", @@ -13,6 +14,9 @@ "attemptreopenmethod_manual": "手動", "attemptreopenmethod_untilpass": "合格するまで自動", "attemptsettings": "受験設定", + "cannoteditduetostatementsubmission": "サイトから提出時宣誓文を取得することができなかったため、アプリでは提出物の追加や編集ができません。", + "cannotgradefromapp": "評定方法にアプリでは未サポートあるいは変更できないものがあります。", + "cannotsubmitduetostatementsubmission": "サイトから提出時宣誓文が取得できなかったため、アプリから評定を提出することができませんでした。", "confirmsubmission": "本当にあなたの作業を評定のために提出してもよろしいですか? これ以上、あなたは変更できないようになります。", "currentattempt": "これは {{$a}} 回目の提出です。", "currentattemptof": "これは {{$a.attemptnumber}} 回目の提出です ( {{$a.maxattempts}} 回の提出が許可されています)。", @@ -24,11 +28,15 @@ "duedatereached": "この課題の提出期限を過ぎました。", "editingstatus": "編集ステータス", "editsubmission": "提出を編集する", + "erroreditpluginsnotsupported": "提出物の編集がサポートされていないプラグインがあるため、アプリから提出物の追加や編集ができませんでした。", + "errorshowinginformation": "提出物の情報を表示できません。", "extensionduedate": "延長提出期限", - "grade": "評点", + "feedbacknotsupported": "このフィードバックはアプリでは未サポートのため、すべての情報が含まれていない可能性があります", + "grade": "評定", "graded": "評定済み", "gradedby": "評定者", "gradedon": "評定日時", + "gradenotsynced": "評定が同期できませんでした", "gradeoutof": "{{$a}} 点中の評点", "gradingstatus": "評定ステータス", "groupsubmissionsettings": "グループ提出設定", @@ -47,6 +55,7 @@ "nomoresubmissionsaccepted": "延長を許可された参加者のみ許可されます。", "noonlinesubmissions": "この課題においてあなたがオンラインで提出するものはありません。", "nosubmission": "この課題に関して提出されているものはありません。", + "notallparticipantsareshown": "提出物のない参加者は表示されていません", "noteam": "どのグループのメンバーでもない", "notgraded": "未評定", "numberofdraftsubmissions": "下書き", @@ -61,6 +70,7 @@ "submission": "提出課題", "submissioneditable": "学生はこの提出を編集できます。", "submissionnoteditable": "学生はこの提出を編集できません。", + "submissionnotsupported": "この提出物はアプリでは未サポートのため、すべての情報が含まれていない可能性があります", "submissionslocked": "この課題は提出を受け付けていません。", "submissionstatus": "提出ステータス", "submissionstatus_": "提出なし", @@ -80,5 +90,8 @@ "ungroupedusers": "設定「提出にグループを必要とする」が有効にされているため、そして何名かのユーザがグループのメンバーではないため、または2つ以上のグループメンバーであるため、提出することはできません。", "unlimitedattempts": "無制限", "userswhoneedtosubmit": "提出が必要なユーザ: {{$a}}", - "viewsubmission": "提出を表示する" + "userwithid": "ID {{id}} を持つユーザ", + "viewsubmission": "提出を表示する", + "warningsubmissiongrademodified": "提出物の評定がサイト上で変更されました。", + "warningsubmissionmodified": "ユーザの提出物がサイト上で変更されました。" } \ No newline at end of file diff --git a/www/addons/mod/assign/lang/nl.json b/www/addons/mod/assign/lang/nl.json index cb58014537a..6148bf53066 100644 --- a/www/addons/mod/assign/lang/nl.json +++ b/www/addons/mod/assign/lang/nl.json @@ -32,7 +32,7 @@ "errorshowinginformation": "We kunnen de instuurinformatie niet tonen", "extensionduedate": "Extra tijd einddatum", "feedbacknotsupported": "Deze feedback wordt niet ondersteund door de app en het is mogelijk dat de informatie onvolledig is", - "grade": "Cijfer", + "grade": "Beoordeling", "graded": "Beoordeeld", "gradedby": "Beoordeeld door", "gradedon": "Beoordeeld op", diff --git a/www/addons/mod/assign/lang/pt-br.json b/www/addons/mod/assign/lang/pt-br.json index 1b62b585379..f88df961a39 100644 --- a/www/addons/mod/assign/lang/pt-br.json +++ b/www/addons/mod/assign/lang/pt-br.json @@ -32,7 +32,7 @@ "errorshowinginformation": "Nós não podemos exibir as informações do envio", "extensionduedate": "Extensão do prazo de entrega", "feedbacknotsupported": "Esse feedback não é suportado pelo aplicativo e pode não conter todas as informações", - "grade": "Avaliação", + "grade": "Nota", "graded": "Avaliado", "gradedby": "Avaliado por", "gradedon": "Avaliado em", @@ -42,7 +42,7 @@ "groupsubmissionsettings": "Configurações de envio em grupo", "hiddenuser": "Participante", "latesubmissions": "Submissões atrasadas", - "latesubmissionsaccepted": "Somente estudante(s) contemplados com uma extensão ainda poderá(ão) enviar a tarefa", + "latesubmissionsaccepted": "Permitido até {{$a}}", "markingworkflowstate": "Estado do fluxo de avaliação", "markingworkflowstateinmarking": "Em avaliação", "markingworkflowstateinreview": "Em revisão", @@ -50,7 +50,7 @@ "markingworkflowstatereadyforrelease": "Pronto para publicação", "markingworkflowstatereadyforreview": "Avaliação concluída", "markingworkflowstatereleased": "Publicado", - "multipleteams": "Você é membro de vários grupos, entre em contato com o seu professor.", + "multipleteams": "Membro de mais de um grupo", "noattempt": "Nenhuma tentativa", "nomoresubmissionsaccepted": "Só é permitido para os participantes que tenham beneficiado de uma extensão", "noonlinesubmissions": "Esta tarefa não requer o envio online", diff --git a/www/addons/mod/assign/lang/pt.json b/www/addons/mod/assign/lang/pt.json index e2242d63f5e..f94e6cbb858 100644 --- a/www/addons/mod/assign/lang/pt.json +++ b/www/addons/mod/assign/lang/pt.json @@ -32,14 +32,14 @@ "errorshowinginformation": "Não é possível mostrar a informação da submissão", "extensionduedate": "Prolongamento da data limite", "feedbacknotsupported": "Este feedback não é suportado pela aplicação e pode não conter toda a informação", - "grade": "Avaliação", + "grade": "Nota", "graded": "Avaliado", "gradedby": "Avaliado por", "gradedon": "Avaliado em", "gradenotsynced": "Nota não está sincronizada", "gradeoutof": "Nota (de 0 a {{$a}})", "gradingstatus": "Estado da avaliação", - "groupsubmissionsettings": "Configurações das submissões de grupo", + "groupsubmissionsettings": "Configurações das submissões em grupo", "hiddenuser": "Participante", "latesubmissions": "Submissões com atraso", "latesubmissionsaccepted": "Disponível até {{$a}}", diff --git a/www/addons/mod/assign/lang/pt_br.json b/www/addons/mod/assign/lang/pt_br.json deleted file mode 100644 index ebcaf06b692..00000000000 --- a/www/addons/mod/assign/lang/pt_br.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "addsubmission": "Adicionar tarefa", - "allowsubmissionsfromdate": "Permite envios a partir de", - "attemptnumber": "Número da tentativa", - "cutoffdate": "Data limite", - "duedate": "Data de entrega", - "duedateno": "Nenhuma data de entrega", - "submissions": "Tarefas enviadas", - "viewsubmission": "Ver envio" -} \ No newline at end of file diff --git a/www/addons/mod/assign/lang/ro.json b/www/addons/mod/assign/lang/ro.json index 00faa4cbbda..9e5786fe879 100644 --- a/www/addons/mod/assign/lang/ro.json +++ b/www/addons/mod/assign/lang/ro.json @@ -20,7 +20,7 @@ "editingstatus": "Se editează statusul", "editsubmission": "Editare temă trimisă", "extensionduedate": "Termen de predare extins", - "grade": "Notează", + "grade": "Notă", "graded": "Notat", "gradedby": "Notat de", "gradedon": "Notat în data de", diff --git a/www/addons/mod/assign/lang/sr-cr.json b/www/addons/mod/assign/lang/sr-cr.json new file mode 100644 index 00000000000..3d0bf618245 --- /dev/null +++ b/www/addons/mod/assign/lang/sr-cr.json @@ -0,0 +1,97 @@ +{ + "acceptsubmissionstatement": "Молимо вас да прихватите изјаву о предаји рада.", + "addattempt": "Дозволи други покушај", + "addnewattempt": "Додај нови покушај", + "addnewattemptfromprevious": "Додај нови покушај на основу претходно предатог рада", + "addsubmission": "Додај рад", + "allowsubmissionsanddescriptionfromdatesummary": "Детаљније информације о задатку и образац за предају радова биће доступни од {{$a}}", + "allowsubmissionsfromdate": "Дозволи предају од", + "allowsubmissionsfromdatesummary": "Овај задатак ће прихватити предају рада од {{$a}}", + "applytoteam": "Примените оцене и повратне информације на целу групу", + "assignmentisdue": "Крајњи рок за предају је истекао", + "attemptnumber": "Број покушаја", + "attemptreopenmethod": "Поновно отварање рада", + "attemptreopenmethod_manual": "Ручно", + "attemptreopenmethod_untilpass": "Аутоматски док не добије прелазну оцену", + "attemptsettings": "Подешавања покушаја", + "cannoteditduetostatementsubmission": "Не можете да додате или мењате рад у апликацији јер нисмо могли да преузмемо са сајта изјаву о предаји рада.", + "cannotgradefromapp": "Апликације још увек не подржава неке методе оцењивања и оне не могу да се мењају.", + "cannotsubmitduetostatementsubmission": "Не можете да предате рад на оцењивање у апликацији јер нисмо могли да преузмемо са сајта изјаву о предаји рада.", + "confirmsubmission": "Да ли сте сигурни да желите да предате свој рад на оцењивање? Више нећете моћи да га мењате.", + "currentattempt": "Ово је покушај {{$a}}.", + "currentattemptof": "Ово је покушај {{$a.attemptnumber}} ( {{$a.maxattempts}} дозвољена/их покушаја ).", + "currentgrade": "Тренутна оцена у књизи оцена", + "cutoffdate": "Дефинитивни рок", + "defaultteam": "Подразумевана група", + "duedate": "Крајњи рок", + "duedateno": "Нема крајњег рока", + "duedatereached": "Крајњи рок за овај задатак је сада истекао", + "editingstatus": "Статус уређивања", + "editsubmission": "Уреди рад", + "erroreditpluginsnotsupported": "Не можете да додате или мењате рад у апликацији јер неки додаци немају подршку за уређивање:", + "errorshowinginformation": "Не можемо да прикажемо информације о предатом раду", + "extensionduedate": "Продужени рок", + "feedbacknotsupported": "Аплликација не подржава ову повратну информацију. Могуће је да она не садржи све информације.", + "grade": "Оцена", + "graded": "Оцењено", + "gradedby": "Оценио/ла", + "gradedon": "Оцењено", + "gradenotsynced": "Оцена није синхронизована", + "gradeoutof": "Оцена од {{$a}}", + "gradingstatus": "Статус оцењивања", + "groupsubmissionsettings": "Подешавања за групну предају рада", + "hiddenuser": "Учесник", + "latesubmissions": "Касно предати радови", + "latesubmissionsaccepted": "Дозвољено до {{$a}}", + "markingworkflowstate": "Стање тока оцењивања", + "markingworkflowstateinmarking": "Оцењује се", + "markingworkflowstateinreview": "На прегледу", + "markingworkflowstatenotmarked": "Није оцењено", + "markingworkflowstatereadyforrelease": "Спремно за објаву", + "markingworkflowstatereadyforreview": "Оцењивање завршено", + "markingworkflowstatereleased": "Објављено", + "multipleteams": "Члан више од једне групе", + "noattempt": "Нема покушаја", + "nomoresubmissionsaccepted": "Дозвољено само полазницима којима је одобрен продужетак", + "noonlinesubmissions": "Овај задатак не тражи од вас да било штa предате онлајн", + "nosubmission": "За овај задатак још ништа није предато", + "notallparticipantsareshown": "Учесници који нису предали рад се не приказују", + "noteam": "Није члан ниједне групе.", + "notgraded": "Није оцењено", + "numberofdraftsubmissions": "Нацрти", + "numberofparticipants": "Учесници", + "numberofsubmissionsneedgrading": "Тражи оцењивање", + "numberofsubmittedassignments": "Предато", + "numberofteams": "Групе", + "numwords": "{{$a}} реч(и)", + "outof": "{{$a.current}} од {{$a.total}}", + "overdue": "Крајњи рок за предају рада је истекао пре: {{$a}}", + "savechanges": "Сачувај промене", + "submission": "Предати рад", + "submissioneditable": "Полазници могу да уређују овај задатак", + "submissionnoteditable": "Полазници не могу да уређују овај задатак", + "submissionnotsupported": "Апликација не подржава овај предати рад. Могуће је да рад не садржи све информације.", + "submissionslocked": "Овај задатак не прихвата предају радова", + "submissionstatus": "Статус предатог рада", + "submissionstatus_": "Нема предатих радова", + "submissionstatus_draft": "Нацрт рада (није предато)", + "submissionstatus_marked": "Оцењено", + "submissionstatus_new": "Нови предати рад", + "submissionstatus_reopened": "Поново отворено", + "submissionstatus_submitted": "Предато за оцењивање", + "submissionstatusheading": "Статус предатог рада", + "submissionteam": "Група", + "submitassignment": "Predaj rad", + "submitassignment_help": "Оног тренутка када предате овај рад више нећете моћи да га мењате.", + "submittedearly": "Задатак је предат {{$a}} раније", + "submittedlate": "Задатак је предат {{$a}} касније", + "timemodified": "Последње измене", + "timeremaining": "Преостало време", + "ungroupedusers": "Подешавање 'Неопходна је група за предају рада' је омогућено, али неки корисници нису чланови ниједне групе, или су чланови више од једне групе, тако да не могу да предају рад.", + "unlimitedattempts": "Неограничено", + "userswhoneedtosubmit": "Корисници који треба да предају решење: {{$a}}", + "userwithid": "Корисник са ID ознаком {{id}}", + "viewsubmission": "Погледај предати рад", + "warningsubmissiongrademodified": "Оцена предатог рада је измењена на сајту.", + "warningsubmissionmodified": "Предати рад корисника је измењен на сајту." +} \ No newline at end of file diff --git a/www/addons/mod/assign/lang/sr-lt.json b/www/addons/mod/assign/lang/sr-lt.json new file mode 100644 index 00000000000..ee08bd63383 --- /dev/null +++ b/www/addons/mod/assign/lang/sr-lt.json @@ -0,0 +1,97 @@ +{ + "acceptsubmissionstatement": "Molimo vas da prihvatite izjavu o predaji rada.", + "addattempt": "Dozvoli drugi pokušaj", + "addnewattempt": "Dodaj novi pokušaj", + "addnewattemptfromprevious": "Dodaj novi pokušaj na osnovu prethodno predatog rada", + "addsubmission": "Dodaj rad", + "allowsubmissionsanddescriptionfromdatesummary": "Detaljnije informacije o zadatku i obrazac za predaju radova biće dostupni od {{$a}}", + "allowsubmissionsfromdate": "Dozvoli predaju od", + "allowsubmissionsfromdatesummary": "Ovaj zadatak će prihvatiti predaju rada od {{$a}}", + "applytoteam": "Primenite ocene i povratne informacije na celu grupu", + "assignmentisdue": "Krajnji rok za predaju je istekao", + "attemptnumber": "Broj pokušaja", + "attemptreopenmethod": "Ponovno otvaranje rada", + "attemptreopenmethod_manual": "Ručno", + "attemptreopenmethod_untilpass": "Automatski dok ne dobije prelaznu ocenu", + "attemptsettings": "Podešavanja pokušaja", + "cannoteditduetostatementsubmission": "Ne možete da dodate ili menjate rad u aplikaciji jer nismo mogli da preuzmemo sa sajta izjavu o predaji rada.", + "cannotgradefromapp": "Aplikacije ne podržava neke metode ocenjivanja i one ne mogu da se menjaju.", + "cannotsubmitduetostatementsubmission": "Ne možete da predate rad na ocenjivanje u aplikaciji jer nismo mogli da preuzmemo sa sajta izjavu o predaji rada.", + "confirmsubmission": "Da li ste sigurni da želite da predate svoj rad na ocenjivanje? Više nećete moći da ga menjate.", + "currentattempt": "Ovo je pokušaj {{$a}}.", + "currentattemptof": "Ovo je pokušaj {{$a.attemptnumber}} ( {{$a.maxattempts}} dozvoljena/ih pokušaja ).", + "currentgrade": "Trenutna ocena u knjizi ocena", + "cutoffdate": "Definitivni rok", + "defaultteam": "Podrazumevana grupa", + "duedate": "Krajnji rok", + "duedateno": "Nema krajnjeg roka", + "duedatereached": "Krajnji rok za ovaj zadatak je sada istekao", + "editingstatus": "Status uređivanja", + "editsubmission": "Uredi rad", + "erroreditpluginsnotsupported": "Ne možete da dodate ili menjate rad u aplikaciji jer neki dodaci nemaju podršku za uređivanje:", + "errorshowinginformation": "Ne možemo da prikažemo informacije o predatom radu", + "extensionduedate": "Produženi rok", + "feedbacknotsupported": "Apllikacija ne podržava ovu povratnu informaciju. Moguće je da ona ne sadrži sve informacije.", + "grade": "Ocena", + "graded": "Ocenjeno", + "gradedby": "Ocenio/la", + "gradedon": "Ocenjeno", + "gradenotsynced": "Ocena nije sinhronizovana", + "gradeoutof": "Ocena od {{$a}}", + "gradingstatus": "Status ocenjivanja", + "groupsubmissionsettings": "Podešavanja za grupnu predaju rada", + "hiddenuser": "Učesnik", + "latesubmissions": "Kasno predati radovi", + "latesubmissionsaccepted": "Dozvoljeno do {{$a}}", + "markingworkflowstate": "Stanje toka ocenjivanja", + "markingworkflowstateinmarking": "Ocenjuje se", + "markingworkflowstateinreview": "Na pregledu", + "markingworkflowstatenotmarked": "Nije ocenjeno", + "markingworkflowstatereadyforrelease": "Spremno za objavu", + "markingworkflowstatereadyforreview": "Ocenjivanje završeno", + "markingworkflowstatereleased": "Objavljeno", + "multipleteams": "Član više od jedne grupe", + "noattempt": "Nema pokušaja", + "nomoresubmissionsaccepted": "Dozvoljeno samo polaznicima kojima je odobren produžetak", + "noonlinesubmissions": "Ovaj zadatak ne traži od vas da bilo šta predate onlajn", + "nosubmission": "Za ovaj zadatak još ništa nije predato", + "notallparticipantsareshown": "Učesnici koji nisu predali rad se ne prikazuju", + "noteam": "Nije član nijedne grupe.", + "notgraded": "Nije ocenjeno", + "numberofdraftsubmissions": "Nacrti", + "numberofparticipants": "Učesnici", + "numberofsubmissionsneedgrading": "Traži ocenjivanje", + "numberofsubmittedassignments": "Predato", + "numberofteams": "Grupe", + "numwords": "{{$a}} reč(i)", + "outof": "{{$a.current}} od {{$a.total}}", + "overdue": "Krajnji rok za predaju rada je istekao pre: {{$a}}", + "savechanges": "Sačuvaj promene", + "submission": "Predati rad", + "submissioneditable": "Polaznici mogu da uređuju ovaj zadatak", + "submissionnoteditable": "Polaznici ne mogu da uređuju ovaj zadatak", + "submissionnotsupported": "Aplikacija ne podržava ovaj predati rad. Moguće je da rad ne sadrži sve informacije.", + "submissionslocked": "Ovaj zadatak ne prihvata predaju radova", + "submissionstatus": "Status predatog rada", + "submissionstatus_": "Nema predatih radova", + "submissionstatus_draft": "Nacrt rada (nije predato)", + "submissionstatus_marked": "Ocenjeno", + "submissionstatus_new": "Novi predati rad", + "submissionstatus_reopened": "Ponovo otvoreno", + "submissionstatus_submitted": "Predato za ocenjivanje", + "submissionstatusheading": "Status predatog rada", + "submissionteam": "Grupa", + "submitassignment": "Predaj zadatak", + "submitassignment_help": "Onog trenutka kada predate ovaj rad više nećete moći da ga menjate.", + "submittedearly": "Zadatak je predat {{$a}} ranije", + "submittedlate": "Zadatak je predat {{$a}} kasnije", + "timemodified": "Poslednje izmene", + "timeremaining": "Preostalo vreme", + "ungroupedusers": "Podešavanje 'Neophodna je grupa za predaju rada' je omogućeno, ali neki korisnici nisu članovi nijedne grupe, ili su članovi više od jedne grupe, tako da ne mogu da predaju rad.", + "unlimitedattempts": "Neograničeno", + "userswhoneedtosubmit": "Korisnici koji treba da predaju rešenje: {{$a}}", + "userwithid": "Korisnik sa ID oznakom {{id}}", + "viewsubmission": "Pogledaj predati rad", + "warningsubmissiongrademodified": "Ocena predatog rada je izmenjena na sajtu.", + "warningsubmissionmodified": "Predati rad korisnika je izmenjen na sajtu." +} \ No newline at end of file diff --git a/www/addons/mod/assign/lang/sv.json b/www/addons/mod/assign/lang/sv.json index 674db970084..a4ffe14d1c8 100644 --- a/www/addons/mod/assign/lang/sv.json +++ b/www/addons/mod/assign/lang/sv.json @@ -13,7 +13,7 @@ "attemptreopenmethod_manual": "Manuellt", "attemptreopenmethod_untilpass": "Automatiskt tills passerat", "attemptsettings": "Inställningar försök", - "confirmsubmission": "Är du säker på att du vill lämna in ditt arbete för betygssättning? Du kommer inte längre att kunna göra några förändringar", + "confirmsubmission": "Är du säker på att du vill lämna in ditt arbete för betygssättning? Du kommer inte längre att kunna göra några ändringar", "currentattempt": "Detta är försök {{$a}}.", "currentattemptof": "Detta är försök {{$a.attemptnumber}} ( {{$a.maxattempts}} försök tillåten).", "currentgrade": "Aktuellt betyg/omdöme i betygskatalogen", @@ -23,9 +23,9 @@ "duedateno": "Inget stoppdatum/tid", "duedatereached": "Stoppdatum för denna inlämningsuppgift har nu passerat", "editingstatus": "Redigerar status", - "editsubmission": "Redigera min inskickade uppgiftslösning", + "editsubmission": "Redigera min inlämning", "extensionduedate": "Förlängning av stoppdatum", - "grade": "Betyg/omdöme", + "grade": "Betyg", "graded": "Betygssatt", "gradedby": "Betygssatt av", "gradedon": "Betygssatt den", diff --git a/www/addons/mod/assign/lang/tr.json b/www/addons/mod/assign/lang/tr.json index 72b0e0a2002..d56c55e9e46 100644 --- a/www/addons/mod/assign/lang/tr.json +++ b/www/addons/mod/assign/lang/tr.json @@ -25,7 +25,7 @@ "editingstatus": "Durumu düzenleme", "editsubmission": "Gönderimi düzenle", "extensionduedate": "Ek sürenin bitiş tarihi", - "grade": "Not", + "grade": "Başarı notu", "graded": "Notlandırıldı", "gradedon": "Not verildi", "gradeoutof": "{{$a}} Dışarıdan notu", diff --git a/www/addons/mod/assign/lang/uk.json b/www/addons/mod/assign/lang/uk.json index 2b97cdc9229..96c4002f16f 100644 --- a/www/addons/mod/assign/lang/uk.json +++ b/www/addons/mod/assign/lang/uk.json @@ -16,7 +16,7 @@ "attemptsettings": "Налаштування спроби", "cannoteditduetostatementsubmission": "Ви не можете додати або змінити представлення в додатку, тому що ми не могли отримати заяву з сайту.", "cannotgradefromapp": "Деякі методи класифікації поки не підтримуються додатком і не можуть бути змінені.", - "cannotsubmitduetostatementsubmission": "Ви не можете подати для сортування в додатку, тому що ми не могли отримати заява представлення з сайту.", + "cannotsubmitduetostatementsubmission": "Ви не можете подати запит для сортування в додатку, тому що ми не могли отримати заява представлення з сайту.", "confirmsubmission": "Відправити вашу роботу на перевірку? Після цього ви не зможете робити в ній ніяких змін.", "currentattempt": "Це спроба {{$a}}.", "currentattemptof": "Це спроба {{$a.attemptnumber}} (дозволено спроб - {{$a.maxattempts}}).", @@ -36,7 +36,7 @@ "graded": "Оцінено", "gradedby": "Оцінив", "gradedon": "Оцінено на", - "gradenotsynced": "Оцінка не синхронізуються", + "gradenotsynced": "Оцінки не синхронізовані", "gradeoutof": "Оцінка (макс. {{$a}})", "gradingstatus": "Статус оцінення", "groupsubmissionsettings": "Налаштування групової здачі", diff --git a/www/addons/mod/assign/lang/zh-tw.json b/www/addons/mod/assign/lang/zh-tw.json index 94a6fc83415..674e767eebf 100644 --- a/www/addons/mod/assign/lang/zh-tw.json +++ b/www/addons/mod/assign/lang/zh-tw.json @@ -32,7 +32,7 @@ "errorshowinginformation": "我們無法顯示提交資訊", "extensionduedate": "展延到期日", "feedbacknotsupported": "該應用程式不支援此回饋, 並且可能不包含所有資訊", - "grade": "分數", + "grade": "成績", "graded": "已評分", "gradedby": "已評分由", "gradedon": "評分標準", diff --git a/www/addons/mod/assign/lang/zh_cn.json b/www/addons/mod/assign/lang/zh_cn.json deleted file mode 100644 index 59341a88ccf..00000000000 --- a/www/addons/mod/assign/lang/zh_cn.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "addsubmission": "添加提交", - "allowsubmissionsfromdate": "开启时间", - "attemptnumber": "作业提交次数", - "cutoffdate": "提交截止时间", - "duedate": "截止时间", - "duedateno": "无截止时间", - "submissions": "提交信息", - "viewsubmission": "查看提交" -} \ No newline at end of file diff --git a/www/addons/mod/assign/lang/zh_tw.json b/www/addons/mod/assign/lang/zh_tw.json deleted file mode 100644 index 16a48d2186a..00000000000 --- a/www/addons/mod/assign/lang/zh_tw.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "addsubmission": "繳交作業", - "allowsubmissionsfromdate": "開始繳交時間", - "attemptnumber": "作業提交次數", - "cutoffdate": "拒收作業時間", - "duedate": "規定繳交時間", - "duedateno": "沒有規定繳交時間", - "submissions": "繳交", - "viewsubmission": "檢視繳交的作業" -} \ No newline at end of file diff --git a/www/addons/mod/assign/services/handlers.js b/www/addons/mod/assign/services/handlers.js index 0dd88eac33b..818e81c48d3 100644 --- a/www/addons/mod/assign/services/handlers.js +++ b/www/addons/mod/assign/services/handlers.js @@ -21,7 +21,7 @@ angular.module('mm.addons.mod_assign') * @ngdoc service * @name $mmaModAssignHandlers */ -.factory('$mmaModAssignHandlers', function($mmCourse, $mmaModAssign, $state, $mmContentLinksHelper, $mmUtil, mmCoreDownloading, +.factory('$mmaModAssignHandlers', function($mmCourse, $mmaModAssign, $state, $mmContentLinksHelper, $mmUtil, mmCoreDownloading, $q, mmCoreNotDownloaded, mmCoreOutdated, $mmEvents, mmCoreEventPackageStatusChanged, $mmSite, mmaModAssignComponent, $mmCoursePrefetchDelegate, $mmaModAssignPrefetchHandler, $mmaModAssignSync) { var self = {}; @@ -102,9 +102,10 @@ angular.module('mm.addons.mod_assign') // We need to call getDownloadSize, the package might have been updated. $mmaModAssignPrefetchHandler.getDownloadSize(module, courseId).then(function(size) { $mmUtil.confirmDownloadSize(size).then(function() { - $mmaModAssignPrefetchHandler.prefetch(module, courseId).catch(function() { + return $mmaModAssignPrefetchHandler.prefetch(module, courseId).catch(function(error) { if (!$scope.$$destroyed) { - $mmUtil.showErrorModal('mm.core.errordownloading', true); + $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true); + return $q.reject(); } }); }).catch(function() { diff --git a/www/addons/mod/assign/submission/file/directive.js b/www/addons/mod/assign/submission/file/directive.js index 5345298b55b..96ffcf8ade2 100644 --- a/www/addons/mod/assign/submission/file/directive.js +++ b/www/addons/mod/assign/submission/file/directive.js @@ -21,7 +21,7 @@ angular.module('mm.addons.mod_assign') * @ngdoc directive * @name mmaModAssignSubmissionFile */ -.directive('mmaModAssignSubmissionFile', function($mmaModAssign, $mmaModAssignSubmissionFileSession, $mmaModAssignHelper, +.directive('mmaModAssignSubmissionFile', function($mmaModAssign, $mmFileSession, mmaModAssignComponent, $mmaModAssignHelper, $mmaModAssignOffline, mmaModAssignSubmissionFileName, $mmFileUploaderHelper, $q) { return { restrict: 'A', @@ -55,7 +55,7 @@ angular.module('mm.addons.mod_assign') scope.files = $mmaModAssign.getSubmissionPluginAttachments(scope.plugin); } }).finally(function() { - $mmaModAssignSubmissionFileSession.setFiles(scope.assign.id, scope.files); + $mmFileSession.setFiles(mmaModAssignComponent, scope.assign.id, scope.files); }); } }; diff --git a/www/addons/mod/assign/submission/file/handlers.js b/www/addons/mod/assign/submission/file/handlers.js index a0eee0b82b9..3ef411ea46c 100644 --- a/www/addons/mod/assign/submission/file/handlers.js +++ b/www/addons/mod/assign/submission/file/handlers.js @@ -23,7 +23,7 @@ angular.module('mm.addons.mod_assign') * @ngdoc service * @name $mmaModAssignSubmissionFileHandler */ -.factory('$mmaModAssignSubmissionFileHandler', function($mmaModAssignSubmissionFileSession, $mmaModAssign, $mmSite, $q, +.factory('$mmaModAssignSubmissionFileHandler', function($mmFileSession, mmaModAssignComponent, $mmaModAssign, $mmSite, $q, $mmaModAssignHelper, $mmWS, $mmFS, $mmFilepool, $mmUtil, $mmaModAssignOffline, mmaModAssignSubmissionFileName, $mmFileUploaderHelper) { @@ -60,10 +60,10 @@ angular.module('mm.addons.mod_assign') * @return {Void} */ self.clearTmpData = function(assign, submission, plugin, inputData) { - var files = $mmaModAssignSubmissionFileSession.getFiles(assign.id); + var files = $mmFileSession.getFiles(mmaModAssignComponent, assign.id); // Clear the files in session for this assign. - $mmaModAssignSubmissionFileSession.clearFiles(assign.id); + $mmFileSession.clearFiles(mmaModAssignComponent, assign.id); // Now delete the local files from the tmp folder. $mmFileUploaderHelper.clearTmpFiles(files); }; @@ -156,7 +156,7 @@ angular.module('mm.addons.mod_assign') // Check if there's any change. if (self.hasDataChanged(assign, submission, plugin, inputData)) { - var files = $mmaModAssignSubmissionFileSession.getFiles(assign.id), + var files = $mmFileSession.getFiles(mmaModAssignComponent, assign.id), totalSize = 0, promises = []; @@ -278,7 +278,7 @@ angular.module('mm.addons.mod_assign') var pluginFiles = $mmaModAssign.getSubmissionPluginAttachments(plugin); return pluginFiles && pluginFiles.length; }).then(function(numFiles) { - var currentFiles = $mmaModAssignSubmissionFileSession.getFiles(assign.id); + var currentFiles = $mmFileSession.getFiles(mmaModAssignComponent, assign.id); if (currentFiles.length != numFiles) { // Number of files has changed. @@ -320,7 +320,7 @@ angular.module('mm.addons.mod_assign') if (self.hasDataChanged(assign, submission, plugin, inputData)) { // Data has changed, we need to upload new files and re-upload all the existing files. - var currentFiles = $mmaModAssignSubmissionFileSession.getFiles(assign.id), + var currentFiles = $mmFileSession.getFiles(mmaModAssignComponent, assign.id), error = $mmUtil.hasRepeatedFilenames(currentFiles); if (error) { diff --git a/www/addons/mod/assign/submission/file/session.js b/www/addons/mod/assign/submission/file/session.js deleted file mode 100644 index cc29a18343a..00000000000 --- a/www/addons/mod/assign/submission/file/session.js +++ /dev/null @@ -1,150 +0,0 @@ -// (C) Copyright 2015 Martin Dougiamas -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -angular.module('mm.addons.mod_assign') - -/** - * Helper to store some temporary data for submission file. - * - * @module mm.addons.mod_assign - * @ngdoc service - * @name $mmaModAssignSubmissionFileSession - */ -.factory('$mmaModAssignSubmissionFileSession', function($mmSite) { - - var self = {}, - files = {}; - - /** - * Add a file to the session. - * - * @module mm.addons.mod_assign - * @ngdoc method - * @name $mmaModAssignSubmissionFileSession#addFile - * @param {Number} assignmentId Assignment ID. - * @param {Object} file File to add. - * @param {String} [siteId] Site ID. If not defined, current site. - * @return {Void} - */ - self.addFile = function(assignmentId, file, siteId) { - siteId = siteId || $mmSite.getId(); - - if (!files[siteId]) { - files[siteId] = {}; - } - - if (!files[siteId][assignmentId]) { - files[siteId][assignmentId] = []; - } - - files[siteId][assignmentId].push(file); - }; - - /** - * Clear files stored in session. - * - * @module mm.addons.mod_assign - * @ngdoc method - * @name $mmaModAssignSubmissionFileSession#clearFiles - * @param {Number} assignmentId Assignment ID. - * @param {String} [siteId] Site ID. If not defined, current site. - * @return {Void} - */ - self.clearFiles = function(assignmentId, siteId) { - siteId = siteId || $mmSite.getId(); - if (files[siteId] && files[siteId][assignmentId]) { - files[siteId][assignmentId] = []; - } - }; - - /** - * Get files stored in session. - * - * @module mm.addons.mod_assign - * @ngdoc method - * @name $mmaModAssignSubmissionFileSession#getFiles - * @param {Number} assignmentId Assignment ID. - * @param {String} [siteId] Site ID. If not defined, current site. - * @return {Object[]} Files in session. - */ - self.getFiles = function(assignmentId, siteId) { - siteId = siteId || $mmSite.getId(); - if (files[siteId] && files[siteId][assignmentId]) { - return files[siteId][assignmentId]; - } - return []; - }; - - /** - * Remove a file stored in session. - * - * @module mm.addons.mod_assign - * @ngdoc method - * @name $mmaModAssignSubmissionFileSession#removeFile - * @param {Number} assignmentId Assignment ID. - * @param {Object} file File to remove. The instance should be exactly the same as the one stored in session. - * @param {String} [siteId] Site ID. If not defined, current site. - * @return {Void} - */ - self.removeFile = function(assignmentId, file, siteId) { - siteId = siteId || $mmSite.getId(); - if (files[siteId] && files[siteId][assignmentId]) { - var position = files[siteId][assignmentId].indexOf(file); - if (position != -1) { - files[siteId][assignmentId].splice(position, 1); - } - } - }; - - /** - * Remove a file stored in session. - * - * @module mm.addons.mod_assign - * @ngdoc method - * @name $mmaModAssignSubmissionFileSession#removeFileByIndex - * @param {Number} assignmentId Assignment ID. - * @param {Number} index Position of the file to remove. - * @param {String} [siteId] Site ID. If not defined, current site. - * @return {Void} - */ - self.removeFileByIndex = function(assignmentId, index, siteId) { - siteId = siteId || $mmSite.getId(); - if (files[siteId] && files[siteId][assignmentId] && index >= 0 && index < files[siteId][assignmentId].length) { - files[siteId][assignmentId].splice(index, 1); - } - }; - - /** - * Set a group of files in the session. - * - * @module mm.addons.mod_assign - * @ngdoc method - * @name $mmaModAssignSubmissionFileSession#setFiles - * @param {Number} assignmentId Assignment ID. - * @param {Object[]} newFiles Files to set. - * @param {String} [siteId] Site ID. If not defined, current site. - * @return {Void} - */ - self.setFiles = function(assignmentId, newFiles, siteId) { - siteId = siteId || $mmSite.getId(); - - if (!files[siteId]) { - files[siteId] = {}; - } - - files[siteId][assignmentId] = newFiles; - }; - - return self; -}); diff --git a/www/addons/mod/book/controllers/index.js b/www/addons/mod/book/controllers/index.js index 8ab97e48515..9677627c1d4 100644 --- a/www/addons/mod/book/controllers/index.js +++ b/www/addons/mod/book/controllers/index.js @@ -56,8 +56,8 @@ angular.module('mm.addons.mod_book') $mmCourse.checkModuleCompletion(courseId, module.completionstatus); } }); - }).catch(function() { - $mmUtil.showErrorModal('mma.mod_book.errorchapter', true); + }).catch(function(error) { + $mmUtil.showErrorModalDefault(error, 'mma.mod_book.errorchapter', true); return $q.reject(); }).finally(function() { $scope.loaded = true; diff --git a/www/addons/mod/book/lang/es_mx.json b/www/addons/mod/book/lang/es_mx.json deleted file mode 100644 index d5d45d924a2..00000000000 --- a/www/addons/mod/book/lang/es_mx.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "errorchapter": "Error al leer capítulo del libro." -} \ No newline at end of file diff --git a/www/addons/mod/book/lang/pt_br.json b/www/addons/mod/book/lang/pt_br.json deleted file mode 100644 index 4c5835d59ae..00000000000 --- a/www/addons/mod/book/lang/pt_br.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "errorchapter": "Erro ao ler capítulo de livro." -} \ No newline at end of file diff --git a/www/addons/mod/book/lang/zh_cn.json b/www/addons/mod/book/lang/zh_cn.json deleted file mode 100644 index 52b287ee7da..00000000000 --- a/www/addons/mod/book/lang/zh_cn.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "errorchapter": "读取图书章节发生错误。" -} \ No newline at end of file diff --git a/www/addons/mod/book/lang/zh_tw.json b/www/addons/mod/book/lang/zh_tw.json deleted file mode 100644 index 32642d09bd0..00000000000 --- a/www/addons/mod/book/lang/zh_tw.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "errorchapter": "讀取章節發生錯誤" -} \ No newline at end of file diff --git a/www/addons/mod/chat/lang/cs.json b/www/addons/mod/chat/lang/cs.json index 5a2dbd232b7..a0e6fc3cd3b 100644 --- a/www/addons/mod/chat/lang/cs.json +++ b/www/addons/mod/chat/lang/cs.json @@ -14,6 +14,6 @@ "mustbeonlinetosendmessages": "Pro odesílání zpráv musíte být online", "nomessages": "Zatím žádné zprávy", "send": "Odeslat", - "sessionstart": "Další chatování začne v {{$a}}, (za {{$a.fromnow}})", + "sessionstart": "Další chatování začne v: {{$a.date}} (tj. za {{$a.fromnow}})", "talk": "Diskuse" } \ No newline at end of file diff --git a/www/addons/mod/chat/lang/de.json b/www/addons/mod/chat/lang/de.json index 9f7bc7161e6..77a921dd9cc 100644 --- a/www/addons/mod/chat/lang/de.json +++ b/www/addons/mod/chat/lang/de.json @@ -14,6 +14,6 @@ "mustbeonlinetosendmessages": "Sie müssen online sein, um Mitteilungen zu senden", "nomessages": "Keine Mitteilungen", "send": "Senden", - "sessionstart": "Nächster Chat beginnt am {{$a.date}}. ({{$a.fromnow}} von jetzt)", + "sessionstart": "Nächster Chat beginnt {{$a.date}}, (also in {{$a.fromnow}})", "talk": "Sprechen" } \ No newline at end of file diff --git a/www/addons/mod/chat/lang/es_mx.json b/www/addons/mod/chat/lang/es_mx.json deleted file mode 100644 index d3e0fbd4d66..00000000000 --- a/www/addons/mod/chat/lang/es_mx.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "beep": "Bip", - "currentusers": "Usuarios", - "enterchat": "Entrar a la sala", - "entermessage": "Escriba su mensaje", - "messagebeepsyou": "{{$a}} le acaba de enviar un beep", - "messageenter": "{{$a}} entró a la sala", - "messageexit": "{{$a}} salió de la sala", - "nomessages": "Aún no hay mensajes", - "send": "Enviar", - "sessionstart": "La siguiente sesión de chat comenzará en: {{$a}}", - "talk": "Charla" -} \ No newline at end of file diff --git a/www/addons/mod/chat/lang/he.json b/www/addons/mod/chat/lang/he.json index 8cd72c5f92d..129855c2b7c 100644 --- a/www/addons/mod/chat/lang/he.json +++ b/www/addons/mod/chat/lang/he.json @@ -10,6 +10,6 @@ "mustbeonlinetosendmessages": "עליך להיות מחובר בכדי לשלוח הודעות.", "nomessages": "אין הודעות עדיין", "send": "שליחה", - "sessionstart": "מפגש הרב-שיח הבא יתחיל ב: {{$a}}", + "sessionstart": "מפגש הרב-שיח הבא יתחיל ב: {{$a.date}}, ({{$a.fromnow}} מעכשיו)", "talk": "דברו" } \ No newline at end of file diff --git a/www/addons/mod/chat/lang/ja.json b/www/addons/mod/chat/lang/ja.json index 052232c43bf..37dd5b0164d 100644 --- a/www/addons/mod/chat/lang/ja.json +++ b/www/addons/mod/chat/lang/ja.json @@ -3,10 +3,15 @@ "currentusers": "現在のユーザ", "enterchat": "ここをクリックしてチャットルームに入室する", "entermessage": "あなたのメッセージを入力してください。", - "errorwhilesendingmessage": "メッセージの送信中にエラーが発生しました。後で再度お試しください。", + "errorwhileconnecting": "チャットに接続する際にエラーが発生しました。", + "errorwhilegettingchatdata": "チャットのデータを取得中にエラーが発生しました。", + "errorwhilegettingchatusers": "チャットのユーザを取得中にエラーが発生しました。", + "errorwhileretrievingmessages": "サーバからメッセージを取得中にエラーが発生しました。", + "errorwhilesendingmessage": "メッセージ送信中にエラーが発生しました。", "messagebeepsyou": "{{$a}} があなたにビープしました!", "messageenter": "このチャットに {{$a}} が入室しました。", "messageexit": "このチャットから {{$a}} が退室しました。", + "mustbeonlinetosendmessages": "メッセージを送信するにはオンラインでなければなりません。", "nomessages": "メッセージがありません。", "send": "送信", "sessionstart": "次のチャットセッションは {{$a.date}} に開始されます (現在から {{$a.fromnow}} 後)。", diff --git a/www/addons/mod/chat/lang/lt.json b/www/addons/mod/chat/lang/lt.json index 0eb4caa16f1..b71c2b82006 100644 --- a/www/addons/mod/chat/lang/lt.json +++ b/www/addons/mod/chat/lang/lt.json @@ -14,6 +14,6 @@ "mustbeonlinetosendmessages": "Norėdamas išsiųsti žinutę, turite būti prisijungęs.", "nomessages": "Žinučių dar nėra", "send": "Siųsti", - "sessionstart": "Pokalbio seansas bus pradėtas po: {{$a}}", + "sessionstart": "Kitas pokalbio seansas prasidės {{$a.date}}, ({{$a.fromnow}} nuo dabar)", "talk": "Kalbėti" } \ No newline at end of file diff --git a/www/addons/mod/chat/lang/pl.json b/www/addons/mod/chat/lang/pl.json index b1a54b073ef..f8fbf09ec3f 100644 --- a/www/addons/mod/chat/lang/pl.json +++ b/www/addons/mod/chat/lang/pl.json @@ -9,6 +9,6 @@ "messageexit": "{{$a}} opuścił czat", "nomessages": "Brak wiadomości", "send": "Wyślij", - "sessionstart": "Sesja czatu rozpocznie się za: {$ a}}", + "sessionstart": "Sesja czatu rozpocznie się {{$a.date}}, za ({{$a.fromnow}}", "talk": "Dyskusja" } \ No newline at end of file diff --git a/www/addons/mod/chat/lang/pt-br.json b/www/addons/mod/chat/lang/pt-br.json index 474fea465ec..eca3a53a9e6 100644 --- a/www/addons/mod/chat/lang/pt-br.json +++ b/www/addons/mod/chat/lang/pt-br.json @@ -14,6 +14,6 @@ "mustbeonlinetosendmessages": "Você deve estar online para enviar mensagens", "nomessages": "Nenhuma mensagem ainda", "send": "Enviar", - "sessionstart": "A próxima sessão de chat irá começar em {{$a}}", + "sessionstart": "A próxima sessão de chat irá começar em {{$a.date}}, ({{$a.fromnow}} a partir de agora)", "talk": "Falar" } \ No newline at end of file diff --git a/www/addons/mod/chat/lang/pt_br.json b/www/addons/mod/chat/lang/pt_br.json deleted file mode 100644 index af36af4277c..00000000000 --- a/www/addons/mod/chat/lang/pt_br.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "beep": "Bip", - "currentusers": "Usuários atuais", - "enterchat": "Clique aqui para entrar no chat agora", - "entermessage": "Digite sua mensagem", - "messagebeepsyou": "{{$a}} está bipando você!", - "messageenter": "{{$a}} entrou no chat", - "messageexit": "{{$a}} abandonou este chat", - "nomessages": "Nenhuma mensagem ainda", - "send": "Enviar", - "sessionstart": "A próxima sessão de chat irá começar em {{$a}}", - "talk": "Falar" -} \ No newline at end of file diff --git a/www/addons/mod/chat/lang/sr-cr.json b/www/addons/mod/chat/lang/sr-cr.json new file mode 100644 index 00000000000..be3c293d91c --- /dev/null +++ b/www/addons/mod/chat/lang/sr-cr.json @@ -0,0 +1,19 @@ +{ + "beep": "Звучни сигнал", + "currentusers": "Тренутни корисници", + "enterchat": "Кликните овде за улазак у причаоницу", + "entermessage": "Унесите вашу поруку", + "errorwhileconnecting": "Грешка приликом повезивања са причаоницом.", + "errorwhilegettingchatdata": "Грешка приликом преузимања података за 'Причаоницу'.", + "errorwhilegettingchatusers": "Грешка приликом преузимања корисника причаонице.", + "errorwhileretrievingmessages": "Грешка приликом преузимања порука са сервера.", + "errorwhilesendingmessage": "Грешка приликом слања поруке.", + "messagebeepsyou": "{{$a}} вас је управо поздравио/ла звучним сигналом!", + "messageenter": "Учесник {{$a}} управо улази у причаоницу", + "messageexit": "Учесник {{$a}} управо напушта причаоницу", + "mustbeonlinetosendmessages": "Морате бити онлајн како бисте слали поруке.", + "nomessages": "Још нема порука", + "send": "Пошаљи", + "sessionstart": "Следећа сесија ће почети дана {{$a.date}}, ({{$a.fromnow}} од сада)", + "talk": "Причај" +} \ No newline at end of file diff --git a/www/addons/mod/chat/lang/sr-lt.json b/www/addons/mod/chat/lang/sr-lt.json new file mode 100644 index 00000000000..dca8b6cbd39 --- /dev/null +++ b/www/addons/mod/chat/lang/sr-lt.json @@ -0,0 +1,19 @@ +{ + "beep": "Zvučni signal", + "currentusers": "Trenutni korisnici", + "enterchat": "Kliknite ovde za ulazak u pričaonicu", + "entermessage": "Unesite vašu poruku", + "errorwhileconnecting": "Greška prilikom povezivanja sa pričaonicom.", + "errorwhilegettingchatdata": "Greška prilikom preuzimanja podataka za 'Pričaonicu'.", + "errorwhilegettingchatusers": "Greška prilikom preuzimanja korisnika pričaonice.", + "errorwhileretrievingmessages": "Greška prilikom preuzimanja poruka sa servera.", + "errorwhilesendingmessage": "Greška prilikom slanja poruke.", + "messagebeepsyou": "{{$a}} vas je upravo pozdravio/la zvučnim signalom!", + "messageenter": "Učesnik {{$a}} upravo ulazi u pričaonicu", + "messageexit": "Učesnik {{$a}} upravo napušta pričaonicu", + "mustbeonlinetosendmessages": "Morate biti onlajn kako biste slali poruke.", + "nomessages": "Još nema poruka", + "send": "Pošalji", + "sessionstart": "Sledeća sesija će početi dana {{$a.date}}, ({{$a.fromnow}} od sada)", + "talk": "Pričaj" +} \ No newline at end of file diff --git a/www/addons/mod/chat/lang/sv.json b/www/addons/mod/chat/lang/sv.json index cc26779e559..d5a2d85343a 100644 --- a/www/addons/mod/chat/lang/sv.json +++ b/www/addons/mod/chat/lang/sv.json @@ -1,14 +1,14 @@ { - "beep": "pipsignal", + "beep": "Pipsignal", "currentusers": "Aktuella användare", "enterchat": "Klicka här för att gå in i direktsamtalet nu", - "entermessage": "Sriv ditt meddelande", + "entermessage": "Skriv ditt meddelande", "errorwhileconnecting": "Fel vid anslutning till chatten", "errorwhilegettingchatdata": "Fel vid vid hämtning av chattdata", "errorwhilegettingchatusers": "Fel vid vid hämtning av chattanvändare", "errorwhileretrievingmessages": "Fel vid hämtning av meddelanden från servern", "errorwhilesendingmessage": "Fel när meddelandet skickades", - "messagebeepsyou": "{{$a}} har just skickat en pipsignal till Dig", + "messagebeepsyou": "{{$a}} har just skickat en pipsignal till dig", "messageenter": "{{$a}} har precis kommit in i detta direktsamtal", "messageexit": "{{$a}} har lämnat det här direktsamtalet", "mustbeonlinetosendmessages": "Du måste vara online för att skicka meddelanden", diff --git a/www/addons/mod/chat/lang/uk.json b/www/addons/mod/chat/lang/uk.json index 66503297072..ab756410d89 100644 --- a/www/addons/mod/chat/lang/uk.json +++ b/www/addons/mod/chat/lang/uk.json @@ -6,8 +6,8 @@ "errorwhileconnecting": "Помилка при підключенні до чату.", "errorwhilegettingchatdata": "Помилка отримання даних чату.", "errorwhilegettingchatusers": "Помилка отримання користувачів чату.", - "errorwhileretrievingmessages": "Помилка отримання повідомлень з серверу", - "errorwhilesendingmessage": "Помилка відправки повідомлення", + "errorwhileretrievingmessages": "Помилка отримання повідомлень з серверу.", + "errorwhilesendingmessage": "Помилка відправки повідомлення.", "messagebeepsyou": "{{$a}} відправив Вам сигнал!", "messageenter": "{{$a}} з'явився в чаті", "messageexit": "{{$a}} пішов із чату", diff --git a/www/addons/mod/chat/lang/zh_cn.json b/www/addons/mod/chat/lang/zh_cn.json deleted file mode 100644 index b8c1f9af432..00000000000 --- a/www/addons/mod/chat/lang/zh_cn.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "beep": "呼叫", - "currentusers": "当前用户", - "enterchat": "进入聊天室", - "entermessage": "输入您的信息", - "messagebeepsyou": "{{$a}}刚刚呼叫您!", - "messageenter": "{{$a}}刚刚进入聊天室", - "messageexit": "{{$a}}已退出聊天室", - "nomessages": "无消息", - "send": "发送", - "sessionstart": "聊天会话开始时间:{{$a}}", - "talk": "交谈" -} \ No newline at end of file diff --git a/www/addons/mod/chat/lang/zh_tw.json b/www/addons/mod/chat/lang/zh_tw.json deleted file mode 100644 index 511cfbb8352..00000000000 --- a/www/addons/mod/chat/lang/zh_tw.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "beep": "呼叫", - "currentusers": "當前用戶", - "enterchat": "點選這裡進入聊天室", - "entermessage": "輸入您的訊息", - "messagebeepsyou": "{{$a}} 呼叫您", - "messageenter": "{{$a}} 剛加入這次聊天", - "messageexit": "{{$a}} 已退出這次聊天", - "nomessages": "尚無訊息", - "send": "傳送", - "sessionstart": "下一個對話時段將開始於:{{$a}}", - "talk": "交談" -} \ No newline at end of file diff --git a/www/addons/mod/choice/lang/ar.json b/www/addons/mod/choice/lang/ar.json index 60ff70d91f6..507d25fbe0c 100644 --- a/www/addons/mod/choice/lang/ar.json +++ b/www/addons/mod/choice/lang/ar.json @@ -4,7 +4,7 @@ "full": "(كامل)", "noresultsviewable": "حالياً لا يمكن معاينة النتائج", "notopenyet": "عذرا، هذا النشاط سيكون متوفر في {{$a}}", - "numberofuser": "عدد المستخدمين", + "numberofuser": "عدد المشاركين", "numberofuserinpercentage": "عدد المستخدمين كنسبة", "removemychoice": "استبعد خياري", "responses": "إجابات", diff --git a/www/addons/mod/choice/lang/ca.json b/www/addons/mod/choice/lang/ca.json index fc6af3e2e89..c0a93b72130 100644 --- a/www/addons/mod/choice/lang/ca.json +++ b/www/addons/mod/choice/lang/ca.json @@ -6,8 +6,8 @@ "full": "(Complet)", "noresultsviewable": "A hores d'ara no es poden veure els resultats", "notopenyet": "Aquesta activitat no estarà disponible fins al dia {{$a}}", - "numberofuser": "Nombre de participants", - "numberofuserinpercentage": "Percentatge de participants", + "numberofuser": "Nombre de respostes", + "numberofuserinpercentage": "Percentatge de respostes (%)", "previewonly": "Això és sols una vista prèvia de les opcions disponibles en aquesta activitat. No esteu habilitat per enviar consultes fins {{$a}}.", "removemychoice": "Suprimeix la meva resposta", "responses": "Respostes", diff --git a/www/addons/mod/choice/lang/da.json b/www/addons/mod/choice/lang/da.json index e462afcd51a..3ef6b107e4d 100644 --- a/www/addons/mod/choice/lang/da.json +++ b/www/addons/mod/choice/lang/da.json @@ -6,8 +6,8 @@ "full": "(Fuld)", "noresultsviewable": "Resultaterne er ikke tilgængelige på nuværende tidspunkt.", "notopenyet": "Denne aktivitet er tilgængelig fra {{$a}}", - "numberofuser": "Antal svar", - "numberofuserinpercentage": "Antal svar i procent", + "numberofuser": "Antal deltagere", + "numberofuserinpercentage": "Procentdel af deltagerne", "previewonly": "Dette er en forhåndsvisning af de tilgængelige valgmuligheder i denne afstemning. Du kan ikke indsende dine valg før {{$a}}.", "removemychoice": "Slet mit valg", "responses": "Besvarelser", diff --git a/www/addons/mod/choice/lang/es-mx.json b/www/addons/mod/choice/lang/es-mx.json index 41b15bb932f..ceddb82adc6 100644 --- a/www/addons/mod/choice/lang/es-mx.json +++ b/www/addons/mod/choice/lang/es-mx.json @@ -6,8 +6,8 @@ "full": "(Lleno)", "noresultsviewable": "Los resultados no pueden verse en este momento.", "notopenyet": "Lo sentimos, esta actividad no estará disponible hasta {{$a}}", - "numberofuser": "Número de participantes", - "numberofuserinpercentage": "Porcentaje de participantes", + "numberofuser": "Número de respuestas", + "numberofuserinpercentage": "Porcentaje de respuestas", "previewonly": "Esto es solamente una vista previa de las opciones disponibles para esta actividad. Usted no podrá enviar su elección hasta {{$a}}.", "removemychoice": "Eliminar mi elección", "responses": "Respuestas", diff --git a/www/addons/mod/choice/lang/ja.json b/www/addons/mod/choice/lang/ja.json index 02afe740bcd..5f5b78343c7 100644 --- a/www/addons/mod/choice/lang/ja.json +++ b/www/addons/mod/choice/lang/ja.json @@ -1,16 +1,19 @@ { "cannotsubmit": "申し訳ございません、あなたの投票送信時に問題が発生しました。再度お試しください。", "choiceoptions": "投票オプション", + "errorgetchoice": "選択データの取得中にエラーが発生しました。", "expired": "申し訳ございません、この活動は {{$a}} に終了しているため、これ以上利用することはできません。", "full": "(上限到達)", "noresultsviewable": "現在、投票結果は閲覧できません。", "notopenyet": "申し訳ございません、この活動は {{$a}} まで利用することができません。", - "numberofuser": "投票者数", - "numberofuserinpercentage": "投票者数 (%)", + "numberofuser": "参加者数", + "numberofuserinpercentage": "参加者の割合", "previewonly": "これはこの活動で利用可能なオプションのプレビューです。あなたの投票は {{$a}} まで送信することができません。", "removemychoice": "私の投票を削除する", "responses": "投票結果", + "responsesresultgraphdescription": "{{number}}% のユーザが選択肢: {{text}} を選択しました。", "responsesresultgraphheader": "グラフ表示", + "resultsnotsynced": "結果にあなたの最後のレスポンスが含まれていません。更新のため、同期を行ってください。", "savemychoice": "私の投票を保存する", "userchoosethisoption": "このオプションを選択したユーザ", "yourselection": "あなたの投票" diff --git a/www/addons/mod/choice/lang/lt.json b/www/addons/mod/choice/lang/lt.json index 94e682f5d51..ee1bf2c25c3 100644 --- a/www/addons/mod/choice/lang/lt.json +++ b/www/addons/mod/choice/lang/lt.json @@ -6,8 +6,8 @@ "full": "(Visas)", "noresultsviewable": "Rezultatai dabar nematomi.", "notopenyet": "Apgailestaujame, ši veikla negalima iki {{$a}}", - "numberofuser": "Dalyvių skaičius", - "numberofuserinpercentage": "Dalyvių procentas", + "numberofuser": "Atsakymų skaičius", + "numberofuserinpercentage": "Atsakymų procentas", "previewonly": "Tai yra tik šios veiklos galimų variantų peržiūra. Savo pasirinkimo negalėsite pateikti iki {{$a}}.", "removemychoice": "Pašalinti mano pasirinkimą", "responses": "Atsakymai", diff --git a/www/addons/mod/choice/lang/pt-br.json b/www/addons/mod/choice/lang/pt-br.json index f8fbe81990b..e1220130458 100644 --- a/www/addons/mod/choice/lang/pt-br.json +++ b/www/addons/mod/choice/lang/pt-br.json @@ -6,8 +6,8 @@ "full": "(Cheio)", "noresultsviewable": "Não é possível visualizar os resultados neste momento.", "notopenyet": "Esta atividade será acessível a partir de {{$a}}", - "numberofuser": "Número de participantes", - "numberofuserinpercentage": "Porcentagem de participantes", + "numberofuser": "Número de respostas", + "numberofuserinpercentage": "Percentagem de respostas", "previewonly": "Esta é somente uma previsualização das opções dessa atividade. Você somente poderá enviar sua escolha a partir de {{$a}}", "removemychoice": "Remover a minha resposta", "responses": "Respostas", diff --git a/www/addons/mod/choice/lang/pt.json b/www/addons/mod/choice/lang/pt.json index a5b426bc80b..68e628591c5 100644 --- a/www/addons/mod/choice/lang/pt.json +++ b/www/addons/mod/choice/lang/pt.json @@ -6,8 +6,8 @@ "full": "Completa", "noresultsviewable": "Os resultados da sondagem ainda não estão disponíveis.", "notopenyet": "Lamentamos mas esta atividade só estará disponível em {{$a}}", - "numberofuser": "Número de participantes", - "numberofuserinpercentage": "Percentagem de participantes", + "numberofuser": "Número de respostas", + "numberofuserinpercentage": "Percentagem de respostas", "previewonly": "Esta é apenas uma pré-visualização das opções disponíveis para esta atividade. Não poderá submeter a sua escolha até {{$a}}.", "removemychoice": "Apagar a minha resposta", "responses": "Respostas", diff --git a/www/addons/mod/choice/lang/ro.json b/www/addons/mod/choice/lang/ro.json index eb9c1bc300b..2133b57b951 100644 --- a/www/addons/mod/choice/lang/ro.json +++ b/www/addons/mod/choice/lang/ro.json @@ -4,8 +4,8 @@ "full": "(plin)", "noresultsviewable": "În acest moment rezultatele nu pot fi vizualizate.", "notopenyet": "Ne pare rău, această activitate nu este disponibilă mai devreme de {{$a}}", - "numberofuser": "Numărul participanților", - "numberofuserinpercentage": "Procentul participanților", + "numberofuser": "Numărul de răspunsuri", + "numberofuserinpercentage": "Procentajul răspunsurilor", "previewonly": "Acesta este doar o prezentare a opțiunilor existente pentru această activitate. Nu veți putea trimite opțiunea dvs. până la {{$a}}.", "removemychoice": "Șterge alegerea mea", "responses": "Răspunsuri", diff --git a/www/addons/mod/choice/lang/ru.json b/www/addons/mod/choice/lang/ru.json index a8b13940e57..38f9cf75ee3 100644 --- a/www/addons/mod/choice/lang/ru.json +++ b/www/addons/mod/choice/lang/ru.json @@ -2,7 +2,7 @@ "cannotsubmit": "Извините, возникла проблема при отправке Вашего ответа на опрос. Пожалуйста, повторите снова.", "choiceoptions": "Варианты ответа", "errorgetchoice": "Ошибка при получении данных выбора", - "expired": "Извините эта активность закрыта {{$a}} и более недоступна", + "expired": "Извините, этот элемент курса закрыт {{$a}} и более недоступен", "full": "(Заполнено)", "noresultsviewable": "Вы не можете в данный момент просматривать результаты опроса.", "notopenyet": "Извините, данное действие недоступно до {{$a}}", diff --git a/www/addons/mod/choice/lang/sr-cr.json b/www/addons/mod/choice/lang/sr-cr.json new file mode 100644 index 00000000000..10465df2265 --- /dev/null +++ b/www/addons/mod/choice/lang/sr-cr.json @@ -0,0 +1,20 @@ +{ + "cannotsubmit": "Извините, дошло је до проблема приликом чувања одабраног одговора. Молимо покушајте поново.", + "choiceoptions": "Опције за избор", + "errorgetchoice": "Грешка приликом преузимања података за 'Избор'", + "expired": "Нажалост, ова активност је затворена дана {{$a}} и није више доступна", + "full": "(Попуњено)", + "noresultsviewable": "Резултати тренутно нису видљиви.", + "notopenyet": "Нажалост, ова активност није доступна до {{$a}}", + "numberofuser": "Број учесника", + "numberofuserinpercentage": "Проценат учесника", + "previewonly": "Ово је само приказ доступних опција за ову активност. Нећете бити у могућности да извршите одабир до {{$a}}.", + "removemychoice": "Уклони мој избор", + "responses": "Одговори", + "responsesresultgraphdescription": "{{number}}% корисника је изабрало опцију: {{text}}.", + "responsesresultgraphheader": "Графички приказ", + "resultsnotsynced": "Резултати не укључује ваш последњи одговор. Покрените синхронизацију како бисте их ажурирали.", + "savemychoice": "Сачувај мој избор", + "userchoosethisoption": "Корисници који су изабрали ову опцију", + "yourselection": "Ваш избор" +} \ No newline at end of file diff --git a/www/addons/mod/choice/lang/sr-lt.json b/www/addons/mod/choice/lang/sr-lt.json new file mode 100644 index 00000000000..7fc4232b84d --- /dev/null +++ b/www/addons/mod/choice/lang/sr-lt.json @@ -0,0 +1,20 @@ +{ + "cannotsubmit": "Izvinite, došlo je do problema prilikom čuvanja odabranog odgovora. Molimo pokušajte ponovo.", + "choiceoptions": "Opcije za izbor", + "errorgetchoice": "Greška prilikom preuzimanja podataka za 'Izbor'", + "expired": "Nažalost, ova aktivnost je zatvorena dana {{$a}} i nije više dostupna", + "full": "(Popunjeno)", + "noresultsviewable": "Rezultati trenutno nisu vidljivi.", + "notopenyet": "Nažalost, ova aktivnost nije dostupna do {{$a}}", + "numberofuser": "Broj učesnika", + "numberofuserinpercentage": "Procenat učesnika", + "previewonly": "Ovo je samo prikaz dostupnih opcija za ovu aktivnost. Nećete biti u mogućnosti da izvršite odabir do {{$a}}.", + "removemychoice": "Ukloni moj izbor", + "responses": "Odgovori", + "responsesresultgraphdescription": "{{number}}% korisnika je izabralo opciju: {{text}}.", + "responsesresultgraphheader": "Grafički prikaz", + "resultsnotsynced": "Rezultati ne uključuje vaš poslednji odgovor. Pokrenite sinhronizaciju kako biste ih ažurirali.", + "savemychoice": "Sačuvaj moj izbor", + "userchoosethisoption": "Korisnici koji su izabrali ovu opciju", + "yourselection": "Vaš izbor" +} \ No newline at end of file diff --git a/www/addons/mod/choice/lang/sv.json b/www/addons/mod/choice/lang/sv.json index 62217bdb227..9b79b1cc765 100644 --- a/www/addons/mod/choice/lang/sv.json +++ b/www/addons/mod/choice/lang/sv.json @@ -14,6 +14,6 @@ "responsesresultgraphdescription": "{{number}}% Av användarna valde alternativet: {{text}}", "responsesresultgraphheader": "Visa en graf", "savemychoice": "Spara min opinionsundersökning", - "userchoosethisoption": "Användaren väljer detta alternativ", + "userchoosethisoption": "Användare som valt detta alternativ", "yourselection": "Ditt urval" } \ No newline at end of file diff --git a/www/addons/mod/choice/lang/uk.json b/www/addons/mod/choice/lang/uk.json index 3587cc22f86..7c22b1890c7 100644 --- a/www/addons/mod/choice/lang/uk.json +++ b/www/addons/mod/choice/lang/uk.json @@ -1,7 +1,7 @@ { "cannotsubmit": "Вибачте, але трапилася проблема під час збереження вашого вибору. Повторіть, будь ласка, ще раз.", "choiceoptions": "Параметри вибору", - "errorgetchoice": "Помилка при отриманні даних вибору.", + "errorgetchoice": "Помилка при отриманні даних виборки.", "expired": "На жаль, ця діяльність закрита для {{$a}} та більше недоступна", "full": "(Все)", "noresultsviewable": "В даний час результати не можна побачити.", diff --git a/www/addons/mod/choice/lang/zh-tw.json b/www/addons/mod/choice/lang/zh-tw.json index fd45e3f3362..c97305fd6fa 100644 --- a/www/addons/mod/choice/lang/zh-tw.json +++ b/www/addons/mod/choice/lang/zh-tw.json @@ -6,8 +6,8 @@ "full": "(已滿)", "noresultsviewable": "目前無法檢視票選結果", "notopenyet": "抱歉,這個活動在{{$a}}之前不能使用", - "numberofuser": "參與者人數", - "numberofuserinpercentage": "參與者百分比", + "numberofuser": "回應的人數", + "numberofuserinpercentage": "回應人數的百分比", "previewonly": "這只是這一活動的可用選項的預覽。你要等到{{$a}}才可以進行投票。", "removemychoice": "移除我的選擇", "responses": "答覆", diff --git a/www/addons/mod/choice/services/handlers.js b/www/addons/mod/choice/services/handlers.js index 4d9145c5d7f..96c13d47b93 100644 --- a/www/addons/mod/choice/services/handlers.js +++ b/www/addons/mod/choice/services/handlers.js @@ -21,7 +21,7 @@ angular.module('mm.addons.mod_choice') * @ngdoc service * @name $mmaModChoiceHandlers */ -.factory('$mmaModChoiceHandlers', function($mmCourse, $mmaModChoice, $state, $mmContentLinksHelper, $mmUtil, $mmEvents, $mmSite, +.factory('$mmaModChoiceHandlers', function($mmCourse, $mmaModChoice, $state, $mmContentLinksHelper, $mmUtil, $mmEvents, $mmSite, $q, $mmaModChoicePrefetchHandler, $mmCoursePrefetchDelegate, mmCoreDownloading, mmCoreNotDownloaded, mmCoreOutdated, mmaModChoiceComponent, mmCoreEventPackageStatusChanged, mmCoreDownloaded, $mmaModChoiceSync) { var self = {}; @@ -103,9 +103,10 @@ angular.module('mm.addons.mod_choice') // Get download size to ask for confirm if it's high. $mmaModChoicePrefetchHandler.getDownloadSize(module, courseId).then(function(size) { $mmUtil.confirmDownloadSize(size).then(function() { - $mmaModChoicePrefetchHandler.prefetch(module, courseId).catch(function() { + return $mmaModChoicePrefetchHandler.prefetch(module, courseId).catch(function(error) { if (!$scope.$$destroyed) { - $mmUtil.showErrorModal('mm.core.errordownloading', true); + $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true); + return $q.reject(); } }); }).catch(function() { diff --git a/www/addons/mod/data/controllers/edit.js b/www/addons/mod/data/controllers/edit.js new file mode 100644 index 00000000000..90bec456681 --- /dev/null +++ b/www/addons/mod/data/controllers/edit.js @@ -0,0 +1,252 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Data add and edit controller. + * + * @module mm.addons.mod_data + * @ngdoc controller + * @name mmaModDataEditCtrl + */ +.controller('mmaModDataEditCtrl', function($scope, $stateParams, $mmaModData, mmaModDataComponent, $q, $mmUtil, $mmaModDataHelper, + $mmGroups, $ionicHistory, $mmEvents, mmaModDataEventEntryChanged, $mmSite, $translate, $mmFileUploaderHelper, $timeout, + $ionicScrollDelegate, $mmApp, $mmaModDataOffline) { + + var module = $stateParams.module || {}, + courseId = $stateParams.courseid, + data, + scrollView, + offlineActions, + siteId = $mmSite.getId(), + offline = !$mmApp.isOnline(), + entryId = $stateParams.entryid || false, + entry; + + $scope.title = module.name; + $scope.component = mmaModDataComponent; + $scope.databaseLoaded = false; + $scope.selectedGroup = $stateParams.group || 0; + + // Block leaving the view, we want to show a confirm to the user if there's unsaved data. + $mmUtil.blockLeaveView($scope, cancel); + + function fetchEntryData() { + + return $mmaModData.getDatabase(courseId, module.id).then(function(databaseData) { + data = databaseData; + + $scope.title = data.name || $scope.title; + $scope.data = databaseData; + + return $mmaModData.getDatabaseAccessInformation(data.id); + }).then(function(accessData) { + $scope.cssTemplate = $mmaModDataHelper.prefixCSS(data.csstemplate, '.mma-data-entries-' + data.id); + + if (entryId !== false) { + // Adding, get groups because it's not set. + return $mmGroups.getActivityGroupInfo(data.coursemodule, accessData.canmanageentries).then(function(groupInfo) { + $scope.groupInfo = groupInfo; + + // Check selected group is accessible. + if (groupInfo && groupInfo.groups && groupInfo.groups.length > 0) { + var found = false; + for (var x in groupInfo.groups) { + if (groupInfo.groups[x].id == $scope.selectedGroup) { + found = true; + break; + } + } + if (!found) { + $scope.selectedGroup = groupInfo.groups[0].id; + } + } + }); + } + }).then(function() { + return $mmaModDataOffline.getEntryActions(data.id, entryId); + }).then(function(actions) { + offlineActions = actions; + + return $mmaModData.getFields(data.id); + }).then(function(fieldsData) { + $scope.fields = {}; + angular.forEach(fieldsData, function(field) { + $scope.fields[field.id] = field; + }); + + return $mmaModDataHelper.getEntry(data, entryId, offlineActions); + }).then(function(entryData) { + if (entryData) { + entry = entryData.entry; + + // Index contents by fieldid. + var contents = {}; + angular.forEach(entry.contents, function(field) { + contents[field.fieldid] = field; + }); + entry.contents = contents; + } else { + entry = {}; + entry.contents = {}; + } + + return $mmaModDataHelper.applyOfflineActions(entry, offlineActions, $scope.fields); + }).then(function(entryData) { + $scope.entry = entryData; + + $scope.editForm = $mmaModDataHelper.displayEditFields(data.addtemplate, $scope.fields, entry.contents); + }).catch(function(message) { + $mmUtil.showErrorModalDefault(message, 'mm.course.errorgetmodule', true); + return $q.reject(); + }).finally(function() { + $scope.databaseLoaded = true; + }); + } + + // Set group to see the database. + $scope.setGroup = function(groupId) { + $scope.selectedGroup = groupId; + $scope.databaseLoaded = false; + + return fetchEntryData(); + }; + + // Saves data. + $scope.save = function() { + return $mmaModDataHelper.hasEditDataChanged(document.forms['mma-mod_data-edit-form'], $scope.fields, data.id, + $scope.entry.contents).then(function(changed) { + + if (!changed) { + if (entryId) { + return returnToEntryList(); + } else { + // New entry, no changes means no field filled, warn the user. + return $q.reject('mma.mod_data.emptyaddform'); + } + } + + var modal = $mmUtil.showModalLoading('mm.core.sending', true); + + // Create an ID to assign files. + var entryTemp = entryId; + if (typeof entryId == "undefined" || entryId === false) { + entryTemp = - (new Date().getTime()); + } + + return $mmaModDataHelper.getEditDataFromForm(document.forms['mma-mod_data-edit-form'], $scope.fields, data.id, + entryTemp, $scope.entry.contents, offline).catch(function(e) { + if (!offline) { + // Cannot submit in online, prepare for offline usage. + offline = true; + + return $mmaModDataHelper.getEditDataFromForm(document.forms['mma-mod_data-edit-form'], $scope.fields, data.id, + entryTemp, $scope.entry.contents, offline); + } + + return $q.reject(e); + }).then(function(editData) { + + if (editData.length > 0) { + if (entryId !== false) { + return $mmaModData.editEntry(data.id, entryId, courseId, editData, $scope.fields, undefined, offline); + } + return $mmaModData.addEntry(data.id, entryTemp, courseId, editData, $scope.selectedGroup, $scope.fields, undefined, + offline); + } + }).then(function(result) { + if (!result) { + // No field filled, warn the user. + return $q.reject('mma.mod_data.emptyaddform'); + } + + // This is done if entry is updated when editing or creating if not. + if ((entryId !== false && result.updated) || (!entryId && result.newentryid)) { + var promises = []; + + entryId = entryId || result.newentryid; + + promises.push($mmaModData.invalidateEntryData(data.id, entryId, siteId)); + promises.push($mmaModData.invalidateEntriesData(data.id, siteId)); + + return $q.all(promises).then(function() { + $mmEvents.trigger(mmaModDataEventEntryChanged, {dataId: data.id, entryId: entryId, siteId: siteId}); + }).finally(function() { + return returnToEntryList(); + }); + } else { + $scope.errors = {}; + angular.forEach(result.fieldnotifications, function(field) { + for (var x in $scope.fields) { + if ($scope.fields[x].name == field.fieldname) { + $scope.errors[$scope.fields[x].id] = field.notification; + return; + } + } + }); + $timeout(function() { + scrollToFirstError(); + }); + } + }).finally(function() { + modal.dismiss(); + }); + }).catch(function(error) { + $mmUtil.showErrorModalDefault(error, 'Cannot edit entry', true); + return $q.reject(); + }); + }; + + // Scroll to first error. + function scrollToFirstError() { + if (!scrollView) { + scrollView = $ionicScrollDelegate.$getByHandle('mmaModDataEntryScroll'); + } + if (!$mmUtil.scrollToElement(document.body, '.mm-data-error', scrollView)) { + scrollView && scrollView.scrollTop && scrollView.scrollTop(); + } + } + + function returnToEntryList() { + return $mmaModDataHelper.getEditTmpFiles(document.forms['mma-mod_data-edit-form'], $scope.fields, data.id, + $scope.entry.contents).then(function(files) { + $mmFileUploaderHelper.clearTmpFiles(files); + }).finally(function() { + // Go back to discussions list. + $ionicHistory.goBack(); + }); + } + + // Just ask to confirm the lost of data. + function cancel() { + return $mmaModDataHelper.hasEditDataChanged(document.forms['mma-mod_data-edit-form'], $scope.fields, data.id, + $scope.entry.contents).then(function(changed) { + if (!changed) { + return $q.when(); + } + // Show confirmation if some data has been modified. + return $mmUtil.showConfirm($translate('mm.core.confirmcanceledit')); + }).then(function() { + // Delete the local files from the tmp folder. + return $mmaModDataHelper.getEditTmpFiles(document.forms['mma-mod_data-edit-form'], $scope.fields, data.id, + $scope.entry.contents).then(function(files) { + $mmFileUploaderHelper.clearTmpFiles(files); + }); + }); + } + + fetchEntryData(); + +}); diff --git a/www/addons/mod/data/controllers/entry.js b/www/addons/mod/data/controllers/entry.js new file mode 100644 index 00000000000..156098179ec --- /dev/null +++ b/www/addons/mod/data/controllers/entry.js @@ -0,0 +1,236 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Data entry controller. + * + * @module mm.addons.mod_data + * @ngdoc controller + * @name mmaModDataEntryCtrl + */ +.controller('mmaModDataEntryCtrl', function($scope, $stateParams, $mmaModData, mmaModDataComponent, $mmCourse, $q, $mmEvents, + $mmText, $translate, $mmUtil, $mmSite, $mmaModDataHelper, $mmGroups, $ionicScrollDelegate, mmaModDataEventEntryChanged, + $ionicHistory, $mmaModDataOffline, mmaModDataEventAutomSynced) { + + var module = $stateParams.module || {}, + courseId = $stateParams.courseid, + entryId = $stateParams.entryid || false, + page = $stateParams.page || false, + data, + entryChangedObserver, + syncObserver, + scrollView, + access, + offlineActions = []; + + $scope.title = module.name; + $scope.description = module.description; + $scope.moduleUrl = module.url; + $scope.moduleName = $mmCourse.translateModuleName('data'); + $scope.component = mmaModDataComponent; + $scope.databaseLoaded = false; + $scope.selectedGroup = $stateParams.group || 0; + $scope.entries = {}; + + function fetchEntryData(refresh) { + return $mmaModData.getDatabase(courseId, module.id).then(function(databaseData) { + data = databaseData; + + $scope.title = data.name || $scope.title; + $scope.description = data.intro || $scope.description; + $scope.data = databaseData; + + return setEntryIdFromPage(data.id, page, $scope.selectedGroup).then(function() { + return $mmaModData.getDatabaseAccessInformation(data.id); + }); + }).then(function(accessData) { + access = accessData; + return $mmGroups.getActivityGroupInfo(data.coursemodule, accessData.canmanageentries).then(function(groupInfo) { + $scope.groupInfo = groupInfo; + + // Check selected group is accessible. + if (groupInfo && groupInfo.groups && groupInfo.groups.length > 0) { + var found = false; + for (var x in groupInfo.groups) { + if (groupInfo.groups[x].id == $scope.selectedGroup) { + found = true; + break; + } + } + if (!found) { + $scope.selectedGroup = groupInfo.groups[0].id; + } + } + + return $mmaModDataOffline.getEntryActions(data.id, entryId); + }); + }).then(function(actions) { + offlineActions = actions; + $scope.hasOffline = !!offlineActions.length; + + return $mmaModData.getFields(data.id).then(function(fieldsData) { + $scope.fields = {}; + angular.forEach(fieldsData, function(field) { + $scope.fields[field.id] = field; + }); + + return $mmaModDataHelper.getEntry(data, entryId, offlineActions); + }); + }).then(function(entry) { + entry = entry.entry; + $scope.cssTemplate = $mmaModDataHelper.prefixCSS(data.csstemplate, '.mma-data-entries-' + data.id); + + // Index contents by fieldid. + var contents = {}; + angular.forEach(entry.contents, function(field) { + contents[field.fieldid] = field; + }); + entry.contents = contents; + + return $mmaModDataHelper.applyOfflineActions(entry, offlineActions, $scope.fields); + }).then(function(entryData) { + $scope.entry = entryData; + + $scope.entries[entryId] = $scope.entry; + + var actions = $mmaModDataHelper.getActions(data, access, $scope.entry); + + $scope.entryRendered = $mmaModDataHelper.displayShowFields(data.singletemplate, $scope.fields, + $scope.entry, 'show', actions); + $scope.showComments = actions.comments; + + return $mmaModDataHelper.getPageInfoByEntry(data.id, entryId, $scope.selectedGroup).then(function(result) { + $scope.previousId = result.previousId; + $scope.nextId = result.nextId; + }); + }).catch(function(message) { + if (!refresh) { + // Some call failed, retry without using cache since it might be a new activity. + return refreshAllData(); + } + + $mmUtil.showErrorModalDefault(message, 'mm.course.errorgetmodule', true); + return $q.reject(); + }).finally(function() { + scrollTop(); + $scope.databaseLoaded = true; + }); + } + + // Set group to see the database. + $scope.setGroup = function(groupId) { + $scope.selectedGroup = groupId; + $scope.databaseLoaded = false; + + return setEntryIdFromPage(data.id, 0, $scope.selectedGroup).then(function() { + return fetchEntryData(); + }); + }; + + // Go to selected entry without changing state. + $scope.gotoEntry = function(entry) { + entryId = entry; + page = false; + $scope.databaseLoaded = false; + return fetchEntryData(); + + }; + + // Convenience function to refresh all the data. + function refreshAllData() { + var promises = []; + + promises.push($mmaModData.invalidateDatabaseData(courseId)); + if (data) { + promises.push($mmaModData.invalidateEntryData(data.id, entryId)); + promises.push($mmGroups.invalidateActivityGroupInfo(data.coursemodule)); + promises.push($mmaModData.invalidateEntriesData(data.id)); + } + + return $q.all(promises).finally(function() { + return fetchEntryData(true); + }); + } + + // Convenience function to translate page number to entry identifier. + function setEntryIdFromPage(dataId, pageNumber, group) { + if (pageNumber !== false) { + return $mmaModDataHelper.getPageInfoByPage(dataId, pageNumber, group).then(function(result) { + entryId = result.entryId; + page = false; + }); + } + + return $q.when(); + } + + fetchEntryData(); + + // Scroll to top. + function scrollTop() { + if (!scrollView) { + scrollView = $ionicScrollDelegate.$getByHandle('mmaModDataEntryScroll'); + } + scrollView && scrollView.scrollTop && scrollView.scrollTop(); + } + + // Context Menu Description action. + $scope.expandDescription = function() { + $mmText.expandText($translate.instant('mm.core.description'), $scope.description, false, mmaModDataComponent, module.id); + }; + + // Pull to refresh. + $scope.refreshDatabase = function() { + if ($scope.databaseLoaded) { + return refreshAllData().finally(function() { + $scope.$broadcast('scroll.refreshComplete'); + }); + } + }; + + // Refresh entry on change. + entryChangedObserver = $mmEvents.on(mmaModDataEventEntryChanged, function(eventData) { + if (eventData.entryId == entryId && data.id == eventData.dataId && $mmSite.getId() == eventData.siteId) { + if (eventData.deleted) { + // If deleted, go back. + $ionicHistory.goBack(); + } else { + $scope.databaseLoaded = false; + return fetchEntryData(true); + } + } + }); + + // Refresh entry on sync. + syncObserver = $mmEvents.on(mmaModDataEventAutomSynced, function(eventData) { + if ((eventData.entryid == entryId || eventData.offlineentryid == entryId) && data.id == eventData.dataid && + $mmSite.getId() == eventData.siteid) { + if (eventData.deleted) { + // If deleted, go back. + $ionicHistory.goBack(); + } else { + entryId = eventData.entryid; + $scope.databaseLoaded = false; + fetchEntryData(true); + } + } + }); + + $scope.$on('$destroy', function() { + entryChangedObserver && entryChangedObserver.off && entryChangedObserver.off(); + syncObserver && syncObserver.off && syncObserver.off(); + }); +}); diff --git a/www/addons/mod/data/controllers/index.js b/www/addons/mod/data/controllers/index.js new file mode 100644 index 00000000000..65a1ea09c17 --- /dev/null +++ b/www/addons/mod/data/controllers/index.js @@ -0,0 +1,451 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Data index controller. + * + * @module mm.addons.mod_data + * @ngdoc controller + * @name mmaModDataIndexCtrl + */ +.controller('mmaModDataIndexCtrl', function($scope, $stateParams, $mmaModData, mmaModDataComponent, $mmCourse, $mmCourseHelper, $q, + $mmText, $translate, $mmEvents, mmCoreEventOnlineStatusChanged, $mmApp, $mmUtil, $mmSite, $mmaModDataHelper, $mmGroups, + mmaModDataEventEntryChanged, $ionicModal, mmaModDataPerPage, $state, $mmComments, $mmaModDataOffline, $mmaModDataSync, + mmaModDataEventAutomSynced) { + + var module = $stateParams.module || {}, + courseId = $stateParams.courseid, + siteId = $mmSite.getId(), + data, + entryChangedObserver, + onlineObserver, + syncObserver, + hasComments = false; + + $scope.title = module.name; + $scope.description = module.description; + $scope.moduleUrl = module.url; + $scope.moduleName = $mmCourse.translateModuleName('data'); + $scope.refreshIcon = 'spinner'; + $scope.syncIcon = 'spinner'; + $scope.component = mmaModDataComponent; + $scope.databaseLoaded = false; + $scope.selectedGroup = $stateParams.group || 0; + $scope.entries = {}; + + $scope.search = { + sortBy: "0", + sortDirection: "DESC", + page: 0, + text: "", + searching: false, + searchingAdvanced: false, + advanced: {} + }; + + function fetchDatabaseData(refresh, sync, showErrors) { + $scope.isOnline = $mmApp.isOnline(); + + return $mmaModData.getDatabase(courseId, module.id).then(function(databaseData) { + data = databaseData; + + $scope.title = data.name || $scope.title; + $scope.description = data.intro || $scope.description; + $scope.data = databaseData; + + if (sync) { + // Try to synchronize the database. + return syncDatabase(showErrors).catch(function() { + // Ignore errors. + }); + } + }).then(function() { + return $mmaModData.getDatabaseAccessInformation(data.id); + }).then(function(accessData) { + $scope.access = accessData; + + if (!accessData.timeavailable) { + var time = $mmUtil.timestamp(); + + $scope.timeAvailableFrom = data.timeavailablefrom && time < data.timeavailablefrom ? + parseInt(data.timeavailablefrom, 10) * 1000 : false; + $scope.timeAvailableFromReadable = $scope.timeAvailableFrom ? + moment($scope.timeAvailableFrom).format('LLL') : false; + $scope.timeAvailableTo = data.timeavailableto && time > data.timeavailableto ? + parseInt(data.timeavailableto, 10) * 1000 : false; + $scope.timeAvailableToReadable = $scope.timeAvailableTo ? moment($scope.timeAvailableTo).format('LLL') : false; + + $scope.isEmpty = true; + $scope.groupInfo = false; + return false; + } + + $scope.canSearch = true; + $scope.canAdd = accessData.canaddentry; + + return $mmGroups.getActivityGroupInfo(data.coursemodule, accessData.canmanageentries).then(function(groupInfo) { + $scope.groupInfo = groupInfo; + + // Check selected group is accessible. + if (groupInfo && groupInfo.groups && groupInfo.groups.length > 0) { + var found = false; + for (var x in groupInfo.groups) { + if (groupInfo.groups[x].id == $scope.selectedGroup) { + found = true; + break; + } + } + if (!found) { + $scope.selectedGroup = groupInfo.groups[0].id; + } + } + return fetchOfflineEntries(); + }); + }).then(function() { + return $mmaModData.getFields(data.id).then(function(fields) { + if (fields.length == 0) { + $scope.canSearch = false; + $scope.canAdd = false; + } + $scope.search.advanced = {}; + + $scope.fields = {}; + angular.forEach(fields, function(field) { + $scope.fields[field.id] = field; + }); + $scope.advancedSearch = $mmaModDataHelper.displayAdvancedSearchFields(data.asearchtemplate, $scope.fields); + + return fetchEntriesData(); + }); + }).then(function() { + // All data obtained, now fill the context menu. + $mmCourseHelper.fillContextMenu($scope, module, courseId, refresh, mmaModDataComponent); + }).catch(function(message) { + if (!refresh) { + // Some call failed, retry without using cache since it might be a new activity. + return refreshAllData(); + } + + $mmUtil.showErrorModalDefault(message, 'mm.course.errorgetmodule', true); + return $q.reject(); + }).finally(function() { + $scope.databaseLoaded = true; + }); + } + + function fetchOfflineEntries() { + // Check if there are entries stored in offline. + return $mmaModDataOffline.getDatabaseEntries(data.id).then(function(offlineEntries) { + $scope.hasOffline = !!offlineEntries.length; + + $scope.offlineActions = {}; + $scope.offlineEntries = {}; + + // Only show offline entries on first page. + if ($scope.search.page == 0 && $scope.hasOffline) { + angular.forEach(offlineEntries, function(entry) { + if (entry.entryid > 0) { + if (typeof $scope.offlineActions[entry.entryid] == "undefined") { + $scope.offlineActions[entry.entryid] = []; + } + $scope.offlineActions[entry.entryid].push(entry); + } else { + if (typeof $scope.offlineActions[entry.entryid] == "undefined") { + $scope.offlineEntries[entry.entryid] = []; + } + $scope.offlineEntries[entry.entryid].push(entry); + } + }); + } + }); + } + + function fetchEntriesData() { + hasComments = false; + + return $mmaModData.getDatabaseAccessInformation(data.id, $scope.selectedGroup).then(function(accessData) { + // Update values for current group. + $scope.access.canaddentry = accessData.canaddentry; + + if ($scope.search.searching) { + var text = $scope.search.searchingAdvanced ? undefined : $scope.search.text; + advanced = $scope.search.searchingAdvanced ? $scope.search.advanced : undefined; + return $mmaModData.searchEntries(data.id, $scope.selectedGroup, text, advanced, $scope.search.sortBy, + $scope.search.sortDirection, $scope.search.page); + } else { + return $mmaModData.getEntries(data.id, $scope.selectedGroup, $scope.search.sortBy, $scope.search.sortDirection, + $scope.search.page); + } + }).then(function(entries) { + var numEntries = (entries && entries.entries && entries.entries.length) || 0; + $scope.isEmpty = !numEntries && !Object.keys($scope.offlineActions).length && !Object.keys($scope.offlineEntries).length; + $scope.hasNextPage = numEntries >= mmaModDataPerPage && (($scope.search.page + 1) * mmaModDataPerPage) < entries.totalcount; + $scope.entriesRendered = ""; + + if (!$scope.isEmpty) { + $scope.cssTemplate = $mmaModDataHelper.prefixCSS(data.csstemplate, '.mma-data-entries-' + data.id); + + var siteInfo = $mmSite.getInfo(), + promises = []; + + angular.forEach($scope.offlineEntries, function(offlineActions) { + var entry; + + angular.forEach(offlineActions, function(offlineEntry) { + if (offlineEntry.action == 'add') { + entry = { + id: offlineEntry.entryid, + canmanageentry: true, + approved: !data.approval || data.manageapproved, + dataid: offlineEntry.dataid, + groupid: offlineEntry.groupid, + timecreated: -offlineEntry.entryid, + timemodified: -offlineEntry.entryid, + userid: siteInfo.userid, + fullname: siteInfo.fullname, + contents: {} + }; + } + }); + + if (entry) { + if (offlineActions.length > 0) { + promises.push($mmaModDataHelper.applyOfflineActions(entry, offlineActions, $scope.fields)); + } else { + promises.push($q.when(entry)); + } + } + + }); + + angular.forEach(entries.entries, function(entry) { + // Index contents by fieldid. + var contents = {}; + angular.forEach(entry.contents, function(field) { + contents[field.fieldid] = field; + }); + entry.contents = contents; + + if (typeof $scope.offlineActions[entry.id] != "undefined") { + promises.push($mmaModDataHelper.applyOfflineActions(entry, $scope.offlineActions[entry.id], $scope.fields)); + } else { + promises.push($q.when(entry)); + } + }); + + return $q.all(promises).then(function(entries) { + var entriesHTML = data.listtemplateheader; + + angular.forEach(entries, function(entry) { + $scope.entries[entry.id] = entry; + + var actions = $mmaModDataHelper.getActions(data, $scope.access, entry); + + entriesHTML += $mmaModDataHelper.displayShowFields(data.listtemplate, $scope.fields, entry, 'list', actions); + }); + entriesHTML += data.listtemplatefooter; + + $scope.entriesRendered = entriesHTML; + }); + } else if (!$scope.search.searching) { + $scope.canSearch = false; + } + }); + } + + // Set group to see the database. + $scope.setGroup = function(groupId) { + $scope.selectedGroup = groupId; + return fetchEntriesData().catch(function(message) { + $mmUtil.showErrorModalDefault(message, 'mm.course.errorgetmodule', true); + return $q.reject(); + }); + }; + + // Convenience function to refresh all the data. + function refreshAllData(sync, showErrors) { + var promises = []; + + promises.push($mmaModData.invalidateDatabaseData(courseId)); + if (data) { + promises.push($mmaModData.invalidateDatabaseAccessInformationData(data.id)); + promises.push($mmGroups.invalidateActivityGroupInfo(data.coursemodule)); + promises.push($mmaModData.invalidateEntriesData(data.id)); + if (hasComments) { + promises.push($mmComments.invalidateCommentsByInstance('module', data.coursemodule)); + } + } + + return $q.all(promises).finally(function() { + return fetchDatabaseData(true, sync, showErrors); + }); + } + + // Tries to synchronize the database. + function syncDatabase(showErrors) { + return $mmaModDataSync.syncDatabase(data.id).then(function(result) { + if (result.warnings && result.warnings.length) { + $mmUtil.showErrorModal(result.warnings[0]); + } + + return result.updated; + }).catch(function(error) { + if (showErrors) { + $mmUtil.showErrorModalDefault(error, 'mm.core.errorsync', true); + } + return $q.reject(); + }); + } + + fetchDatabaseData(false, true).then(function() { + $mmaModData.logView(data.id).then(function() { + $mmCourse.checkModuleCompletion(courseId, module.completionstatus); + }); + }).finally(function() { + $scope.refreshIcon = 'ion-refresh'; + $scope.syncIcon = 'ion-loop'; + }); + + // Confirm and Remove action. + $scope.removeFiles = function() { + $mmCourseHelper.confirmAndRemove(module, courseId); + }; + + // Context Menu Prefetch action. + $scope.prefetch = function() { + $mmCourseHelper.contextMenuPrefetch($scope, module, courseId); + }; + // Context Menu Description action. + $scope.expandDescription = function() { + $mmText.expandText($translate.instant('mm.core.description'), $scope.description, false, mmaModDataComponent, module.id); + }; + + // Pull to refresh. + $scope.refreshDatabase = function(showErrors) { + if ($scope.databaseLoaded) { + $scope.refreshIcon = 'spinner'; + $scope.syncIcon = 'spinner'; + return refreshAllData(true, showErrors).finally(function() { + $scope.refreshIcon = 'ion-refresh'; + $scope.syncIcon = 'ion-loop'; + $scope.$broadcast('scroll.refreshComplete'); + }); + } + }; + + // Setup search modal. + $ionicModal.fromTemplateUrl('addons/mod/data/templates/search-modal.html', { + scope: $scope, + animation: 'slide-in-up' + }).then(function(searchModal) { + $scope.showSearch = function() { + searchModal.show(); + }; + $scope.closeSearch = function() { + searchModal.hide(); + }; + $scope.$on('$destroy', function() { + searchModal.remove(); + }); + }); + + // Performs the search and closes the modal. + $scope.searchEntries = function(page) { + $scope.closeSearch(); + $scope.databaseLoaded = false; + $scope.search.page = page; + + if ($scope.search.searchingAdvanced) { + $scope.search.advanced = $mmaModDataHelper.getSearchDataFromForm(document.forms['mma-mod_data-advanced-search-form'], + $scope.fields); + $scope.search.searching = $scope.search.advanced.length > 0; + } else { + $scope.search.searching = $scope.search.text.length > 0; + } + return fetchEntriesData().catch(function(message) { + $mmUtil.showErrorModalDefault(message, 'mm.course.errorgetmodule', true); + return $q.reject(); + }).finally(function() { + $scope.databaseLoaded = true; + }); + }; + + // Reset all search filters and closes the modal. + $scope.searchReset = function() { + $scope.search.sortBy = "0"; + $scope.search.sortDirection = "DESC"; + $scope.search.text = ""; + $scope.search.advanced = {}; + $scope.search.searchingAdvanced = false; + $scope.search.searching = false; + $scope.searchEntries(0); + }; + + // Switches between advanced to normal search + $scope.switchAdvanced = function(enable) { + $scope.search.searchingAdvanced = enable; + }; + + // Opens add entries form + $scope.gotoAddEntries = function() { + var stateParams = { + moduleid: module.id, + module: module, + courseid: courseId, + group: $scope.selectedGroup + }; + $state.go('site.mod_data-edit', stateParams); + }; + + $scope.gotoEntry = function(entryId) { + var stateParams = { + module: module, + moduleid: module.id, + courseid: courseId, + entryid: entryId, + group: $scope.selectedGroup + }; + $state.go('site.mod_data-entry', stateParams); + }; + + // Refresh online status when changes. + onlineObserver = $mmEvents.on(mmCoreEventOnlineStatusChanged, function(online) { + $scope.isOnline = online; + }); + + // Refresh entries on change. + entryChangedObserver = $mmEvents.on(mmaModDataEventEntryChanged, function(eventData) { + if (data.id == eventData.dataId && siteId == eventData.siteId) { + $scope.databaseLoaded = false; + return fetchDatabaseData(true); + } + }); + + // Refresh entries on sync. + syncObserver = $mmEvents.on(mmaModDataEventAutomSynced, function(eventData) { + // Update just when all database is synced. + if (data.id == eventData.dataid && siteId == eventData.siteid && typeof eventData.entryid == "undefined") { + $scope.databaseLoaded = false; + fetchDatabaseData(true); + } + }); + + $scope.$on('$destroy', function() { + onlineObserver && onlineObserver.off && onlineObserver.off(); + entryChangedObserver && entryChangedObserver.off && entryChangedObserver.off(); + syncObserver && syncObserver.off && syncObserver.off(); + }); +}); diff --git a/www/addons/mod/data/directives/action.js b/www/addons/mod/data/directives/action.js new file mode 100644 index 00000000000..747edede8f9 --- /dev/null +++ b/www/addons/mod/data/directives/action.js @@ -0,0 +1,56 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Directive to render data action. + * + * @module mm.addons.mod_data + * @ngdoc directive + * @name mmaModDataAction + */ +.directive('mmaModDataAction', function($mmSite, $mmUser, $mmaModDataOffline, $mmEvents, mmaModDataEventEntryChanged) { + return { + restrict: 'E', + priority: 100, + scope: { + action: '@', + database: '=', + entry: '=?', + mode: '@' + }, + templateUrl: 'addons/mod/data/templates/action.html', + link: function(scope) { + scope.url = $mmSite.getURL(); + + if (scope.action == 'userpicture') { + $mmUser.getProfile(scope.entry.userid, scope.database.courseid).then(function(profile) { + scope.userpicture = profile.profileimageurl; + }); + } + + scope.undoDelete = function() { + var dataId = scope.database.id; + entryId = scope.entry.id; + return $mmaModDataOffline.getEntry(dataId, entryId, 'delete').then(function() { + // Found. Just delete the action. + return $mmaModDataOffline.deleteEntry(dataId, entryId, 'delete'); + }).then(function() { + $mmEvents.trigger(mmaModDataEventEntryChanged, {dataId: dataId, entryId: entryId, siteId: $mmSite.getId()}); + }); + }; + } + }; +}); diff --git a/www/addons/mod/data/directives/field.js b/www/addons/mod/data/directives/field.js new file mode 100644 index 00000000000..97039efa03e --- /dev/null +++ b/www/addons/mod/data/directives/field.js @@ -0,0 +1,59 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Directive to render data field. + * + * @module mm.addons.mod_data + * @ngdoc directive + * @name mmaModDataField + */ +.directive('mmaModDataField', function($mmaModDataFieldsDelegate, $compile) { + return { + restrict: 'E', + priority: 100, + scope: { + field: '=', + value: '=?', + database: '=?', + error: '=?', + viewAction: '&?', + mode: '@' + }, + templateUrl: 'addons/mod/data/templates/field.html', + link: function(scope, element) { + var field = scope.field, + container = element[0].querySelector('.mma-mod-data-field-container'), + directive; + + if (!field || !container) { + return; + } + + // Check if the plugin has defined its own directive to render itself. + directive = $mmaModDataFieldsDelegate.getDirectiveForPlugin(field); + + if (directive) { + // Add the directive to the element. + container.setAttribute(directive, ''); + // Compile the new directive. + $compile(container)(scope); + } else { + scope.fieldLoaded = true; + } + } + }; +}); diff --git a/www/addons/mod/data/fields/checkbox/directive.js b/www/addons/mod/data/fields/checkbox/directive.js new file mode 100644 index 00000000000..16e95b2ca4e --- /dev/null +++ b/www/addons/mod/data/fields/checkbox/directive.js @@ -0,0 +1,52 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +.filter('mmaModDataFieldCheckboxFormat', function() { + return function(text) { + return text.split("##").join("
"); + }; +}) + +/** + * Directive to render data checkbox field. + * + * @module mm.addons.mod_data + * @ngdoc directive + * @name mmaModDataFieldCheckbox + */ +.directive('mmaModDataFieldCheckbox', function() { + return { + restrict: 'A', + priority: 100, + templateUrl: 'addons/mod/data/fields/checkbox/template.html', + link: function(scope) { + scope.mode = scope.mode == 'list' ? 'show' : scope.mode; + if (scope.mode == 'show') { + return; + } + + scope.options = scope.field.param1.split("\n"); + + if (scope.mode == 'edit' && scope.value) { + scope.values = {}; + + angular.forEach(scope.value.content.split("##"), function(value) { + scope.values[value] = true; + }); + } + } + }; +}); diff --git a/www/addons/mod/data/fields/checkbox/handler.js b/www/addons/mod/data/fields/checkbox/handler.js new file mode 100644 index 00000000000..d7d89c69554 --- /dev/null +++ b/www/addons/mod/data/fields/checkbox/handler.js @@ -0,0 +1,148 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Handler for checkbox data field plugin. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataFieldCheckboxHandler + */ +.factory('$mmaModDataFieldCheckboxHandler', function($translate) { + + var self = {}; + + /** + * Get field search data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldSearchData = function(field, inputData) { + var fieldName = 'f_' + field.id, + reqName = 'f_' + field.id + '_allreq'; + + var checkboxes = [], + values = []; + angular.forEach(inputData[fieldName], function(value, option) { + if (value) { + checkboxes.push(option); + } + }); + if (checkboxes.length > 0) { + values.push({ + name: fieldName, + value: checkboxes + }); + + if (inputData[reqName]['1']) { + values.push({ + name: reqName, + value: true + }); + } + return values; + } + + return false; + }; + + /** + * Get field edit data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldEditData = function(field, inputData) { + var fieldName = 'f_' + field.id; + + var checkboxes = []; + angular.forEach(inputData[fieldName], function(value, option) { + if (value) { + checkboxes.push(option); + } + }); + if (checkboxes.length > 0) { + return [{ + fieldid: field.id, + value: checkboxes + }]; + } + + return false; + }; + + /** + * Get field data in changed. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @param {Object} originalFieldData Original field entered data. + * @return {Boolean} If the field has changes. + */ + self.hasFieldDataChanged = function(field, inputData, originalFieldData) { + var fieldName = 'f_' + field.id, + checkboxes = []; + + angular.forEach(inputData[fieldName], function(value, option) { + if (value) { + checkboxes.push(option); + } + }); + + originalFieldData = (originalFieldData && originalFieldData.content) || ""; + return checkboxes.join("##") != originalFieldData; + }; + + /** + * Check and get field requeriments. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {String} String with the notification or false. + */ + self.getFieldsNotifications = function(field, inputData) { + if (field.required && (!inputData || !inputData.length || !inputData[0].value)) { + return $translate.instant('mma.mod_data.errormustsupplyvalue'); + } + return false; + }; + + /** + * Override field content data with offline submission. + * + * @param {Object} originalContent Original data to be overriden. + * @param {Array} offlineContent Array with all the offline data to override. + * @return {Object} Data overriden + */ + self.overrideData = function(originalContent, offlineContent) { + originalContent.content = (offlineContent[''] && offlineContent[''].join("##")) || ""; + return originalContent; + }; + + return self; +}) + +.run(function($mmAddonManager) { + // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons, + // since they cannot assume that the data addon will be packaged in custom apps. + var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate'); + if ($mmaModDataFieldsDelegate) { + $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldCheckbox', 'checkbox', '$mmaModDataFieldCheckboxHandler'); + } +}); diff --git a/www/addons/mod/data/fields/checkbox/template.html b/www/addons/mod/data/fields/checkbox/template.html new file mode 100644 index 00000000000..82c3ac440c3 --- /dev/null +++ b/www/addons/mod/data/fields/checkbox/template.html @@ -0,0 +1,7 @@ + + + {{ error }} + {{ option }} + {{ 'mma.mod_data.selectedrequired' | translate }} + +{{ value.content | mmaModDataFieldCheckboxFormat }} \ No newline at end of file diff --git a/www/addons/mod/data/fields/date/directive.js b/www/addons/mod/data/fields/date/directive.js new file mode 100644 index 00000000000..9626c53b9f0 --- /dev/null +++ b/www/addons/mod/data/fields/date/directive.js @@ -0,0 +1,52 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +.filter('mmaModDataFieldDateFormat', function() { + return function(text) { + return text * 1000; + }; +}) + +/** + * Directive to render data date field. + * + * @module mm.addons.mod_data + * @ngdoc directive + * @name mmaModDataFieldDate + */ +.directive('mmaModDataFieldDate', function() { + return { + restrict: 'A', + priority: 100, + templateUrl: 'addons/mod/data/fields/date/template.html', + link: function(scope) { + scope.mode = scope.mode == 'list' ? 'show' : scope.mode; + if (scope.mode == 'show') { + return; + } + + if (scope.mode == 'edit' && scope.value) { + scope.enable = true; + } else { + scope.value = { + content: Math.floor(Date.now() / 1000) + }; + scope.enable = false; + } + scope.val = new Date(scope.value.content * 1000); + } + }; +}); diff --git a/www/addons/mod/data/fields/date/handler.js b/www/addons/mod/data/fields/date/handler.js new file mode 100644 index 00000000000..a41d81653e3 --- /dev/null +++ b/www/addons/mod/data/fields/date/handler.js @@ -0,0 +1,161 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Handler for date data field plugin. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataFieldDateHandler + */ +.factory('$mmaModDataFieldDateHandler', function($translate) { + + var self = {}; + + /** + * Get field search data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldSearchData = function(field, inputData) { + var fieldName = 'f_' + field.id, + enabledName = fieldName + '_z'; + + if (inputData[enabledName]['1']) { + var values = [], + date = inputData[fieldName].split('-'), + year = date[0], + month = date[1], + day = date[2]; + values.push({ + name: fieldName + '_y', + value: year + }); + values.push({ + name: fieldName + '_m', + value: month + }); + values.push({ + name: fieldName + '_d', + value: day + }); + values.push({ + name: enabledName, + value: 1 + }); + return values; + } + return false; + }; + + /** + * Get field edit data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldEditData = function(field, inputData) { + var fieldName = 'f_' + field.id; + + if (inputData[fieldName]) { + var values = [], + date = inputData[fieldName].split('-'), + year = date[0], + month = date[1], + day = date[2]; + values.push({ + fieldid: field.id, + subfield: 'year', + value: year + }); + values.push({ + fieldid: field.id, + subfield: 'month', + value: month + }); + values.push({ + fieldid: field.id, + subfield: 'day', + value: day + }); + return values; + } + return false; + }; + + /** + * Get field data in changed. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @param {Object} originalFieldData Original field entered data. + * @return {Boolean} If the field has changes. + */ + self.hasFieldDataChanged = function(field, inputData, originalFieldData) { + var fieldName = 'f_' + field.id, + input = inputData[fieldName] || ""; + + originalFieldData = (originalFieldData && originalFieldData.content && + new Date(originalFieldData.content * 1000).toISOString().substr(0, 10)) || ""; + + return input != originalFieldData; + }; + + /** + * Check and get field requeriments. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {String} String with the notification or false. + */ + self.getFieldsNotifications = function(field, inputData) { + if (field.required && + (!inputData || inputData.length < 2 || !inputData[0].value || !inputData[1].value || !inputData[2].value)) { + return $translate.instant('mma.mod_data.errormustsupplyvalue'); + } + return false; + }; + + /** + * Override field content data with offline submission. + * + * @param {Object} originalContent Original data to be overriden. + * @param {Array} offlineContent Array with all the offline data to override. + * @return {Object} Data overriden + */ + self.overrideData = function(originalContent, offlineContent) { + var date = Date.UTC(offlineContent.year || "", offlineContent.month ? offlineContent.month - 1 : "", + offlineContent.day || ""); + date = Math.floor(date / 1000); + + originalContent.content = date || ""; + return originalContent; + }; + + return self; +}) + +.run(function($mmAddonManager) { + // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons, + // since they cannot assume that the data addon will be packaged in custom apps. + var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate'); + if ($mmaModDataFieldsDelegate) { + $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldDate', 'date', '$mmaModDataFieldDateHandler'); + } +}); diff --git a/www/addons/mod/data/fields/date/template.html b/www/addons/mod/data/fields/date/template.html new file mode 100644 index 00000000000..783d1fc842b --- /dev/null +++ b/www/addons/mod/data/fields/date/template.html @@ -0,0 +1,5 @@ + +{{ error }} + +{{ 'mma.mod_data.usedate' | translate }} +{{ value.content | mmaModDataFieldDateFormat | mmFormatDate:"dfdaymonthyear" }} \ No newline at end of file diff --git a/www/addons/mod/data/fields/file/directive.js b/www/addons/mod/data/fields/file/directive.js new file mode 100644 index 00000000000..238d362ce52 --- /dev/null +++ b/www/addons/mod/data/fields/file/directive.js @@ -0,0 +1,68 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Directive to render data file field. + * + * @module mm.addons.mod_data + * @ngdoc directive + * @name mmaModDataFieldFile + */ +.directive('mmaModDataFieldFile', function($mmFileSession, mmaModDataComponent) { + + /** + * Get the files from the input value. + * + * @param {Object} value Input value. + * @return {Object[]} List of files. + */ + function getFiles(value) { + var files = (value && value.files) || []; + + // Reduce to first element. + if (files.length > 0) { + files = [files[0]]; + } + + return files; + } + + return { + restrict: 'A', + priority: 100, + templateUrl: 'addons/mod/data/fields/file/template.html', + link: function(scope) { + scope.mode = scope.mode == 'list' ? 'show' : scope.mode; + if (scope.mode == 'show' || scope.mode == 'edit') { + scope.component = mmaModDataComponent; + scope.componentId = scope.database.coursemodule; + + if (scope.mode == 'show') { + // Displaying the list of files, watch the value to update the list if it changes. + scope.$watch('value', function(newValue) { + scope.files = getFiles(newValue); + }); + } else { + // Edit mode, the list shouldn't change so there is no need to watch it. + scope.files = getFiles(scope.value); + + scope.maxSizeBytes = parseInt(scope.field.param3, 10); + $mmFileSession.setFiles(mmaModDataComponent, scope.database.id + '_' + scope.field.id, scope.files); + } + } + } + }; +}); diff --git a/www/addons/mod/data/fields/file/handler.js b/www/addons/mod/data/fields/file/handler.js new file mode 100644 index 00000000000..9785294c354 --- /dev/null +++ b/www/addons/mod/data/fields/file/handler.js @@ -0,0 +1,137 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Handler for file data field plugin. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataFieldFileHandler + */ +.factory('$mmaModDataFieldFileHandler', function($mmFileSession, mmaModDataComponent, $mmFileUploaderHelper, $translate) { + + var self = {}; + + /** + * Get field search data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldSearchData = function(field, inputData) { + var fieldName = 'f_' + field.id; + if (inputData[fieldName]) { + return [{ + name: fieldName, + value: inputData[fieldName] + }]; + } + return false; + }; + + /** + * Get field edit data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @return {Promise} With name and value of the data to be sent. + */ + self.getFieldEditData = function(field) { + var files = self.getFieldEditFiles(field); + if (files.length) { + return [{ + fieldid: field.id, + subfield: 'file', + files: files + }]; + } + return false; + }; + + /** + * Get field edit files in the input data. + * + * @param {Object} field Defines the field.. + * @return {Promise} With name and value of the data to be sent. + */ + self.getFieldEditFiles = function(field) { + return $mmFileSession.getFiles(mmaModDataComponent, field.dataid + '_' + field.id); + }; + + /** + * Get field data in changed. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @param {Object} originalFieldData Original field entered data. + * @return {Boolean} If the field has changes. + */ + self.hasFieldDataChanged = function(field, inputData, originalFieldData) { + var files = $mmFileSession.getFiles(mmaModDataComponent, field.dataid + '_' + field.id) || [], + originalFiles = (originalFieldData && originalFieldData.files) || []; + + if (originalFiles.length) { + originalFiles = [originalFiles[0]]; + } + + return $mmFileUploaderHelper.areFileListDifferent(files, originalFiles); + }; + + /** + * Check and get field requeriments. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {String} String with the notification or false. + */ + self.getFieldsNotifications = function(field, inputData) { + if (field.required && (!inputData || !inputData.length || !inputData[0].value)) { + return $translate.instant('mma.mod_data.errormustsupplyvalue'); + } + return false; + }; + + /** + * Override field content data with offline submission. + * + * @param {Object} originalContent Original data to be overriden. + * @param {Array} offlineContent Array with all the offline data to override. + * @param {Array} offlineFiles Array with all the offline files in the field. + * @return {Object} Data overriden + */ + self.overrideData = function(originalContent, offlineContent, offlineFiles) { + if (offlineContent && offlineContent.file && offlineContent.file.offline > 0 && offlineFiles && offlineFiles.length > 0) { + originalContent.content = offlineFiles[0].filename; + originalContent.files = [offlineFiles[0]]; + } else if (offlineContent && offlineContent.file && offlineContent.file.online && offlineContent.file.online.length > 0) { + originalContent.content = offlineContent.file.online[0].filename; + originalContent.files = [offlineContent.file.online[0]]; + } + + return originalContent; + }; + + return self; +}) + +.run(function($mmAddonManager) { + // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons, + // since they cannot assume that the data addon will be packaged in custom apps. + var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate'); + if ($mmaModDataFieldsDelegate) { + $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldFile', 'file', '$mmaModDataFieldFileHandler'); + } +}); diff --git a/www/addons/mod/data/fields/file/template.html b/www/addons/mod/data/fields/file/template.html new file mode 100644 index 00000000000..713ac633e29 --- /dev/null +++ b/www/addons/mod/data/fields/file/template.html @@ -0,0 +1,10 @@ + +{{ error }} + + +
+ + + + +
\ No newline at end of file diff --git a/www/addons/mod/data/fields/latlong/directive.js b/www/addons/mod/data/fields/latlong/directive.js new file mode 100644 index 00000000000..9d3bf66b413 --- /dev/null +++ b/www/addons/mod/data/fields/latlong/directive.js @@ -0,0 +1,58 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +.filter('mmaModDataFieldLatLongFormat', function() { + return function(value) { + var north = (value && parseFloat(value.content)) || "", + east = (value && parseFloat(value.content1)) || ""; + + if (north !== '' || east !== '') { + north = north ? north.toFixed(4) : '0.0000'; + east = east ? east.toFixed(4) : '0.0000'; + + var latitude = north < 0 ? -north + '°S' : north + '°N', + longitude = east < 0 ? -east + '°W' : east + '°E', + link = ionic.Platform.isAndroid() ? 'geo:' + north + ',' + east : + 'http://maps.apple.com/?ll=' + north + ',' + east + '&near=' + north + ',' + east; + + return '' + latitude + ' ' + longitude + ''; + } + }; +}) + +/** + * Directive to render data latlong field. + * + * @module mm.addons.mod_data + * @ngdoc directive + * @name mmaModDataFieldLatlong + */ +.directive('mmaModDataFieldLatlong', function() { + return { + restrict: 'A', + priority: 100, + templateUrl: 'addons/mod/data/fields/latlong/template.html', + link: function(scope) { + scope.mode = scope.mode == 'list' ? 'show' : scope.mode; + if (scope.value) { + if (scope.mode == 'edit') { + scope.north = (scope.value && parseFloat(scope.value.content)) || ""; + scope.east = (scope.value && parseFloat(scope.value.content1)) || ""; + } + } + } + }; +}); diff --git a/www/addons/mod/data/fields/latlong/handler.js b/www/addons/mod/data/fields/latlong/handler.js new file mode 100644 index 00000000000..9922c1397a1 --- /dev/null +++ b/www/addons/mod/data/fields/latlong/handler.js @@ -0,0 +1,143 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Handler for latlong data field plugin. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataFieldLatlongHandler + */ +.factory('$mmaModDataFieldLatlongHandler', function($translate) { + + var self = {}; + + /** + * Get field search data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldSearchData = function(field, inputData) { + var fieldName = 'f_' + field.id; + if (inputData[fieldName]) { + return [{ + name: fieldName, + value: inputData[fieldName] + }]; + } + return false; + }; + + /** + * Get field edit data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldEditData = function(field, inputData) { + var fieldName = 'f_' + field.id; + + var values = []; + + if (inputData[fieldName + '_0']) { + values.push({ + fieldid: field.id, + subfield: '0', + value: inputData[fieldName + '_0'] + }); + } + if (inputData[fieldName + '_1']) { + values.push({ + fieldid: field.id, + subfield: '1', + value: inputData[fieldName + '_1'] + }); + } + return values; + }; + + /** + * Get field data in changed. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @param {Object} originalFieldData Original field entered data. + * @return {Boolean} If the field has changes. + */ + self.hasFieldDataChanged = function(field, inputData, originalFieldData) { + var fieldName = 'f_' + field.id, + lat = inputData[fieldName + '_0'] || "", + long = inputData[fieldName + '_1'] || "", + originalLat = (originalFieldData && originalFieldData.content) || "", + originalLong = (originalFieldData && originalFieldData.content1) || ""; + + return lat != originalLat || long != originalLong; + }; + + + /** + * Check and get field requeriments. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {String} String with the notification or false. + */ + self.getFieldsNotifications = function(field, inputData) { + var valueCount = 0; + + // The lat long class has two values that need to be checked. + angular.forEach(inputData, function(value) { + if (typeof value.value != "undefined" && value.value != "") { + valueCount++; + } + }); + + // If we get here then only one field has been filled in. + if (valueCount == 1) { + return $translate.instant('mma.mod_data.latlongboth'); + } else if (field.required && valueCount == 0) { + return $translate.instant('mma.mod_data.errormustsupplyvalue'); + } + return false; + }; + + /** + * Override field content data with offline submission. + * + * @param {Object} originalContent Original data to be overriden. + * @param {Array} offlineContent Array with all the offline data to override. + * @return {Object} Data overriden + */ + self.overrideData = function(originalContent, offlineContent) { + originalContent.content = offlineContent[0] || ""; + originalContent.content1 = offlineContent[1] || ""; + return originalContent; + }; + + return self; +}) + +.run(function($mmAddonManager) { + // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons, + // since they cannot assume that the data addon will be packaged in custom apps. + var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate'); + if ($mmaModDataFieldsDelegate) { + $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldLatlong', 'latlong', '$mmaModDataFieldLatlongHandler'); + } +}); diff --git a/www/addons/mod/data/fields/latlong/template.html b/www/addons/mod/data/fields/latlong/template.html new file mode 100644 index 00000000000..5f0383efcde --- /dev/null +++ b/www/addons/mod/data/fields/latlong/template.html @@ -0,0 +1,13 @@ + + +{{ error }} + + + + diff --git a/www/addons/mod/data/fields/menu/directive.js b/www/addons/mod/data/fields/menu/directive.js new file mode 100644 index 00000000000..d4d6bcbbd4d --- /dev/null +++ b/www/addons/mod/data/fields/menu/directive.js @@ -0,0 +1,42 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Directive to render data menu field. + * + * @module mm.addons.mod_data + * @ngdoc directive + * @name mmaModDataFieldMenu + */ +.directive('mmaModDataFieldMenu', function() { + return { + restrict: 'A', + priority: 100, + templateUrl: 'addons/mod/data/fields/menu/template.html', + link: function(scope) { + scope.mode = scope.mode == 'list' ? 'show' : scope.mode; + if (scope.mode == 'show') { + return; + } + + scope.options = scope.field.param1.split("\n"); + + if (scope.mode == 'edit' && scope.value) { + scope.val = scope.value.content; + } + } + }; +}); diff --git a/www/addons/mod/data/fields/menu/handler.js b/www/addons/mod/data/fields/menu/handler.js new file mode 100644 index 00000000000..08af08fefb9 --- /dev/null +++ b/www/addons/mod/data/fields/menu/handler.js @@ -0,0 +1,117 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Handler for menu data field plugin. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataFieldMenuHandler + */ +.factory('$mmaModDataFieldMenuHandler', function($translate) { + + var self = {}; + + /** + * Get field search data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldSearchData = function(field, inputData) { + var fieldName = 'f_' + field.id; + if (inputData[fieldName]) { + return [{ + name: fieldName, + value: inputData[fieldName] + }]; + } + return false; + }; + + /** + * Get field edit data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldEditData = function(field, inputData) { + var fieldName = 'f_' + field.id; + + if (inputData[fieldName]) { + return [{ + fieldid: field.id, + value: inputData[fieldName] + }]; + } + return false; + }; + + /** + * Get field data in changed. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @param {Object} originalFieldData Original field entered data. + * @return {Boolean} If the field has changes. + */ + self.hasFieldDataChanged = function(field, inputData, originalFieldData) { + var fieldName = 'f_' + field.id, + input = inputData[fieldName] || ""; + originalFieldData = (originalFieldData && originalFieldData.content) || ""; + + return input != originalFieldData; + }; + + /** + * Check and get field requeriments. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {String} String with the notification or false. + */ + self.getFieldsNotifications = function(field, inputData) { + if (field.required && (!inputData || !inputData.length || !inputData[0].value)) { + return $translate.instant('mma.mod_data.errormustsupplyvalue'); + } + return false; + }; + + /** + * Override field content data with offline submission. + * + * @param {Object} originalContent Original data to be overriden. + * @param {Array} offlineContent Array with all the offline data to override. + * @return {Object} Data overriden + */ + self.overrideData = function(originalContent, offlineContent) { + originalContent.content = offlineContent[''] || ""; + return originalContent; + }; + + return self; +}) + +.run(function($mmAddonManager) { + // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons, + // since they cannot assume that the data addon will be packaged in custom apps. + var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate'); + if ($mmaModDataFieldsDelegate) { + $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldMenu', 'menu', '$mmaModDataFieldMenuHandler'); + } +}); diff --git a/www/addons/mod/data/fields/menu/template.html b/www/addons/mod/data/fields/menu/template.html new file mode 100644 index 00000000000..0966a1b3f34 --- /dev/null +++ b/www/addons/mod/data/fields/menu/template.html @@ -0,0 +1,9 @@ + +{{ error }} +
+ +
+{{ value.content }} \ No newline at end of file diff --git a/www/addons/mod/data/fields/multimenu/directive.js b/www/addons/mod/data/fields/multimenu/directive.js new file mode 100644 index 00000000000..612b71d7f7b --- /dev/null +++ b/www/addons/mod/data/fields/multimenu/directive.js @@ -0,0 +1,57 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +.filter('mmaModDataFieldMultimenuFormat', function() { + return function(text) { + return text.split("##").join("
"); + }; +}) + +/** + * Directive to render data multimenu field. + * + * @module mm.addons.mod_data + * @ngdoc directive + * @name mmaModDataFieldMultimenu + */ +.directive('mmaModDataFieldMultimenu', function() { + return { + restrict: 'A', + priority: 100, + templateUrl: 'addons/mod/data/fields/multimenu/template.html', + link: function(scope) { + scope.mode = scope.mode == 'list' ? 'show' : scope.mode; + if (scope.mode == 'show') { + return; + } + + scope.options = scope.field.param1.split("\n").map(function(option) { + return {key: option, value: option}; + }); + + if (scope.mode == 'edit' && scope.value && scope.value.content) { + angular.forEach(scope.value.content.split("##"), function(value) { + for (var x in scope.options) { + if (value == scope.options[x].key) { + scope.options[x].selected = true; + break; + } + } + }); + } + } + }; +}); diff --git a/www/addons/mod/data/fields/multimenu/handler.js b/www/addons/mod/data/fields/multimenu/handler.js new file mode 100644 index 00000000000..ada5c6c7704 --- /dev/null +++ b/www/addons/mod/data/fields/multimenu/handler.js @@ -0,0 +1,137 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Handler for multimenu data field plugin. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataFieldMultimenuHandler + */ +.factory('$mmaModDataFieldMultimenuHandler', function($translate) { + + var self = {}; + + /** + * Get field search data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldSearchData = function(field, inputData) { + var fieldName = 'f_' + field.id, + reqName = 'f_' + field.id + '_allreq'; + + if (inputData[fieldName].length > 0) { + var options = inputData[fieldName].split('###'); + values = []; + if (options.length > 0) { + values.push({ + name: fieldName, + value: options + }); + + if (inputData[reqName]['1']) { + values.push({ + name: reqName, + value: true + }); + } + return values; + } + } + + return false; + }; + + /** + * Get field edit data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldEditData = function(field, inputData) { + var fieldName = 'f_' + field.id; + + if (inputData[fieldName] && inputData[fieldName].length > 0) { + var options = inputData[fieldName].split('###'); + if (options.length > 0) { + return [{ + fieldid: field.id, + value: options + }]; + } + } + + return false; + }; + + /** + * Get field data in changed. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @param {Object} originalFieldData Original field entered data. + * @return {Boolean} If the field has changes. + */ + self.hasFieldDataChanged = function(field, inputData, originalFieldData) { + var fieldName = 'f_' + field.id, + input = inputData[fieldName] || ""; + originalFieldData = (originalFieldData && originalFieldData.content) || ""; + + return input != originalFieldData; + }; + + /** + * Check and get field requeriments. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {String} String with the notification or false. + */ + self.getFieldsNotifications = function(field, inputData) { + if (field.required && (!inputData || !inputData.length || !inputData[0].value)) { + return $translate.instant('mma.mod_data.errormustsupplyvalue'); + } + return false; + }; + + /** + * Override field content data with offline submission. + * + * @param {Object} originalContent Original data to be overriden. + * @param {Array} offlineContent Array with all the offline data to override. + * @return {Object} Data overriden + */ + self.overrideData = function(originalContent, offlineContent) { + originalContent.content = (offlineContent[''] && offlineContent[''].join("###")) || ""; + return originalContent; + }; + + + return self; +}) + +.run(function($mmAddonManager) { + // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons, + // since they cannot assume that the data addon will be packaged in custom apps. + var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate'); + if ($mmaModDataFieldsDelegate) { + $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldMultimenu', 'multimenu', '$mmaModDataFieldMultimenuHandler'); + } +}); diff --git a/www/addons/mod/data/fields/multimenu/template.html b/www/addons/mod/data/fields/multimenu/template.html new file mode 100644 index 00000000000..bae95d7a2ce --- /dev/null +++ b/www/addons/mod/data/fields/multimenu/template.html @@ -0,0 +1,5 @@ + +{{ error }} + +{{ 'mma.mod_data.selectedrequired' | translate }} +{{ value.content | mmaModDataFieldMultimenuFormat }} \ No newline at end of file diff --git a/www/addons/mod/data/fields/number/directive.js b/www/addons/mod/data/fields/number/directive.js new file mode 100644 index 00000000000..b3dcb81413d --- /dev/null +++ b/www/addons/mod/data/fields/number/directive.js @@ -0,0 +1,37 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Directive to render data number field. + * + * @module mm.addons.mod_data + * @ngdoc directive + * @name mmaModDataFieldNumber + */ +.directive('mmaModDataFieldNumber', function() { + return { + restrict: 'A', + priority: 100, + templateUrl: 'addons/mod/data/fields/number/template.html', + link: function(scope) { + scope.mode = scope.mode == 'list' ? 'show' : scope.mode; + + if (scope.mode == 'edit' && scope.value) { + scope.val = scope.value && parseFloat(scope.value.content); + } + } + }; +}); diff --git a/www/addons/mod/data/fields/number/handler.js b/www/addons/mod/data/fields/number/handler.js new file mode 100644 index 00000000000..0229ff1b1cb --- /dev/null +++ b/www/addons/mod/data/fields/number/handler.js @@ -0,0 +1,117 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +angular.module('mm.addons.mod_data') + +/** + * Handler for number data field plugin. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataFieldNumberHandler + */ +.factory('$mmaModDataFieldNumberHandler', function($translate) { + + var self = {}; + + /** + * Get field search data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldSearchData = function(field, inputData) { + var fieldName = 'f_' + field.id; + if (inputData[fieldName]) { + return [{ + name: fieldName, + value: inputData[fieldName] + }]; + } + return false; + }; + + /** + * Get field edit data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldEditData = function(field, inputData) { + var fieldName = 'f_' + field.id; + if (inputData[fieldName]) { + return [{ + fieldid: field.id, + value: inputData[fieldName] + }]; + } + return false; + }; + + /** + * Get field data in changed. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @param {Object} originalFieldData Original field entered data. + * @return {Boolean} If the field has changes. + */ + self.hasFieldDataChanged = function(field, inputData, originalFieldData) { + var fieldName = 'f_' + field.id, + input = inputData[fieldName] || ""; + originalFieldData = (originalFieldData && originalFieldData.content) || ""; + + return input != originalFieldData; + }; + + /** + * Check and get field requeriments. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {String} String with the notification or false. + */ + self.getFieldsNotifications = function(field, inputData) { + if (field.required && (!inputData || !inputData.length || inputData[0].value == "")) { + return $translate.instant('mma.mod_data.errormustsupplyvalue'); + } + return false; + }; + + /** + * Override field content data with offline submission. + * + * @param {Object} originalContent Original data to be overriden. + * @param {Array} offlineContent Array with all the offline data to override. + * @return {Object} Data overriden + */ + self.overrideData = function(originalContent, offlineContent) { + originalContent.content = offlineContent[''] || ""; + return originalContent; + }; + + return self; +}) + +.run(function($mmAddonManager) { + // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons, + // since they cannot assume that the data addon will be packaged in custom apps. + var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate'); + if ($mmaModDataFieldsDelegate) { + $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldNumber', 'number', '$mmaModDataFieldNumberHandler'); + } +}); diff --git a/www/addons/mod/data/fields/number/template.html b/www/addons/mod/data/fields/number/template.html new file mode 100644 index 00000000000..4f1dd5780ab --- /dev/null +++ b/www/addons/mod/data/fields/number/template.html @@ -0,0 +1,4 @@ + +{{ error }} + +{{ value.content }} \ No newline at end of file diff --git a/www/addons/mod/data/fields/picture/directive.js b/www/addons/mod/data/fields/picture/directive.js new file mode 100644 index 00000000000..cf5a0419f5b --- /dev/null +++ b/www/addons/mod/data/fields/picture/directive.js @@ -0,0 +1,102 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Directive to render data picture field. + * + * @module mm.addons.mod_data + * @ngdoc directive + * @name mmaModDataFieldPicture + */ +.directive('mmaModDataFieldPicture', function(mmaModDataComponent, $mmFileSession) { + + // Find file in a list. + function findFile(files, filenameSeek) { + for (var x in files) { + if (files[x].filename == filenameSeek) { + return files[x]; + } + } + return false; + } + + /** + * Given an input value, extract the image files and all the required data. + * + * @param {Object} scope Directive's scope. + * @param {Object} value Field value. + * @return {Void} + */ + function treatFiles(scope, value) { + var files = value && value.files || []; + + // Get image or thumb. + if (files.length > 0) { + var filenameSeek = scope.mode == 'list' ? 'thumb_' + value.content : value.content; + scope.image = findFile(files, filenameSeek); + + if (!scope.image && scope.mode == 'list') { + scope.image = findFile(files, value.content); + } + + scope.files = [scope.image]; + } else { + scope.image = false; + scope.files = []; + } + + if (scope.mode == 'edit') { + scope.maxSizeBytes = parseInt(scope.field.param3, 10); + $mmFileSession.setFiles(mmaModDataComponent, scope.database.id + '_' + scope.field.id, scope.files); + scope.alttext = (value && value.content1) || ""; + } else { + scope.entryId = (value && value.recordid) || false; + scope.title = (value && value.content1) || ""; + scope.imageUrl = false; + if (scope.image) { + if (scope.image.offline) { + scope.imageUrl = (scope.image && scope.image.toURL()) || false; + } else { + scope.imageUrl = (scope.image && scope.image.fileurl) || false; + } + } + scope.width = scope.field.param1 || ""; + scope.height = scope.field.param2 || ""; + } + } + + return { + restrict: 'A', + priority: 100, + templateUrl: 'addons/mod/data/fields/picture/template.html', + link: function(scope) { + if (scope.mode != 'search') { + scope.component = mmaModDataComponent; + scope.componentId = scope.database.coursemodule; + + if (scope.mode == 'show') { + // Displaying the list of files, watch the value to update the list if it changes. + scope.$watch('value', function(newValue) { + treatFiles(scope, newValue); + }); + } else { + // Edit mode, the list shouldn't change so there is no need to watch it. + treatFiles(scope, scope.value); + } + } + } + }; +}); diff --git a/www/addons/mod/data/fields/picture/handler.js b/www/addons/mod/data/fields/picture/handler.js new file mode 100644 index 00000000000..e8fd592b4a6 --- /dev/null +++ b/www/addons/mod/data/fields/picture/handler.js @@ -0,0 +1,175 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Handler for picture data field plugin. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataFieldPictureHandler + */ +.factory('$mmaModDataFieldPictureHandler', function($mmFileSession, mmaModDataComponent, $mmFileUploaderHelper, $translate) { + + var self = {}; + + /** + * Get field search data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldSearchData = function(field, inputData) { + var fieldName = 'f_' + field.id; + if (inputData[fieldName]) { + return [{ + name: fieldName, + value: inputData[fieldName] + }]; + } + return false; + }; + + /** + * Get field edit data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @return {Promise} With name and value of the data to be sent. + */ + self.getFieldEditData = function(field, inputData) { + var files = self.getFieldEditFiles(field), + values = [], + fieldName = 'f_' + field.id + '_alttext'; + + if (files.length) { + values.push({ + fieldid: field.id, + subfield: 'file', + files: files + }); + } + + if (inputData[fieldName]) { + values.push({ + fieldid: field.id, + subfield: 'alttext', + value: inputData[fieldName] + }); + } + return values; + }; + + /** + * Get field edit files in the input data. + * + * @param {Object} field Defines the field.. + * @return {Promise} With name and value of the data to be sent. + */ + self.getFieldEditFiles = function(field) { + return $mmFileSession.getFiles(mmaModDataComponent, field.dataid + '_' + field.id); + }; + + /** + * Get field data in changed. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @param {Object} originalFieldData Original field entered data. + * @return {Boolean} If the field has changes. + */ + self.hasFieldDataChanged = function(field, inputData, originalFieldData) { + var fieldName = 'f_' + field.id + '_alttext', + altText = inputData[fieldName] || "", + originalAltText = (originalFieldData && originalFieldData.content1) || "", + files = $mmFileSession.getFiles(mmaModDataComponent, field.dataid + '_' + field.id) || [], + originalFiles = (originalFieldData && originalFieldData.files) || []; + + // Get image. + if (originalFiles.length > 0) { + var filenameSeek = (originalFieldData && originalFieldData.content) || ""; + for (var x in originalFiles) { + if (originalFiles[x].filename == filenameSeek) { + originalFiles = originalFiles[x]; + break; + } + } + originalFiles = [originalFiles]; + } else { + originalFiles = []; + } + + return altText != originalAltText || $mmFileUploaderHelper.areFileListDifferent(files, originalFiles); + }; + + /** + * Check and get field requeriments. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {String} String with the notification or false. + */ + self.getFieldsNotifications = function(field, inputData) { + if (field.required) { + if (!inputData || !inputData.length) { + return $translate.instant('mma.mod_data.errormustsupplyvalue'); + } + var found = false; + for (var x in inputData) { + if (typeof inputData[x].subfield !="undefined" && inputData[x].subfield == 'file') { + found = !!inputData[x].value; + break; + } + } + + if (!found) { + return $translate.instant('mma.mod_data.errormustsupplyvalue'); + } + } + return false; + }; + + /** + * Override field content data with offline submission. + * + * @param {Object} originalContent Original data to be overriden. + * @param {Array} offlineContent Array with all the offline data to override. + * @param {Array} offlineFiles Array with all the offline files in the field. + * @return {Object} Data overriden + */ + self.overrideData = function(originalContent, offlineContent, offlineFiles) { + if (offlineContent && offlineContent.file && offlineContent.file.offline > 0 && offlineFiles && offlineFiles.length > 0) { + originalContent.content = offlineFiles[0].filename; + originalContent.files = [offlineFiles[0]]; + } else if (offlineContent && offlineContent.file && offlineContent.file.online && offlineContent.file.online.length > 0) { + originalContent.content = offlineContent.file.online[0].filename; + originalContent.files = [offlineContent.file.online[0]]; + } + + originalContent.content1 = offlineContent.alttext || ""; + return originalContent; + }; + + return self; +}) + +.run(function($mmAddonManager) { + // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons, + // since they cannot assume that the data addon will be packaged in custom apps. + var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate'); + if ($mmaModDataFieldsDelegate) { + $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldPicture', 'picture', '$mmaModDataFieldPictureHandler'); + } +}); diff --git a/www/addons/mod/data/fields/picture/template.html b/www/addons/mod/data/fields/picture/template.html new file mode 100644 index 00000000000..9b92ee53e3b --- /dev/null +++ b/www/addons/mod/data/fields/picture/template.html @@ -0,0 +1,11 @@ + +{{ error }} + + + + {{ 'mma.mod_data.alttext' | translate }} + + + +{{title}} +{{title}} diff --git a/www/addons/mod/data/fields/radiobutton/directive.js b/www/addons/mod/data/fields/radiobutton/directive.js new file mode 100644 index 00000000000..86eaf2bd78f --- /dev/null +++ b/www/addons/mod/data/fields/radiobutton/directive.js @@ -0,0 +1,42 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Directive to render data radiobutton field. + * + * @module mm.addons.mod_data + * @ngdoc directive + * @name mmaModDataFieldRadiobutton + */ +.directive('mmaModDataFieldRadiobutton', function() { + return { + restrict: 'A', + priority: 100, + templateUrl: 'addons/mod/data/fields/radiobutton/template.html', + link: function(scope) { + scope.mode = scope.mode == 'list' ? 'show' : scope.mode; + if (scope.mode == 'show') { + return; + } + + scope.options = scope.field.param1.split("\n"); + + if (scope.mode == 'edit' && scope.value) { + scope.val = scope.value.content; + } + } + }; +}); diff --git a/www/addons/mod/data/fields/radiobutton/handler.js b/www/addons/mod/data/fields/radiobutton/handler.js new file mode 100644 index 00000000000..93fd7d5d740 --- /dev/null +++ b/www/addons/mod/data/fields/radiobutton/handler.js @@ -0,0 +1,117 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Handler for radiobutton data field plugin. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataFieldRadiobuttonHandler + */ +.factory('$mmaModDataFieldRadiobuttonHandler', function($translate) { + + var self = {}; + + /** + * Get field search data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldSearchData = function(field, inputData) { + var fieldName = 'f_' + field.id; + if (inputData[fieldName]) { + return [{ + name: fieldName, + value: inputData[fieldName] + }]; + } + return false; + }; + + /** + * Get field edit data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldEditData = function(field, inputData) { + var fieldName = 'f_' + field.id; + + if (inputData[fieldName]) { + return [{ + fieldid: field.id, + value: inputData[fieldName] + }]; + } + return false; + }; + + /** + * Get field data in changed. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @param {Object} originalFieldData Original field entered data. + * @return {Boolean} If the field has changes. + */ + self.hasFieldDataChanged = function(field, inputData, originalFieldData) { + var fieldName = 'f_' + field.id, + input = inputData[fieldName] || ""; + originalFieldData = (originalFieldData && originalFieldData.content) || ""; + + return input != originalFieldData; + }; + + /** + * Check and get field requeriments. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {String} String with the notification or false. + */ + self.getFieldsNotifications = function(field, inputData) { + if (field.required && (!inputData || !inputData.length || !inputData[0].value)) { + return $translate.instant('mma.mod_data.errormustsupplyvalue'); + } + return false; + }; + + /** + * Override field content data with offline submission. + * + * @param {Object} originalContent Original data to be overriden. + * @param {Array} offlineContent Array with all the offline data to override. + * @return {Object} Data overriden + */ + self.overrideData = function(originalContent, offlineContent) { + originalContent.content = offlineContent[''] || ""; + return originalContent; + }; + + return self; +}) + +.run(function($mmAddonManager) { + // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons, + // since they cannot assume that the data addon will be packaged in custom apps. + var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate'); + if ($mmaModDataFieldsDelegate) { + $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldRadiobutton', 'radiobutton', '$mmaModDataFieldRadiobuttonHandler'); + } +}); diff --git a/www/addons/mod/data/fields/radiobutton/template.html b/www/addons/mod/data/fields/radiobutton/template.html new file mode 100644 index 00000000000..0966a1b3f34 --- /dev/null +++ b/www/addons/mod/data/fields/radiobutton/template.html @@ -0,0 +1,9 @@ + +{{ error }} +
+ +
+{{ value.content }} \ No newline at end of file diff --git a/www/addons/mod/data/fields/text/directive.js b/www/addons/mod/data/fields/text/directive.js new file mode 100644 index 00000000000..18bdb2c3362 --- /dev/null +++ b/www/addons/mod/data/fields/text/directive.js @@ -0,0 +1,37 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Directive to render data text field. + * + * @module mm.addons.mod_data + * @ngdoc directive + * @name mmaModDataFieldText + */ +.directive('mmaModDataFieldText', function() { + return { + restrict: 'A', + priority: 100, + templateUrl: 'addons/mod/data/fields/text/template.html', + link: function(scope) { + scope.mode = scope.mode == 'list' ? 'show' : scope.mode; + + if (scope.mode == 'edit' && scope.value) { + scope.val = scope.value.content; + } + } + }; +}); diff --git a/www/addons/mod/data/fields/text/handler.js b/www/addons/mod/data/fields/text/handler.js new file mode 100644 index 00000000000..909a1e2b92c --- /dev/null +++ b/www/addons/mod/data/fields/text/handler.js @@ -0,0 +1,116 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Handler for text data field plugin. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataFieldTextHandler + */ +.factory('$mmaModDataFieldTextHandler', function($translate) { + + var self = {}; + + /** + * Get field search data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldSearchData = function(field, inputData) { + var fieldName = 'f_' + field.id; + if (inputData[fieldName]) { + return [{ + name: fieldName, + value: inputData[fieldName] + }]; + } + return false; + }; + + /** + * Get field edit data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldEditData = function(field, inputData) { + var fieldName = 'f_' + field.id; + if (inputData[fieldName]) { + return [{ + fieldid: field.id, + value: inputData[fieldName] + }]; + } + return false; + }; + + /** + * Get field data in changed. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @param {Object} originalFieldData Original field entered data. + * @return {Boolean} If the field has changes. + */ + self.hasFieldDataChanged = function(field, inputData, originalFieldData) { + var fieldName = 'f_' + field.id, + input = inputData[fieldName] || ""; + originalFieldData = (originalFieldData && originalFieldData.content) || ""; + + return input != originalFieldData; + }; + + /** + * Check and get field requeriments. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {String} String with the notification or false. + */ + self.getFieldsNotifications = function(field, inputData) { + if (field.required && (!inputData || !inputData.length || !inputData[0].value)) { + return $translate.instant('mma.mod_data.errormustsupplyvalue'); + } + return false; + }; + + /** + * Override field content data with offline submission. + * + * @param {Object} originalContent Original data to be overriden. + * @param {Array} offlineContent Array with all the offline data to override. + * @return {Object} Data overriden + */ + self.overrideData = function(originalContent, offlineContent) { + originalContent.content = offlineContent[''] || ""; + return originalContent; + }; + + return self; +}) + +.run(function($mmAddonManager) { + // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons, + // since they cannot assume that the data addon will be packaged in custom apps. + var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate'); + if ($mmaModDataFieldsDelegate) { + $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldText', 'text', '$mmaModDataFieldTextHandler'); + } +}); diff --git a/www/addons/mod/data/fields/text/template.html b/www/addons/mod/data/fields/text/template.html new file mode 100644 index 00000000000..3fe5aa19cba --- /dev/null +++ b/www/addons/mod/data/fields/text/template.html @@ -0,0 +1,4 @@ + +{{ error }} + +{{ value.content }} \ No newline at end of file diff --git a/www/addons/mod/data/fields/textarea/directive.js b/www/addons/mod/data/fields/textarea/directive.js new file mode 100644 index 00000000000..66662e9d2ad --- /dev/null +++ b/www/addons/mod/data/fields/textarea/directive.js @@ -0,0 +1,63 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +.filter('mmaModDataFieldTextareaFormat', function($mmText) { + return function(value) { + var files = (value && value.files) || []; + return value ? $mmText.replacePluginfileUrls(value.content, files) : ''; + }; +}) + +/** + * Directive to render data textarea field. + * + * @module mm.addons.mod_data + * @ngdoc directive + * @name mmaModDataFieldTextarea + */ +.directive('mmaModDataFieldTextarea', function($mmText, mmaModDataComponent) { + return { + restrict: 'A', + priority: 100, + templateUrl: 'addons/mod/data/fields/textarea/template.html', + link: function(scope) { + scope.mode = scope.mode == 'list' ? 'show' : scope.mode; + if (scope.mode == 'show') { + scope.component = mmaModDataComponent; + scope.componentId = scope.database.coursemodule; + return; + } + + // Check if rich text editor is enabled. + if (scope.mode == 'edit') { + var files = (scope.value && scope.value.files) || [], + text = scope.value ? $mmText.replacePluginfileUrls(scope.value.content, files) : ""; + + // Get the text. + scope.model = { + text: text + }; + + scope.firstRender = function() { + if (!scope.value) { + scope.value = {}; + } + scope.value.content = scope.model.text; + }; + } + } + }; +}); diff --git a/www/addons/mod/data/fields/textarea/handler.js b/www/addons/mod/data/fields/textarea/handler.js new file mode 100644 index 00000000000..0e04c8951ae --- /dev/null +++ b/www/addons/mod/data/fields/textarea/handler.js @@ -0,0 +1,168 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Handler for textarea data field plugin. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataFieldTextareaHandler + */ +.factory('$mmaModDataFieldTextareaHandler', function($mmText, $mmUtil, $translate) { + + var self = {}; + + /** + * Get field search data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldSearchData = function(field, inputData) { + var fieldName = 'f_' + field.id; + if (inputData[fieldName]) { + return [{ + name: fieldName, + value: inputData[fieldName] + }]; + } + return false; + }; + + /** + * Get field edit data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @param {Object} originalFieldData Original field entered data. + * @return {Promise} With name and value of the data to be sent. + */ + self.getFieldEditData = function(field, inputData, originalFieldData) { + var fieldName = 'f_' + field.id; + if (inputData[fieldName]) { + return $mmUtil.isRichTextEditorEnabled().then(function(enabled) { + var files = self.getFieldEditFiles(field, inputData, originalFieldData), + text = $mmText.restorePluginfileUrls(inputData[fieldName], files); + + if (!enabled) { + // Rich text editor not enabled, add some HTML to the text if needed. + text = $mmText.formatHtmlLines(text); + } + + return [{ + fieldid: field.id, + value: text + }, + { + fieldid: field.id, + subfield: 'content1', + value: 1 + }, + { + fieldid: field.id, + subfield: 'itemid', + files: files + } + ]; + }); + } + return false; + }; + + /** + * Get field edit files in the input data. + * + * @param {Object} field Defines the field.. + * @param {Object} inputData Data entered in the edit form. + * @param {Object} originalFieldData Original field entered data. + * @return {Promise} With name and value of the data to be sent. + */ + self.getFieldEditFiles = function(field, inputData, originalFieldData) { + return (originalFieldData && originalFieldData.files) || []; + }; + + /** + * Get field data in changed. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @param {Object} originalFieldData Original field entered data. + * @return {Boolean} If the field has changes. + */ + self.hasFieldDataChanged = function(field, inputData, originalFieldData) { + var fieldName = 'f_' + field.id, + input = inputData[fieldName] || ""; + originalFieldData = (originalFieldData && originalFieldData.content) || ""; + + return input != originalFieldData; + }; + + /** + * Check and get field requeriments. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {String} String with the notification or false. + */ + self.getFieldsNotifications = function(field, inputData) { + if (field.required) { + if (!inputData || !inputData.length) { + return $translate.instant('mma.mod_data.errormustsupplyvalue'); + } + var found = false; + for (var x in inputData) { + if (!inputData[x].subfield) { + found = inputData[x].value; + break; + } + } + + if (!found) { + return $translate.instant('mma.mod_data.errormustsupplyvalue'); + } + } + return false; + }; + + /** + * Override field content data with offline submission. + * + * @param {Object} originalContent Original data to be overriden. + * @param {Array} offlineContent Array with all the offline data to override. + * @return {Object} Data overriden + */ + self.overrideData = function(originalContent, offlineContent) { + originalContent.content = offlineContent[''] || ""; + if (originalContent.content.length > 0 && originalContent.files && originalContent.files.length > 0) { + // Take the original files since we cannot edit them on the app. + originalContent.content = $mmText.replacePluginfileUrls(originalContent.content, originalContent.files); + } + + return originalContent; + }; + + return self; +}) + +.run(function($mmAddonManager) { + // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons, + // since they cannot assume that the data addon will be packaged in custom apps. + var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate'); + if ($mmaModDataFieldsDelegate) { + $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldTextarea', 'textarea', '$mmaModDataFieldTextareaHandler'); + } +}); diff --git a/www/addons/mod/data/fields/textarea/template.html b/www/addons/mod/data/fields/textarea/template.html new file mode 100644 index 00000000000..4260325d1a6 --- /dev/null +++ b/www/addons/mod/data/fields/textarea/template.html @@ -0,0 +1,7 @@ + +{{ error }} + +
+ +
+{{ value | mmaModDataFieldTextareaFormat }} \ No newline at end of file diff --git a/www/addons/mod/data/fields/url/directive.js b/www/addons/mod/data/fields/url/directive.js new file mode 100644 index 00000000000..5306dbd9904 --- /dev/null +++ b/www/addons/mod/data/fields/url/directive.js @@ -0,0 +1,37 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Directive to render data url field. + * + * @module mm.addons.mod_data + * @ngdoc directive + * @name mmaModDataFieldUrl + */ +.directive('mmaModDataFieldUrl', function() { + return { + restrict: 'A', + priority: 100, + templateUrl: 'addons/mod/data/fields/url/template.html', + link: function(scope) { + scope.mode = scope.mode == 'list' ? 'show' : scope.mode; + + if (scope.mode == 'edit' && scope.value) { + scope.val = scope.value.content; + } + } + }; +}); diff --git a/www/addons/mod/data/fields/url/handler.js b/www/addons/mod/data/fields/url/handler.js new file mode 100644 index 00000000000..8719873723f --- /dev/null +++ b/www/addons/mod/data/fields/url/handler.js @@ -0,0 +1,116 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Handler for url data field plugin. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataFieldUrlHandler + */ +.factory('$mmaModDataFieldUrlHandler', function($translate) { + + var self = {}; + + /** + * Get field search data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldSearchData = function(field, inputData) { + var fieldName = 'f_' + field.id; + if (inputData[fieldName]) { + return [{ + name: fieldName, + value: inputData[fieldName] + }]; + } + return false; + }; + + /** + * Get field edit data in the input data. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {Array} With name and value of the data to be sent. + */ + self.getFieldEditData = function(field, inputData) { + var fieldName = 'f_' + field.id; + if (inputData[fieldName]) { + return [{ + fieldid: field.id, + value: inputData[fieldName] + }]; + } + return false; + }; + + /** + * Get field data in changed. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @param {Object} originalFieldData Original field entered data. + * @return {Boolean} If the field has changes. + */ + self.hasFieldDataChanged = function(field, inputData, originalFieldData) { + var fieldName = 'f_' + field.id, + input = inputData[fieldName] || ""; + originalFieldData = (originalFieldData && originalFieldData.content) || ""; + + return input != originalFieldData; + }; + + /** + * Check and get field requeriments. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {String} String with the notification or false. + */ + self.getFieldsNotifications = function(field, inputData) { + if (field.required && (!inputData || !inputData.length || !inputData[0].value)) { + return $translate.instant('mma.mod_data.errormustsupplyvalue'); + } + return false; + }; + + /** + * Override field content data with offline submission. + * + * @param {Object} originalContent Original data to be overriden. + * @param {Array} offlineContent Array with all the offline data to override. + * @return {Object} Data overriden + */ + self.overrideData = function(originalContent, offlineContent) { + originalContent.content = offlineContent[''] || ""; + return originalContent; + }; + + return self; +}) + +.run(function($mmAddonManager) { + // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons, + // since they cannot assume that the data addon will be packaged in custom apps. + var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate'); + if ($mmaModDataFieldsDelegate) { + $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldUrl', 'url', '$mmaModDataFieldUrlHandler'); + } +}); diff --git a/www/addons/mod/data/fields/url/template.html b/www/addons/mod/data/fields/url/template.html new file mode 100644 index 00000000000..cd181b6fd86 --- /dev/null +++ b/www/addons/mod/data/fields/url/template.html @@ -0,0 +1,3 @@ + + +{{field.name}} diff --git a/www/addons/mod/data/lang/ar.json b/www/addons/mod/data/lang/ar.json new file mode 100644 index 00000000000..241c0dfb51c --- /dev/null +++ b/www/addons/mod/data/lang/ar.json @@ -0,0 +1,31 @@ +{ + "addentries": "أضف مدخلات", + "advancedsearch": "بحث متقدم", + "alttext": "النص البديل", + "approve": "اسمح/وافق", + "approved": "تم الموافقة", + "ascending": "تصاعدي", + "authorfirstname": "الاسم الأول للكاتب", + "authorlastname": "الاسم الأخير للكاتب", + "confirmdeleterecord": "هل فعلا ترغب في حذف هذا السجل؟", + "descending": "تنازليا", + "emptyaddform": "لم تقم بتعبئة الحقول!", + "expired": "عذراً، تم إغلاق هذا النشاط في {{$a}} وهو غير متوفر الآن.", + "fields": "حقول", + "menuchoose": "اختار", + "more": "المزيد", + "nomatch": "لم يتم العثور على مدخلات مطابقة!", + "norecords": "لا يوجد مدخلات في قاعدة البيانات", + "notapproved": "لم يتم الموافقة على المدخل بعد", + "notopenyet": "عذراً، هذا النشاط لن يتاح حتى {{$a}}", + "numrecords": "{{$a}} سجلات", + "other": "اخر", + "recordapproved": "تم الموافقه على السجل", + "recorddeleted": "تم حذف السجل", + "resetsettings": "إعادة تعين الحقول", + "search": "بحث", + "selectedrequired": "كل المختار مطلوب", + "timeadded": "وقت الإضافة", + "timemodified": "وقت التعديل", + "usedate": "تضمين في البحث" +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/bg.json b/www/addons/mod/data/lang/bg.json new file mode 100644 index 00000000000..2210bbfe18e --- /dev/null +++ b/www/addons/mod/data/lang/bg.json @@ -0,0 +1,35 @@ +{ + "addentries": "Добавяне на записи", + "advancedsearch": "Разширено търсене", + "alttext": "Алтернативен текст", + "approve": "Одобрение", + "approved": "Одобрен", + "ascending": "По нарастване", + "authorfirstname": "Име на автора", + "authorlastname": "Презиме на автора", + "confirmdeleterecord": "Сигурни ли сте, че искате да изтриете това?", + "descending": "По намаляване", + "disapprove": "Отхвърляне на одобрение", + "emptyaddform": "Не сте попълнили никакви полета!", + "entrieslefttoadd": "Трябва да добавите още {{$a.entriesleft}} записи, за да завършите тази дейност", + "entrieslefttoaddtoview": "Трябва да добавите още {{$a.entrieslefttoview}} записи преди да можете да видите записите на другите участници.", + "expired": "За съжаление тази дейност е затворена в {{$a}} и вече не е достъпна", + "fields": "Полета", + "menuchoose": "Изберете...", + "more": "Още", + "nomatch": "Не са намерени съответстващи записи!", + "norecords": "Няма записи в базата данни", + "notapproved": "Записът още не е качен", + "notopenyet": "За съжаление тази дейност не е достъпна от {{$a}}", + "numrecords": "{{$a}} записи", + "other": "Друго", + "recordapproved": "Записът качен", + "recorddeleted": "Записът изтрит", + "recorddisapproved": "Записът не е одобрен", + "resetsettings": "Нулиране на филтрите", + "search": "Търсене", + "selectedrequired": "Всичко избрано се изисква", + "timeadded": "Време на добавяне", + "timemodified": "Време на промяна", + "usedate": "Включване в търсене." +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/ca.json b/www/addons/mod/data/lang/ca.json new file mode 100644 index 00000000000..fc0c0d549bd --- /dev/null +++ b/www/addons/mod/data/lang/ca.json @@ -0,0 +1,37 @@ +{ + "addentries": "Afegeix entrades", + "advancedsearch": "Cerca avançada", + "alttext": "Text alternatiu", + "approve": "Aprova", + "approved": "Acceptat", + "ascending": "Ascendent", + "authorfirstname": "Nom de l'autor/autora", + "authorlastname": "Cognoms de l'autor/autora", + "confirmdeleterecord": "Segur que voleu suprimir aquesta entrada?", + "descending": "Descendent", + "disapprove": "Desfés l'aprovació", + "emptyaddform": "No heu emplenat cap camp", + "entrieslefttoadd": "Heu d'afegir {{$a.entriesleft}} una entrada o més per completar aquesta activitat", + "entrieslefttoaddtoview": "Heu d'afegir {{$a.entrieslefttoview}} una entrada o més abans que pugueu veure les entrades d'altres participants", + "errormustsupplyvalue": "Cal que poseu un valor aquí.", + "expired": "Aquesta activitat es va tancar el dia {{$a}} i ja no està disponible", + "fields": "Camps", + "latlongboth": "Cal posar tant la latitud com la longitud.", + "menuchoose": "Trieu...", + "more": "Més", + "nomatch": "No s'han trobat entrades que coincideixin", + "norecords": "No hi ha entrades en la base de dades", + "notapproved": "L'entrada encara no està aprovada.", + "notopenyet": "Aquesta activitat no estarà disponible fins al dia {{$a}}", + "numrecords": "{{$a}} entrades", + "other": "Un altre", + "recordapproved": "S'ha aprovat l'entrada", + "recorddeleted": "S'ha suprimit l'entrada", + "recorddisapproved": "Entrada no aprovada", + "resetsettings": "Reinicialitza els filtres", + "search": "Cerca", + "selectedrequired": "Cal que estigui tot seleccionat", + "timeadded": "Hora de la incorporació", + "timemodified": "Hora de la modificació", + "usedate": "Inclou en la cerca." +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/cs.json b/www/addons/mod/data/lang/cs.json new file mode 100644 index 00000000000..8430a087b16 --- /dev/null +++ b/www/addons/mod/data/lang/cs.json @@ -0,0 +1,37 @@ +{ + "addentries": "Přidat záznamy", + "advancedsearch": "Pokročilé vyhledávání", + "alttext": "Alternativní text", + "approve": "Schválit", + "approved": "Schváleno", + "ascending": "Vzestupně", + "authorfirstname": "Křestní jméno autora", + "authorlastname": "Příjmení autora", + "confirmdeleterecord": "Chcete skutečně odstranit tento záznam?", + "descending": "Sestupně", + "disapprove": "Odvolat schválení", + "emptyaddform": "Nevyplnili jste žádná pole!", + "entrieslefttoadd": "Ještě musíte vložit {{$a.entriesleft}} záznamů(-y), abyste dokončili tuto činnost", + "entrieslefttoaddtoview": "Ještě musíte vložit {{$a.entrieslefttoview}} záznamů(-y), než budete moci vidět záznamy ostatních účastníků.", + "errormustsupplyvalue": "Musí obsahovat nějakou hodnotu.", + "expired": "Tato činnost byla ukončena {{$a}} a není již nadále dostupná.", + "fields": "Pole", + "latlongboth": "Je požadována zeměpisná šířka i délka.", + "menuchoose": "Vybrat...", + "more": "Podrobněji", + "nomatch": "Nenalezeny žádné záznamy!", + "norecords": "Nejsou k dispozici žádné záznamy", + "notapproved": "Záznam není zatím schválen", + "notopenyet": "Tato činnost nebude dostupná až do {{$a}}", + "numrecords": "{{$a}} záznamů", + "other": "Jiné", + "recordapproved": "Záznam byl schválen", + "recorddeleted": "Záznam byl smazán", + "recorddisapproved": "Neschválený záznam", + "resetsettings": "Resetovat filtry", + "search": "Vyhledat", + "selectedrequired": "Všechna zvolená povinná", + "timeadded": "Čas vložení", + "timemodified": "Čas poslední úpravy", + "usedate": "Zahrnout do vyhledávání." +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/da.json b/www/addons/mod/data/lang/da.json new file mode 100644 index 00000000000..6509111b86e --- /dev/null +++ b/www/addons/mod/data/lang/da.json @@ -0,0 +1,37 @@ +{ + "addentries": "Tilføj indlæg", + "advancedsearch": "Avanceret søgning", + "alttext": "Alternativ tekst", + "approve": "Godkend", + "approved": "Godkendt", + "ascending": "Stigende", + "authorfirstname": "Forfatterens fornavn", + "authorlastname": "Forfatterens efternavn", + "confirmdeleterecord": "Er du sikker på at du vil slette denne post?", + "descending": "Faldende", + "disapprove": "Fortryd godkendelse", + "emptyaddform": "Du udfyldte ingen felter!", + "entrieslefttoadd": "Du mangler at tilføje {{$a.entriesleft}} post(er) til denne database.", + "entrieslefttoaddtoview": "Du skal tilføje {{$a.entrieslefttoview}} post(er mere) til denne database før du kan se andre deltageres bidrag.", + "errormustsupplyvalue": "Du skal indsætte en værdi her.", + "expired": "Beklager, denne aktivitet lukkede {{$a}} og er ikke længere tilgængelig", + "fields": "Felter", + "latlongboth": "Skriv både bredde- og længdegrad", + "menuchoose": "Vælg...", + "more": "Flere", + "nomatch": "Ingen passende indlæg fundet", + "norecords": "Ingen indlæg i databasen", + "notapproved": "Posten er ikke godkendt endnu.", + "notopenyet": "Beklager, denne aktivitet er først tilgængelig {{$a}}", + "numrecords": "{{$a}} poster", + "other": "Anden", + "recordapproved": "Post godkendt", + "recorddeleted": "Posten er slettet", + "recorddisapproved": "Posten er ikke godkendt", + "resetsettings": "Nulstil filtre", + "search": "Søg", + "selectedrequired": "Alle valgte er påkrævet", + "timeadded": "Tilføjet", + "timemodified": "Ændret", + "usedate": "Inkluder i søgning." +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/de.json b/www/addons/mod/data/lang/de.json new file mode 100644 index 00000000000..f9e7fff488f --- /dev/null +++ b/www/addons/mod/data/lang/de.json @@ -0,0 +1,39 @@ +{ + "addentries": "Einträge hinzufügen", + "advancedsearch": "Erweiterte Suche", + "alttext": "Alternativer Text", + "approve": "Zulassen", + "approved": "Bestätigt", + "ascending": "Aufsteigend", + "authorfirstname": "Vorname (Autor)", + "authorlastname": "Nachname (Autor)", + "confirmdeleterecord": "Möchten Sie diesen Datensatz wirklich in der Datenbank löschen?", + "descending": "Absteigend", + "disapprove": "Eintrag nicht freigegeben", + "emptyaddform": "Sie haben keine Einträge vorgenommen!", + "entrieslefttoadd": "Sie müssen {{$a.entriesleft}} (weitere) Einträge vornehmen, um diese Aktivität zu beenden.", + "entrieslefttoaddtoview": "Sie müssen {{$a.entrieslefttoview}} (weitere) Einträge vornehmen, bevor Sie andere Teilnehmerbeiträge betrachten können.", + "errorapproving": "Fehler beim Freigeben bzw. Ablehnen des Eintrags", + "errordeleting": "Fehler beim Löschen des Eintrags", + "errormustsupplyvalue": "Sie müssen hier einen Wert eintragen.", + "expired": "Die Aktivität wurde am {{$a}} abgeschlossen und ist nicht weiter verfügbar.", + "fields": "Felder", + "latlongboth": "Längen- und Breitengrad müssen eingetragen werden.", + "menuchoose": "Auswählen ...", + "more": "Einzelansicht", + "nomatch": "Keine passenden Einträge gefunden", + "norecords": "Keine Einträge in der Datenbank", + "notapproved": "Der Eintrag wurde bisher nicht freigegeben", + "notopenyet": "Die Aktivität ist nicht verfügbar bis {{$a}}.", + "numrecords": "{{$a}} Datensätze", + "other": "Andere", + "recordapproved": "Datensatz wurde angenommen", + "recorddeleted": "Datensatz gelöscht", + "recorddisapproved": "Eintrag nicht freigegeben", + "resetsettings": "Filter zurücksetzen", + "search": "Suche", + "selectedrequired": "Gesamte Auswahl ist erforderlich", + "timeadded": "Zeit erstellt", + "timemodified": "Zeit geändert", + "usedate": "In Suche einbeziehen" +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/el.json b/www/addons/mod/data/lang/el.json new file mode 100644 index 00000000000..8afbe5fdcc4 --- /dev/null +++ b/www/addons/mod/data/lang/el.json @@ -0,0 +1,31 @@ +{ + "addentries": "Προσθήκη καταχωρήσεων", + "advancedsearch": "Advanced search", + "alttext": "Εναλλακτικό κείμενο", + "approve": "Έγκριση", + "approved": "Εγκρίθηκε", + "ascending": "Αύξουσα", + "authorfirstname": "Όνομα συγγραφέα", + "authorlastname": "Επίθετο συγγραφέα", + "confirmdeleterecord": "Σίγουρα θέλετε να διαγραφεί αυτή η καταχώρηση;", + "descending": "Φθίνουσα", + "emptyaddform": "Δεν συμπληρώσατε κανένα από τα πεδία!", + "entrieslefttoadd": "Πρέπει να προσθέσετε {{$a.entriesleft}} περισσότερες καταχωρήσεις ώστε να ολοκληρώσετε αυτήν τη δραστηριότητα", + "entrieslefttoaddtoview": "Πρέπει να προσθέσετε {{$a.entrieslefttoview}} περισσότερες καταχωρήσεις πριν να μπορέσετε να δείτε τις καταχωρήσεις άλλων χρηστών.", + "expired": "Η δραστηριότητα αυτή έκλεισε στις {{$a}} και δεν είναι πλέον διαθέσιμη", + "fields": "Πεδία", + "menuchoose": "Επιλέξτε....", + "more": "Περισσότερα", + "nomatch": "Δεν βρέθηκαν καταχωρήσεις που να ταιριάζουν!", + "norecords": "Δεν υπάρχουν καταχωρήσεις στη βάση δεδομένων", + "notopenyet": "Συγνώμη, αυτή η δραστηριότητα δεν είναι διαθέσιμη μέχρι {{$a}}", + "numrecords": "{{$a}} καταχωρήσεις", + "other": "Άλλο", + "recordapproved": "Η καταχώρηση εγκρίθηκε", + "recorddeleted": "Η καταχώρηση διαγράφθηκε", + "resetsettings": "Επανορισμός φίλτρων", + "search": "Αναζήτηση", + "selectedrequired": "Απαιτούνται όλα τα επιλεγμένα", + "timeadded": "Προστέθηκε χρόνος", + "timemodified": "Ο χρόνος μεταβλήθηκε" +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/en.json b/www/addons/mod/data/lang/en.json new file mode 100644 index 00000000000..8ad92b9ec45 --- /dev/null +++ b/www/addons/mod/data/lang/en.json @@ -0,0 +1,41 @@ +{ + "addentries": "Add entries", + "advancedsearch": "Advanced search", + "alttext": "Alternative text", + "approve": "Approve", + "approved": "Approved", + "authorfirstname": "Author first name", + "authorlastname": "Author surname", + "ascending": "Ascending", + "authorfirstname": "Author first name", + "authorlastname": "Author surname", + "confirmdeleterecord": "Are you sure you want to delete this entry?", + "descending": "Descending", + "disapprove": "Undo approval", + "emptyaddform": "You did not fill out any fields!", + "entrieslefttoadd": "You must add {{$a.entriesleft}} more entry/entries in order to complete this activity", + "entrieslefttoaddtoview": "You must add {{$a.entrieslefttoview}} more entry/entries before you can view other participants' entries.", + "errorapproving": "Error approving or unapproving entry.", + "errordeleting": "Error deleting the entry.", + "errormustsupplyvalue": "You must supply a value here.", + "expired": "Sorry, this activity closed on {{$a}} and is no longer available", + "fields": "Fields", + "latlongboth": "Both latitude and longitude are required.", + "menuchoose": "Choose...", + "more": "More", + "nomatch": "No matching entries found!", + "norecords": "No entries in database", + "notapproved": "Entry is not approved yet.", + "notopenyet": "Sorry, this activity is not available until {{$a}}", + "numrecords": "{{$a}} entries", + "other": "Other", + "recordapproved": "Entry approved", + "recorddeleted": "Entry deleted", + "recorddisapproved": "Entry unapproved", + "resetsettings": "Reset filters", + "search": "Search", + "selectedrequired": "All selected required", + "timeadded": "Time added", + "timemodified": "Time modified", + "usedate": "Include in search." +} diff --git a/www/addons/mod/data/lang/es-mx.json b/www/addons/mod/data/lang/es-mx.json new file mode 100644 index 00000000000..44cb6f922de --- /dev/null +++ b/www/addons/mod/data/lang/es-mx.json @@ -0,0 +1,39 @@ +{ + "addentries": "Añadir entradas", + "advancedsearch": "Búsqueda avanzada", + "alttext": "Texto alternativo", + "approve": "Aprobar", + "approved": "Aprobado", + "ascending": "Ascendente", + "authorfirstname": "Nombre del autor", + "authorlastname": "Apellidos del autor", + "confirmdeleterecord": "¿Está seguro de que desea eliminar esta entrada?", + "descending": "Descendente", + "disapprove": "Deshacer aprobación", + "emptyaddform": "¡No ha rellenado ningún campo!", + "entrieslefttoadd": "Debe añadir {{$a.entriesleft}} entrada(s) más antes de poder ver las entradas de otro participante.", + "entrieslefttoaddtoview": "Debe añadir {{$a.entrieslefttoview}} entrada(s) antes de poder ver las entradas de otros participantes.", + "errorapproving": "Error al aprobar o des_aprobar una entrada.", + "errordeleting": "Error al eliminar la entrada.", + "errormustsupplyvalue": "Usted debe proporcionar un valor aquí.", + "expired": "Lo sentimos, esta actividad se cerró el {{$a}} y ya no está disponible", + "fields": "Campos", + "latlongboth": "Tanto la Latitud como la Longitud son necesarias.", + "menuchoose": "Seleccionar...", + "more": "Más", + "nomatch": "No se han encontrado entradas", + "norecords": "No entradas en la base de datos", + "notapproved": "La entrada aún no ha sido aprobada.", + "notopenyet": "Lo sentimos, esta actividad no está disponible hasta {{$a}}", + "numrecords": "{{$a}} entradas", + "other": "Otro", + "recordapproved": "Entrada aprobada", + "recorddeleted": "Entrada eliminada", + "recorddisapproved": "Entrada desaprobada", + "resetsettings": "Restablecer filtros", + "search": "Buscar", + "selectedrequired": "Se requieren todos los seleccionados", + "timeadded": "Tiempo añadido", + "timemodified": "Tiempo modificado", + "usedate": "Incluir en búsqueda." +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/es.json b/www/addons/mod/data/lang/es.json new file mode 100644 index 00000000000..f03697158fa --- /dev/null +++ b/www/addons/mod/data/lang/es.json @@ -0,0 +1,37 @@ +{ + "addentries": "Añadir entradas", + "advancedsearch": "Búsqueda avanzada", + "alttext": "Texto alternativo", + "approve": "Aprobar", + "approved": "Aprobado", + "ascending": "Ascendente", + "authorfirstname": "Nombre del autor", + "authorlastname": "Apellido del autor", + "confirmdeleterecord": "¿Está seguro de que desea eliminar esta entrada?", + "descending": "Descendente", + "disapprove": "Desaprobar", + "emptyaddform": "¡No ha rellenado ningún campo!", + "entrieslefttoadd": "Debe agregar {{$a.entriesleft}} entrada(s) más para poder finalizar esta actividad", + "entrieslefttoaddtoview": "Debe añadir {{$a.entrieslefttoview}} entrada(s) antes de poder ver las entradas de otros participantes.", + "errormustsupplyvalue": "Debe proporcionar un valor aquí.", + "expired": "Lo sentimos, esta actividad se cerró el {{$a}} y ya no está disponible", + "fields": "Campos", + "latlongboth": "Tanto la latitud como la longitud son necesarias.", + "menuchoose": "Seleccionar...", + "more": "Más", + "nomatch": "No se han encontrado entradas", + "norecords": "No hay entradas en la base de datos", + "notapproved": "La entrada aún no ha sido aprobada.", + "notopenyet": "Lo sentimos, esta actividad no está disponible hasta {{$a}}", + "numrecords": "{{$a}} entradas", + "other": "Otro", + "recordapproved": "Entrada aprobada", + "recorddeleted": "Entrada eliminada", + "recorddisapproved": "Entrada desaprobada", + "resetsettings": "Restablecer filtros", + "search": "Buscar", + "selectedrequired": "Se requieren todos los seleccionados", + "timeadded": "Tiempo añadido", + "timemodified": "Tiempo modificado", + "usedate": "Incluir en la búsqueda" +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/eu.json b/www/addons/mod/data/lang/eu.json new file mode 100644 index 00000000000..e7e02cdd912 --- /dev/null +++ b/www/addons/mod/data/lang/eu.json @@ -0,0 +1,37 @@ +{ + "addentries": "Gehitu sarrerak", + "advancedsearch": "Bilaketa aurreratua", + "alttext": "Ordezko testua", + "approve": "Onartu", + "approved": "Onartuta", + "ascending": "Goranzkoa", + "authorfirstname": "Egilearen izena", + "authorlastname": "Egilearen deitura", + "confirmdeleterecord": "Ziur al zaude sarrera hau ezabatu nahi duzula?", + "descending": "Beheranzkoa", + "disapprove": "Onarpena desegin", + "emptyaddform": "Ez duzu eremuren bat bete!", + "entrieslefttoadd": "{{$a.entriesleft}} sarrera gehiago gehitu behar dituzu jarduera hau osatzeko.", + "entrieslefttoaddtoview": "{{$a.entrieslefttoview}} sarrera gehiago gehitu behar dituzu beste partaideen sarrerak ikusi ahal izateko.", + "errormustsupplyvalue": "Hemen balio bat eman behar duzu.", + "expired": "Barkatu, jarduera hau {{$a}} datan itxi zen eta dagoeneko ez dago eskuragarri", + "fields": "Eremuak", + "latlongboth": "Latitudea eta longitudea beharrekoak dira.", + "menuchoose": "Aukeratu...", + "more": "Gehiago", + "nomatch": "Ez da sarrera egokirik aurkitu!", + "norecords": "Datu-basean sarrerarik ez", + "notapproved": "Sarrera ez da oraindik onartu", + "notopenyet": "Barkatu, jarduera hau ez dago eskuragarri {{$a}} arte", + "numrecords": "{{$a}} sarrera(k)", + "other": "Beste bat", + "recordapproved": "Sarrera onartu da", + "recorddeleted": "Sarrera ezabatu da", + "recorddisapproved": "Onartu gabeko sarrera", + "resetsettings": "Berrabiarazi iragazkiak", + "search": "Bilatu", + "selectedrequired": "Aukeratutako guztia beharrezkoa", + "timeadded": "Denbora gehituta", + "timemodified": "Denbora aldatuta", + "usedate": "Sartu bilaketan." +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/fa.json b/www/addons/mod/data/lang/fa.json new file mode 100644 index 00000000000..c6a248a09b0 --- /dev/null +++ b/www/addons/mod/data/lang/fa.json @@ -0,0 +1,32 @@ +{ + "addentries": "داده‌هایی را اضافه کنید", + "advancedsearch": "جستجوی پیشرفته", + "alttext": "متن جایگزین", + "approve": "تایید", + "approved": "وضعیت تایید", + "ascending": "صعودی", + "authorfirstname": "نام وارد کننده", + "authorlastname": "نام خانوادگی وارد کننده", + "confirmdeleterecord": "آیا مطمئن هستید که می‌خواهید این مورد را حذف کنید؟", + "descending": "نزولی", + "emptyaddform": "شما هیچ فیلدی را پر نکردید!", + "entrieslefttoadd": "برای کامل کردن این فعالیت باید {{$a.entriesleft}} دادهٔ دیگر وارد کنید", + "entrieslefttoaddtoview": "باید {{$a.entrieslefttoview}} دادهٔ دیگر وارد کنید تا بتوانید داده‌های وارد شده توسط سایرین را ببینید.", + "expired": "متأسفیم، این فعالیت در {{$a}} بسته شد و دیگر در دسترس نیست", + "fields": "فیلدها", + "menuchoose": "انتخاب کنید...", + "more": "نمایش جزئیات", + "nomatch": "دادهٔ مطابقی پیدا نشد!", + "norecords": "بانک اطلاعاتی خالی است", + "notapproved": "دادهٔ ورودی هنوز تایید نشده است.", + "notopenyet": "با عرض پوزش، این فعالیت تا قبل از {{$a}} در دسترس نیست", + "numrecords": "{{$a}} دادهٔ ورودی", + "other": "غیره", + "recordapproved": "دادهٔ ورودی تایید شد", + "recorddeleted": "حذف شد", + "resetsettings": "بازنشانی فیلترها", + "search": "جستجو", + "selectedrequired": "تمامی گزینه‌های انتخاب شده لازم هستند", + "timeadded": "زمان اضافه شدن", + "timemodified": "زمان آخرین تغییر" +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/fr.json b/www/addons/mod/data/lang/fr.json new file mode 100644 index 00000000000..d9c3b73be8e --- /dev/null +++ b/www/addons/mod/data/lang/fr.json @@ -0,0 +1,39 @@ +{ + "addentries": "Ajouter des fiches", + "advancedsearch": "Recherche avancée", + "alttext": "Texte alternatif", + "approve": "Approuver", + "approved": "Approuvé", + "ascending": "Ascendant", + "authorfirstname": "Prénom auteur", + "authorlastname": "Nom auteur", + "confirmdeleterecord": "Voulez-vous vraiment supprimer cette fiche ?", + "descending": "Descendant", + "disapprove": "Retirer l'approbation", + "emptyaddform": "Vous n'avez rempli aucun champ !", + "entrieslefttoadd": "Vous devez ajouter encore {{$a.entriesleft}} fiches pour terminer cette activité", + "entrieslefttoaddtoview": "Vous devez ajouter encore {{$a.entrieslefttoview}} fiches avant de pouvoir consulter les fiches des autres participants.", + "errorapproving": "Erreur lors de l'approbation ou de la désapprobation de la fiche.", + "errordeleting": "Erreur lors de suppression de la fiche.", + "errormustsupplyvalue": "Veuillez renseigner une valeur.", + "expired": "Cette activité est fermée depuis {{$a}} et n'est plus disponible", + "fields": "Champs", + "latlongboth": "La latitude et la longitude sont requises.", + "menuchoose": "Sélectionner...", + "more": "Plus", + "nomatch": "Aucune fiche trouvée !", + "norecords": "Aucune fiche dans la base de données", + "notapproved": "La fiche n'est pas encore approuvée.", + "notopenyet": "Cette activité n'est pas disponible avant le {{$a}}", + "numrecords": "{{$a}} fiches", + "other": "Autre", + "recordapproved": "Fiche approuvée", + "recorddeleted": "Fiche supprimée", + "recorddisapproved": "Fiche désapprouvée", + "resetsettings": "Réinitialiser les filtres", + "search": "Recherche", + "selectedrequired": "Toute la sélection requise", + "timeadded": "Date ajout", + "timemodified": "Date modification", + "usedate": "Inclure dans la recherche." +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/he.json b/www/addons/mod/data/lang/he.json new file mode 100644 index 00000000000..e3495248234 --- /dev/null +++ b/www/addons/mod/data/lang/he.json @@ -0,0 +1,37 @@ +{ + "addentries": "הוספת פריטים", + "advancedsearch": "חיפוש מורחב", + "alttext": "תוכן חלופי", + "approve": "אישור", + "approved": "מאושר", + "ascending": "בסדר עולה", + "authorfirstname": "שם פרטי של המחבר", + "authorlastname": "שם משפחה של המחבר", + "confirmdeleterecord": "האם למחוק את הפריט הזה?", + "descending": "בסדר יורד", + "disapprove": "ביטול האישור", + "emptyaddform": "לא מילאת אף שדה!", + "entrieslefttoadd": "יש להזין {{$a.entriesleft}} פריטים נוספים בכדי להשלים פעילות זו", + "entrieslefttoaddtoview": "יש להזין {{$a.entrieslefttoview}} פריטים נוספים בכדי לראות פריטים של משתתפים אחרים.", + "errormustsupplyvalue": "יש להזין ערך בשדה זה.", + "expired": "מצטערים, פעילות זו נסגרה ב {{$a}} ואיננה זמינה יותר.", + "fields": "שדות", + "latlongboth": "נדרשים נתוני קו־רוחב וגם קו־אורך", + "menuchoose": "יש לבחור...", + "more": "עוד", + "nomatch": "לא נמצאו פריטים מתאימים!", + "norecords": "אין פריטים בבסיס הנתונים", + "notapproved": "הפריט עדיין לא אושר.", + "notopenyet": "מצטערים, פעילות זו איננה זמינה עד {{$a}} .", + "numrecords": "{{$a}} פריטים", + "other": "אחר", + "recordapproved": "הפריט אושר", + "recorddeleted": "הפריט נמחק", + "recorddisapproved": "הפריט לא מאושר", + "resetsettings": "איפוס שדות", + "search": "חיפוש", + "selectedrequired": "כל הנבחרים דרושים", + "timeadded": "זמן הוספה", + "timemodified": "זמן עדכון", + "usedate": "כלול בחיפוש" +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/hu.json b/www/addons/mod/data/lang/hu.json new file mode 100644 index 00000000000..a42ee251c97 --- /dev/null +++ b/www/addons/mod/data/lang/hu.json @@ -0,0 +1,37 @@ +{ + "addentries": "Bejegyzések hozzáadása", + "advancedsearch": "Részletes keresés", + "alttext": "Alternatív szöveg", + "approve": "Jóváhagy", + "approved": "Jóváhagyva", + "ascending": "Növekvő", + "authorfirstname": "Szerző keresztneve", + "authorlastname": "Szerző vezetékneve", + "confirmdeleterecord": "Biztosan törölni akarja ezt a bejegyzést?", + "descending": "Csökkenő", + "disapprove": "Jóváhagyás elvetése", + "emptyaddform": "Nem töltött ki egy mezőt sem!", + "entrieslefttoadd": "A tevékenység befejezéséhez {{$a.entriesleft}} további tételt kell hozzáadnia.", + "entrieslefttoaddtoview": "Még {{$a.entrieslefttoview}} bejegyzést kell hozzáadnia, mielőtt megtekintheti más résztvevők bejegyzéseit.", + "errormustsupplyvalue": "Itt egy értéket kell megadnia.", + "expired": "A tevékenység {{$a}} időpontban lezárult és már nem érhető el.", + "fields": "Mezők", + "latlongboth": "Mind a szélesség, mind a hosszúság kitöltendő.", + "menuchoose": "Választás...", + "more": "Tovább", + "nomatch": "Nincs egyező fogalom!", + "norecords": "Nincsenek bejegyzések az adatbázisban", + "notapproved": "A bejegyzés még nincs jóváhagyva.", + "notopenyet": "A tevékenység {{$a}} időpontig nem elérhető.", + "numrecords": "{{$a}} bejegyzés", + "other": "Más", + "recordapproved": "Bejegyzés jóváhagyva", + "recorddeleted": "Bejegyzés törölve", + "recorddisapproved": "Nem jóváhagyott fogalom", + "resetsettings": "Szűrők visszaállítása", + "search": "Keresés", + "selectedrequired": "Minden kiválasztott szükséges", + "timeadded": "Időpont hozzáadva", + "timemodified": "Időpont módosult", + "usedate": "Keresésben szerepeljen." +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/it.json b/www/addons/mod/data/lang/it.json new file mode 100644 index 00000000000..81aa26d1e83 --- /dev/null +++ b/www/addons/mod/data/lang/it.json @@ -0,0 +1,37 @@ +{ + "addentries": "Aggiungi record", + "advancedsearch": "Ricerca avanzata", + "alttext": "Testo alternativo", + "approve": "Approva", + "approved": "Approvato", + "ascending": "Crescente", + "authorfirstname": "Nome autore", + "authorlastname": "Cognome autore", + "confirmdeleterecord": "Stai per eliminare questo record. Ne sei certo?", + "descending": "Decrescente", + "disapprove": "Disapprova", + "emptyaddform": "Non hai riempito nessun campo!", + "entrieslefttoadd": "Per poter visualizzare i record inseriti dagli altri partecipanti è necessario inserire altri {{$a.entriesleft}} record.", + "entrieslefttoaddtoview": "Devi aggiungere {{$a.entrieslefttoview}} altri record prima di poter vedere i record degli altri partecipanti.", + "errormustsupplyvalue": "Devi inserire un valore.", + "expired": "Spiacente, l'attività non è più disponibile poiché è stata chiusa il {{$a}} ", + "fields": "Campi", + "latlongboth": "Devi compilare sia la latitudine sia la longitudine.", + "menuchoose": "Scegli...", + "more": "Dettagli", + "nomatch": "Non è stato trovato nessun record che corrisponda!", + "norecords": "Nessun record è presente nel Database", + "notapproved": "Il record inserito è in attesa di essere approvato.", + "notopenyet": "Spiacente, questa attività non sarà disponibile prima del {{$a}}", + "numrecords": "{{$a}} record", + "other": "Altro", + "recordapproved": "Record approvati", + "recorddeleted": "Il record è stato eliminato", + "recorddisapproved": "Record disapprovato", + "resetsettings": "Reimposta filtri", + "search": "Cerca", + "selectedrequired": "Necessari tutti i selezionati", + "timeadded": "Data/ora inserimento", + "timemodified": "Data/ora modifica", + "usedate": "Includi nella ricerca." +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/ja.json b/www/addons/mod/data/lang/ja.json new file mode 100644 index 00000000000..a779faabe27 --- /dev/null +++ b/www/addons/mod/data/lang/ja.json @@ -0,0 +1,37 @@ +{ + "addentries": "エントリを追加する", + "advancedsearch": "高度な検索", + "alttext": "代替テキスト", + "approve": "承認", + "approved": "承認日時", + "ascending": "昇順", + "authorfirstname": "著者の名", + "authorlastname": "著者の姓", + "confirmdeleterecord": "本当にこのエントリを削除してもよろしいですか?", + "descending": "降順", + "disapprove": "承認を取り消す", + "emptyaddform": "あなたはどのフィールドにも入力していません!", + "entrieslefttoadd": "この活動を完了するにはさらに {{$a.entriesleft}} 件以上のエントリを追加してください。", + "entrieslefttoaddtoview": "他の参加者のエントリを閲覧するにはさらに {{$a.entrieslefttoview}} 件以上のエントリを追加してください。", + "errormustsupplyvalue": "あなたはここで値を提供する必要があります。", + "expired": "申し訳ございません、この活動は {{$a}} に終了して利用することはできません。", + "fields": "フィールド", + "latlongboth": "緯度および経度の両方とも必須です。", + "menuchoose": "選択 ...", + "more": "詳細", + "nomatch": "該当するエントリが見つかりませんでした!", + "norecords": "データベースにエントリはありません。", + "notapproved": "エントリはまだ承認されていません。", + "notopenyet": "申し訳ございません、この活動は {{$a}} まで利用できません。", + "numrecords": "{{$a}} エントリ", + "other": "その他", + "recordapproved": "エントリが承認されました。", + "recorddeleted": "エントリが削除されました。", + "recorddisapproved": "エントリ未承認", + "resetsettings": "フィルタをリセットする", + "search": "検索", + "selectedrequired": "選択したすべてを含む", + "timeadded": "追加日時", + "timemodified": "修正日時", + "usedate": "検索に含む" +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/lt.json b/www/addons/mod/data/lang/lt.json new file mode 100644 index 00000000000..1c83b6faf07 --- /dev/null +++ b/www/addons/mod/data/lang/lt.json @@ -0,0 +1,37 @@ +{ + "addentries": "Įtraukti įrašus", + "advancedsearch": "Išplėstinė paieška", + "alttext": "Alternatyvusis tekstas", + "approve": "Patvirtinti", + "approved": "Patvirtinta", + "ascending": "Didėjimo tvarka", + "authorfirstname": "Autoriaus vardas", + "authorlastname": "Autoriaus pavardė", + "confirmdeleterecord": "Ar tikrai norite naikinti šį įrašą?", + "descending": "Mažėjimo tvarka", + "disapprove": "Atšaukti patvirtinimą", + "emptyaddform": "Neužpildėte jokių laukų!", + "entrieslefttoadd": "Turite įtraukti dar {{$a.entriesleft}} įrašus (-ų), kad galėtumėte užbaigti šią veiklą", + "entrieslefttoaddtoview": "Turite įtraukti dar {{$a.entrieslefttoview}} įrašus (-ų), kad galėtumėte peržiūrėti kitų dalyvių įrašus.", + "errormustsupplyvalue": "Privalote pateikti reikšmę čia.", + "expired": "Apgailestaujame, ši veikla uždaryta {{$a}} ir nebegalima", + "fields": "Laukai", + "latlongboth": "Abu, platuma ir ilguma, yra privalomi.", + "menuchoose": "Pasirinkite...", + "more": "Daugiau", + "nomatch": "Nerasta atitinkančių įrašų!", + "norecords": "Duomenų bazėje nėra įrašų", + "notapproved": "Įrašas dar nepatvirtintas.", + "notopenyet": "Apgailestaujame, ši veikla negalima iki {{$a}}", + "numrecords": "{{$a}} įrašai (-ų)", + "other": "Kita", + "recordapproved": "Įrašas patvirtintas", + "recorddeleted": "Įrašas panaikintas", + "recorddisapproved": "Įrašas nepatvirtintas", + "resetsettings": "Nustatyti filtrus iš naujo", + "search": "Ieškoti", + "selectedrequired": "Visi pasirinkti būtini", + "timeadded": "Įtraukimo laikas", + "timemodified": "Modifikavimo laikas", + "usedate": "Įtraukti į paiešką." +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/nl.json b/www/addons/mod/data/lang/nl.json new file mode 100644 index 00000000000..deb0be88f87 --- /dev/null +++ b/www/addons/mod/data/lang/nl.json @@ -0,0 +1,39 @@ +{ + "addentries": "Items goedkeuren", + "advancedsearch": "Geavanceerd zoeken", + "alttext": "Alternatieve tekst", + "approve": "Goedkeuren", + "approved": "Goedgekeurd", + "ascending": "Oplopend", + "authorfirstname": "Voornaam auteur", + "authorlastname": "Achternaam auteur", + "confirmdeleterecord": "Je gaat deze record verwijderen. Ben je zeker?", + "descending": "Aflopend", + "disapprove": "Verwerp", + "emptyaddform": "Je hebt geen velden ingevuld!", + "entrieslefttoadd": "Je moet {{$a.entriesleft}} meer item(s) ingeven voor je de items van anderen kunt zien.", + "entrieslefttoaddtoview": "je moet {{$a.entrieslefttoview}} items meer toevoegen voor je de items van anderen kan zien.", + "errorapproving": "Fout bij het goedkeuren of verwerpen van het nieuwe item.", + "errordeleting": "Fout bij het verwijderen van het item.", + "errormustsupplyvalue": "Je moet hier een waarde geven.", + "expired": "Deze activiteit is gesloten op {{$a}} en is niet langer beschikbaar", + "fields": "Velden", + "latlongboth": "Zowel de breedtegraad als de lengtegraad zijn vereist.", + "menuchoose": "Kies...", + "more": "Meer", + "nomatch": "Geen overeenkomende items gevonden", + "norecords": "Geen items in de databank", + "notapproved": "Item is nog niet goedgekeurd", + "notopenyet": "Deze actieviteit is niet beschikbaar tot {{$a}}", + "numrecords": "{{$a}} records", + "other": "Andere", + "recordapproved": "Item goedgekeurd", + "recorddeleted": "Record verwijderd", + "recorddisapproved": "Item verworpen", + "resetsettings": "Reset filters", + "search": "Zoek", + "selectedrequired": "Alle geselecteerde vereist", + "timeadded": "Toegevoegd op", + "timemodified": "Gewijzigd op", + "usedate": "Ook zoeken" +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/pl.json b/www/addons/mod/data/lang/pl.json new file mode 100644 index 00000000000..3d8d44e49c3 --- /dev/null +++ b/www/addons/mod/data/lang/pl.json @@ -0,0 +1,37 @@ +{ + "addentries": "Dodaj wpisy", + "advancedsearch": "Wyszukiwanie zaawansowane", + "alttext": "Alternatywny tekst", + "approve": "Zatwierdź", + "approved": "Zatwierdzony", + "ascending": "Rosnąco", + "authorfirstname": "Imię autora", + "authorlastname": "Nazwisko autora", + "confirmdeleterecord": "Na pewno chcesz usunąć ten wpis?", + "descending": "Malejąco", + "disapprove": "Cofnij zatwierdzenie", + "emptyaddform": "Nie wypełniłeś wszystkich pól", + "entrieslefttoadd": "Musisz dodać {{$a.entriesleft}} więcej wpisów, aby zakończyć tą aktywność", + "entrieslefttoaddtoview": "Musisz dodać {{$a.entrieslefttoview}} więcej wpisów, aby móc wyświetlać wpisy innych użytkowników.", + "errormustsupplyvalue": "Musisz podać wartość tutaj.", + "expired": "Niestety, ta aktywność została zamknięta {{$a}} i nie jest już dłużej dostępna", + "fields": "Pola", + "latlongboth": "Wymagana jest zarówno szerokość i długość geograficzna.", + "menuchoose": "Wybierz...", + "more": "Więcej", + "nomatch": "Żaden wpis nie został znaleziony.", + "norecords": "Brak wpisów w bazie danych", + "notapproved": "Wpis nie jest jeszcze zatwierdzony.", + "notopenyet": "Niestety, ta aktywność jest niedostępna aż do {{$a}}", + "numrecords": "{{$a}} wpisów", + "other": "Inne", + "recordapproved": "Wpis zatwierdzony", + "recorddeleted": "Wpis usunięty", + "recorddisapproved": "Wpis odrzucony", + "resetsettings": "Resetuj pola", + "search": "Szukaj", + "selectedrequired": "Wszystkie zaznaczone są wymagane", + "timeadded": "Dodano czas", + "timemodified": "Zmodyfikowano czas", + "usedate": "Uwzględnij w wyszukiwaniu." +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/pt-br.json b/www/addons/mod/data/lang/pt-br.json new file mode 100644 index 00000000000..6574d31f4c8 --- /dev/null +++ b/www/addons/mod/data/lang/pt-br.json @@ -0,0 +1,37 @@ +{ + "addentries": "Acrescentar itens", + "advancedsearch": "Busca avançada", + "alttext": "Texto alternativo", + "approve": "Aprovar", + "approved": "Aprovado", + "ascending": "Crescente", + "authorfirstname": "Nome do autor", + "authorlastname": "Sobrenome do autor", + "confirmdeleterecord": "Tem certeza que quer excluir este item?", + "descending": "Decrescente", + "disapprove": "Desfazer aprovação", + "emptyaddform": "Você não completou nenhum campo!", + "entrieslefttoadd": "Você precisa adicionar mais {{$a.entriesleft}} item(ns) para completar esta atividade", + "entrieslefttoaddtoview": "Você precisa adicionar mais {{$a.entrieslefttoview}} item(ns) antes de poder ver os itens dos outros participantes.", + "errormustsupplyvalue": "Você precisa fornecer um valor aqui.", + "expired": "Sinto muito, mas esta atividade foi fechada em {{$a}} e não está mais disponível", + "fields": "Campos", + "latlongboth": "Tanto a Latitude quanto a Longitude devem ser preenchidas.", + "menuchoose": "Selecionar...", + "more": "Mais", + "nomatch": "Nenhum item correspondente encontrado!", + "norecords": "Nenhum item na base de dados", + "notapproved": "O item ainda não foi aprovado.", + "notopenyet": "Desculpe, esta atividade não está disponível até {{$a}}", + "numrecords": "{{$a}} itens", + "other": "Outro", + "recordapproved": "Item aprovado", + "recorddeleted": "Item cancelado", + "recorddisapproved": "Entrada não aprovada", + "resetsettings": "Reconfigurar filtros", + "search": "Busca", + "selectedrequired": "Todos os itens selecionados são obrigatórios", + "timeadded": "Tempo adicionado", + "timemodified": "Tempo modificado", + "usedate": "Incluir na pesquisa." +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/pt.json b/www/addons/mod/data/lang/pt.json new file mode 100644 index 00000000000..fe1adf4e1cb --- /dev/null +++ b/www/addons/mod/data/lang/pt.json @@ -0,0 +1,37 @@ +{ + "addentries": "Adicionar registos", + "advancedsearch": "Pesquisa avançada", + "alttext": "Texto alternativo", + "approve": "Aprovar", + "approved": "Aprovado", + "ascending": "Ascendente", + "authorfirstname": "Primeiro nome do autor", + "authorlastname": "Apelido do autor", + "confirmdeleterecord": "Tem a certeza de que pretende apagar este registo?", + "descending": "Descendente", + "disapprove": "Anular aprovação", + "emptyaddform": "Não preencheu nenhum campo!", + "entrieslefttoadd": "Tem que adicionar mais {{$a.entriesleft}} registo(s) para completar esta atividade", + "entrieslefttoaddtoview": "Tem que adicionar mais {{$a.entrieslefttoview}} registos para conseguir visualizar as entradas dos outros participantes.", + "errormustsupplyvalue": "Indique aqui um valor.", + "expired": "A atividade terminou em {{$a}} e não se encontra disponível", + "fields": "Campos", + "latlongboth": "É necessário a latitude e a longitude.", + "menuchoose": "Selecione...", + "more": "Mais", + "nomatch": "Não foram encontrados registos correspondentes!", + "norecords": "Não existem registos na base de dados", + "notapproved": "O registo ainda não foi aprovado.", + "notopenyet": "A atividade apenas será disponibilizada em {{$a}}", + "numrecords": "{{$a}} registos", + "other": "Outro", + "recordapproved": "Registo aprovado", + "recorddeleted": "Registo apagado", + "recorddisapproved": "Entrada não aprovada", + "resetsettings": "Reiniciar filtros", + "search": "Pesquisar", + "selectedrequired": "Todos os selecionados são obrigatórios", + "timeadded": "Data de criação", + "timemodified": "Data da última edição", + "usedate": "Incluir na pesquisa." +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/ro.json b/www/addons/mod/data/lang/ro.json new file mode 100644 index 00000000000..76ddb872d74 --- /dev/null +++ b/www/addons/mod/data/lang/ro.json @@ -0,0 +1,36 @@ +{ + "addentries": "Adaugă articole", + "advancedsearch": "Căutare complexă", + "alttext": "Text alternativ", + "approve": "Aprobă", + "approved": "Aprobat", + "ascending": "Crescător", + "authorfirstname": "Prenume autor", + "authorlastname": "Nume autor", + "confirmdeleterecord": "Sunteţi sigur că doriţi să ştergeţi acest articol?", + "descending": "Descrescător", + "disapprove": "Anulați aprobarea", + "emptyaddform": "Nu aţi completat niciun câmp!", + "entrieslefttoadd": "Pentru a finaliza această activitate trebuie să mai adăugaţi {{$a.entriesleft}} more entry/entries articole", + "entrieslefttoaddtoview": "Pentru a vedea articolele postate de ceilalţi participanţi trebuie să mai adăugaţi {{$a.entrieslefttoview}} articole.", + "errormustsupplyvalue": "Trebuie să inserați o valoare aici.", + "expired": "Ne pare rău, activitatea s-a închis în {{$a}} și nu mai este disponibilă", + "fields": "Câmpuri", + "menuchoose": "Alegeţi...", + "more": "Detalii suplimentare", + "nomatch": "Nu s-au găsit articole care să corespundă criteriilor selectate!", + "norecords": "Nu s-au găsit articole în baza de date", + "notapproved": "Acest articol nu a fost încă aprobat.", + "notopenyet": "Ne pare rău, această activitate nu este disponibilă până în {{$a}}", + "numrecords": "{{$a}} articole", + "other": "Altele", + "recordapproved": "Articol aprobat", + "recorddeleted": "Articol şters", + "recorddisapproved": "Postare neaprobată", + "resetsettings": "Resetează filtre", + "search": "Căutare", + "selectedrequired": "Toate elementele selectate sunt obligatorii", + "timeadded": "Ora la care a fost adăugat", + "timemodified": "Ora la care a fost modificat", + "usedate": "Include în căutare" +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/ru.json b/www/addons/mod/data/lang/ru.json new file mode 100644 index 00000000000..260f25ebd98 --- /dev/null +++ b/www/addons/mod/data/lang/ru.json @@ -0,0 +1,37 @@ +{ + "addentries": "Добавить записи", + "advancedsearch": "Расширенный поиск", + "alttext": "Альтернативный текст", + "approve": "Одобрить", + "approved": "Одобрено", + "ascending": "По возрастанию", + "authorfirstname": "Имя автора", + "authorlastname": "Фамилия автора", + "confirmdeleterecord": "Вы уверены, что хотите удалить эту запись?", + "descending": "По убыванию", + "disapprove": "Отменить одобрение", + "emptyaddform": "Вы не заполнили ни одного поля", + "entrieslefttoadd": "Чтобы просматривать записи других участников Вы должны добавить еще записи - ({{$a.entriesleft}})", + "entrieslefttoaddtoview": "Вы должны еще добавить записи ({{$a.entrieslefttoview}}), прежде чем сможете просматривать записи других участников.", + "errormustsupplyvalue": "Вы должны здесь указать значение.", + "expired": "К сожалению, эта база данных закрыта {{$a}} и больше не доступна", + "fields": "Поля", + "latlongboth": "Необходимо задать и широту, и долготу.", + "menuchoose": "Выбрать...", + "more": "Просмотр записи", + "nomatch": "Соответствующих записей не найдено!", + "norecords": "Нет записей в базе данных", + "notapproved": "Запись пока не одобрена.", + "notopenyet": "Извините, этот элемент курса не доступен до {{$a}}", + "numrecords": "{{$a}} записей", + "other": "Другое", + "recordapproved": "Запись одобрена", + "recorddeleted": "Запись удалена", + "recorddisapproved": "Снято одобрение записи", + "resetsettings": "Сбросить фильтры", + "search": "Поиск", + "selectedrequired": "Требуются все выбранные", + "timeadded": "Время добавления", + "timemodified": "Время изменения", + "usedate": "Включить в поиск" +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/sr-cr.json b/www/addons/mod/data/lang/sr-cr.json new file mode 100644 index 00000000000..a8ce67ae329 --- /dev/null +++ b/www/addons/mod/data/lang/sr-cr.json @@ -0,0 +1,39 @@ +{ + "addentries": "Додај уносе", + "advancedsearch": "Напредно претраживање", + "alttext": "Алтернативни текст", + "approve": "Одобри", + "approved": "Одобрено", + "ascending": "Растуће", + "authorfirstname": "Име аутора", + "authorlastname": "Презиме аутора", + "confirmdeleterecord": "Да ли сте сигурни да желите да обришете овај унос?", + "descending": "Опадајуће", + "disapprove": "Повуци одобрење", + "emptyaddform": "Нисте испунили ниједно поље!", + "entrieslefttoadd": "Морате да додате још {{$a.entriesleft}} унос(а) како бисте завршили ову активност", + "entrieslefttoaddtoview": "Морате да додате још {{$a.entrieslefttoview}} уноса пре него што будете могли да видите уносе других корисника.", + "errorapproving": "Грешка приликом одобравања или неодобравања уноса.", + "errordeleting": "Грешка приликом брисања уноса.", + "errormustsupplyvalue": "Морате овде задати вредност.", + "expired": "Нажалост, ова активност је затворена {$}} и више није доступна", + "fields": "Поља", + "latlongboth": "Поља за географску ширина и дужина су обавезна.", + "menuchoose": "Изаберите...", + "more": "Још", + "nomatch": "Нема уноса који се поклапају!", + "norecords": "Нема уноса у бази података", + "notapproved": "Унос још није одобрен", + "notopenyet": "Нажалост, ова активност није доступна до {{$a}}", + "numrecords": "{{$a}} уноса", + "other": "Друго", + "recordapproved": "Унос је одобрен", + "recorddeleted": "Унос је обрисан", + "recorddisapproved": "Унос није одобрен", + "resetsettings": "Ресетуј филтере", + "search": "Тражи", + "selectedrequired": "Све изабрано обавезно", + "timeadded": "Време додавања", + "timemodified": "Време измене", + "usedate": "Укључи у претраживање." +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/sr-lt.json b/www/addons/mod/data/lang/sr-lt.json new file mode 100644 index 00000000000..01163f8f244 --- /dev/null +++ b/www/addons/mod/data/lang/sr-lt.json @@ -0,0 +1,39 @@ +{ + "addentries": "Dodaj unose", + "advancedsearch": "Napredno pretraživanje", + "alttext": "Alternativni tekst", + "approve": "Odobri", + "approved": "Odobreno", + "ascending": "Rastuće", + "authorfirstname": "Ime autora", + "authorlastname": "Prezime autora", + "confirmdeleterecord": "Da li ste sigurni da želite da obrišete ovaj unos?", + "descending": "Opadajuće", + "disapprove": "Povuci odobrenje", + "emptyaddform": "Niste ispunili nijedno polje!", + "entrieslefttoadd": "Morate da dodate još {{$a.entriesleft}} unos(a) kako biste završili ovu aktivnost", + "entrieslefttoaddtoview": "Morate da dodate još {{$a.entrieslefttoview}} unosa pre nego što budete mogli da vidite unose drugih korisnika.", + "errorapproving": "Greška prilikom odobravanja ili neodobravanja unosa.", + "errordeleting": "Greška prilikom brisanja unosa.", + "errormustsupplyvalue": "Morate ovde zadati vrednost.", + "expired": "Nažalost, ova aktivnost je zatvorena {$}} i više nije dostupna", + "fields": "Polja", + "latlongboth": "Polja za geografsku širina i dužina su obavezna.", + "menuchoose": "Izaberite...", + "more": "Još", + "nomatch": "Nema unosa koji se poklapaju!", + "norecords": "Nema unosa u bazi podataka", + "notapproved": "Unos još nije odobren", + "notopenyet": "Nažalost, ova aktivnost nije dostupna do {{$a}}", + "numrecords": "{{$a}} unosa", + "other": "Drugo", + "recordapproved": "Unos je odobren", + "recorddeleted": "Unos je obrisan", + "recorddisapproved": "Unos nije odobren", + "resetsettings": "Resetuj filtere", + "search": "Traži", + "selectedrequired": "Sve izabrano obavezno", + "timeadded": "Vreme dodavanja", + "timemodified": "Vreme izmene", + "usedate": "Uključi u pretraživanje." +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/sv.json b/www/addons/mod/data/lang/sv.json new file mode 100644 index 00000000000..a99d7225328 --- /dev/null +++ b/www/addons/mod/data/lang/sv.json @@ -0,0 +1,33 @@ +{ + "addentries": "Lägg till bidrag", + "advancedsearch": "Avancerad sökning", + "alttext": "Alternativ text", + "approve": "Godkänn", + "approved": "Godkänd", + "ascending": "Stigande", + "authorfirstname": "Författarens förnamn", + "authorlastname": "Författarens efternamn", + "confirmdeleterecord": "Är Du säker på att du vill ta bort det här bidraget?", + "descending": "Fallande", + "emptyaddform": "Du fyllde inte i alla fält!", + "entrieslefttoadd": "Du måste lägga till {{$a.entriesleft}} fler bidrag för att fullfölja den här aktiviteten.", + "entrieslefttoaddtoview": "Du måste lägga till {{$a.entrieslefttoview}} fler bidrag innan du kan få se de andra deltagarnas bidrag.", + "expired": "Den här aktiviteten stängdes tyvärr den {{$a}} och är inte längre tillgänglig.", + "fields": "Fält", + "menuchoose": "Välj...", + "more": "Fler", + "nomatch": "Det gick inte att hitta några matchande bidrag!", + "norecords": "Det finns inga bidrag i databasen", + "notapproved": "Bidraget är inte godkänt än", + "notopenyet": "Den här aktiviteten är tyvärr inte tillgänglig förrän {$}}", + "numrecords": "{{$a}} bidrag", + "other": "Övrigt", + "recordapproved": "Bidraget har godkänts", + "recorddeleted": "Bidraget har tagits bort", + "resetsettings": "Filter för återställning", + "search": "Sök", + "selectedrequired": "Alla de valda är obligatoriska", + "timeadded": "Tillagd när", + "timemodified": "Modifierad när", + "usedate": "Ta med i sökning" +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/tr.json b/www/addons/mod/data/lang/tr.json new file mode 100644 index 00000000000..c250d4477cb --- /dev/null +++ b/www/addons/mod/data/lang/tr.json @@ -0,0 +1,37 @@ +{ + "addentries": "Kayıtları ekle", + "advancedsearch": "Gelişmiş arama", + "alttext": "Alternatif metin", + "approve": "Onayla", + "approved": "Onaylandı", + "ascending": "Artan", + "authorfirstname": "Yazarın adı", + "authorlastname": "Yazarın soyadı", + "confirmdeleterecord": "Bu kaydı silmek istediğinizden emin misiniz?", + "descending": "Azalan", + "disapprove": "Onayı geri al", + "emptyaddform": "Hiçbir alanı doldurmadınız!", + "entrieslefttoadd": "Bu etkinliği bitirmek için {{$a.entriesleft}} kayıt daha eklemelisiniz.", + "entrieslefttoaddtoview": "Diğer katılımcıların kayıtlarını görebilmek için {{$a.entrieslefttoview}} kayıt daha eklemelisiniz.", + "errormustsupplyvalue": "Burada bir değer vermelisiniz.", + "expired": "Maalesef, bu etkinlik {{$a}} tarihinde kapandı ve artık mevcut değil", + "fields": "Alanlar", + "latlongboth": "Enlem ve boylam gereklidir.", + "menuchoose": "Seç...", + "more": "Dahası", + "nomatch": "Eşleşen kayıt bulunamadı!", + "norecords": "Veritabanında kayıt yok", + "notapproved": "Kayıt henüz onaylanmamış.", + "notopenyet": "Üzgünüz, bu etkinlik {{$a}} kadar kullanılamıyor", + "numrecords": "{{$a}} kayıt", + "other": "Diğer", + "recordapproved": "Kayıt onaylandı", + "recorddeleted": "Kayıt silindi", + "recorddisapproved": "Giriş onaylanmadı", + "resetsettings": "Alanları Temizle", + "search": "Ara", + "selectedrequired": "Tüm seçililer gereklidir", + "timeadded": "Ekleme zamanı", + "timemodified": "Düzenleme zamanı", + "usedate": "Aramaya dahil et." +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/uk.json b/www/addons/mod/data/lang/uk.json new file mode 100644 index 00000000000..5221866c401 --- /dev/null +++ b/www/addons/mod/data/lang/uk.json @@ -0,0 +1,37 @@ +{ + "addentries": "Додати записи", + "advancedsearch": "Розширений пошук", + "alttext": "Альтернативний текст", + "approve": "Прийняти", + "approved": "Прийнято", + "ascending": "за зростанням", + "authorfirstname": "Ім’я автора", + "authorlastname": "Прізвище автора", + "confirmdeleterecord": "Ви впевнені, що хочете видалити цей запис?", + "descending": "за спаданням", + "disapprove": "Скасувати схвалення", + "emptyaddform": "Ви не заповнили жодного поля!", + "entrieslefttoadd": "Вам потрібно додати більше чим {{$a}} записів перед тим, як ви зможете побачити записи інших учасників.", + "entrieslefttoaddtoview": "Ви повинні ввести більше чим {{$a.entrieslefttoview}} запис(ів) перед тим, як матимете змогу бачити записи інших.", + "errormustsupplyvalue": "Ви повинні тут вказати значення.", + "expired": "На жаль, ця діяльність закрита на {{$a}} і більше не доступна", + "fields": "Поля", + "latlongboth": "Широта і довгота є обов’язковими.", + "menuchoose": "Вибрати...", + "more": "Детальний перегляд...", + "nomatch": "Жодного запису не знайдено!", + "norecords": "Немає записів у базі даних", + "notapproved": "Запис ще не схвалено", + "notopenyet": "ця діяльність не доступна до {{$a}}", + "numrecords": "{{$a}} записів", + "other": "Інше", + "recordapproved": "Запис погоджено", + "recorddeleted": "Запис вилучено", + "recorddisapproved": "Запис не схвалено", + "resetsettings": "Скинути фільтри", + "search": "Пошук", + "selectedrequired": "Всі відібрані вимоги", + "timeadded": "Час введення", + "timemodified": "Час модифікації", + "usedate": "Включити в пошук" +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/zh-cn.json b/www/addons/mod/data/lang/zh-cn.json new file mode 100644 index 00000000000..6ee9c6d0542 --- /dev/null +++ b/www/addons/mod/data/lang/zh-cn.json @@ -0,0 +1,36 @@ +{ + "addentries": "添加条目", + "advancedsearch": "高级搜索", + "alttext": "可替代文本", + "approve": "批准", + "approved": "许可", + "ascending": "升序", + "authorfirstname": "姓", + "authorlastname": "名", + "confirmdeleterecord": "您确定要删除这条记录?", + "descending": "降序", + "disapprove": "撤消审核", + "emptyaddform": "您未填写任何字段", + "entrieslefttoadd": "在完成此活动前,您还需添加 {{$a.entriesleft}} 条目", + "entrieslefttoaddtoview": "在查看其他参与者的条目前,您还需添加 {{$a.entrieslefttoview}} 条目", + "errormustsupplyvalue": "这儿你必须提供一个值。", + "expired": "对不起,这项活动截止于{{$a}},不再有效", + "fields": "字段", + "menuchoose": "选择...", + "more": "更多", + "nomatch": "未找到匹配的条目", + "norecords": "数据库中无条目", + "notapproved": "条目尚未被核准。", + "notopenyet": "抱歉,此活动直到{{$a}}才可用", + "numrecords": "{{$a}} 条记录", + "other": "其他", + "recordapproved": "记录已核准", + "recorddeleted": "记录已删除", + "recorddisapproved": "不可进入", + "resetsettings": "重置字段", + "search": "搜索", + "selectedrequired": "全选", + "timeadded": "追加时间", + "timemodified": "编辑时间", + "usedate": "包含到搜索中。" +} \ No newline at end of file diff --git a/www/addons/mod/data/lang/zh-tw.json b/www/addons/mod/data/lang/zh-tw.json new file mode 100644 index 00000000000..7ccf7b95f73 --- /dev/null +++ b/www/addons/mod/data/lang/zh-tw.json @@ -0,0 +1,37 @@ +{ + "addentries": "新增條目", + "advancedsearch": "進階搜尋", + "alttext": "替代文字", + "approve": "審核", + "approved": "已核准", + "ascending": "升冪", + "authorfirstname": "作者的名字", + "authorlastname": "作者的姓氏", + "confirmdeleterecord": "您確定要刪除這筆資料嗎?", + "descending": "降冪", + "disapprove": "取消核准", + "emptyaddform": "您沒有填入任何欄位!", + "entrieslefttoadd": "在您要瀏覽其他同學提供的資料前,您必須要再新增{{$a.entriesleft}} 筆資料。", + "entrieslefttoaddtoview": "您必須新增{{$a.entrieslefttoview}}筆以上資料,才能夠看到其他同學提供的資料。", + "errormustsupplyvalue": "這裡你必須提供一個數值。", + "expired": "抱歉,這活動已經在 {{$a}}關閉,已經無法使用。", + "fields": "欄位", + "latlongboth": "緯度和經度兩者都要填寫", + "menuchoose": "選擇...", + "more": "更多", + "nomatch": "找不到符合的資料!", + "norecords": "資料庫中沒有資料", + "notapproved": "資料尚未審核。", + "notopenyet": "抱歉,這一活動要等到{{$a}}才開始", + "numrecords": "{{$a}} 筆資料", + "other": "其他", + "recordapproved": "資料已審核", + "recorddeleted": "資料已刪除", + "recorddisapproved": "不可進入", + "resetsettings": "重設欄位", + "search": "搜尋", + "selectedrequired": "所有必要的選擇", + "timeadded": "新增的時間", + "timemodified": "修改的時間", + "usedate": "包含在搜尋中" +} \ No newline at end of file diff --git a/www/addons/mod/data/main.js b/www/addons/mod/data/main.js new file mode 100644 index 00000000000..3ce8a7aa2eb --- /dev/null +++ b/www/addons/mod/data/main.js @@ -0,0 +1,91 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data', ['mm.core']) + +.constant('mmaModDataComponent', 'mmaModData') +.constant('mmaModDataEventEntryChanged', 'mma-mod_data_entry_changed') +.constant('mmaModDataPerPage', 25) +.constant('mmaModDataEventAutomSynced', 'mma_mod_data_autom_synced') +.constant('mmaModDataSyncTime', 300000) // In milliseconds. + +.config(function($stateProvider) { + + $stateProvider + + .state('site.mod_data', { + url: '/mod_data', + params: { + module: null, + courseid: null, + group: null + }, + views: { + 'site': { + controller: 'mmaModDataIndexCtrl', + templateUrl: 'addons/mod/data/templates/index.html' + } + } + }) + + .state('site.mod_data-entry', { + url: '/mod_data-entry', + params: { + module: null, + moduleid: null, // Redundant parameter to fix a problem passing object as parameters. To be fixed in MOBILE-1370. + courseid: null, + entryid: null, + page: null, + group: null + }, + views: { + 'site': { + controller: 'mmaModDataEntryCtrl', + templateUrl: 'addons/mod/data/templates/entry.html' + } + } + }) + + .state('site.mod_data-edit', { + url: '/mod_data-edit', + params: { + module: null, + moduleid: null, // Redundant parameter to fix a problem passing object as parameters. To be fixed in MOBILE-1370. + courseid: null, + entryid: null, + group: null + }, + views: { + 'site': { + controller: 'mmaModDataEditCtrl', + templateUrl: 'addons/mod/data/templates/edit.html' + } + } + }); +}) + +.config(function($mmCourseDelegateProvider, $mmContentLinksDelegateProvider, $mmCoursePrefetchDelegateProvider) { + $mmCourseDelegateProvider.registerContentHandler('mmaModData', 'data', '$mmaModDataHandlers.courseContent'); + $mmCoursePrefetchDelegateProvider.registerPrefetchHandler('mmaModData', 'data', '$mmaModDataPrefetchHandler'); + $mmContentLinksDelegateProvider.registerLinkHandler('mmaModData:index', '$mmaModDataHandlers.indexLinksHandler'); + $mmContentLinksDelegateProvider.registerLinkHandler('mmaModData:entry', '$mmaModDataHandlers.showEntryLinksHandler'); + $mmContentLinksDelegateProvider.registerLinkHandler('mmaModData:approve', '$mmaModDataHandlers.approveEntryLinksHandler'); + $mmContentLinksDelegateProvider.registerLinkHandler('mmaModData:delete', '$mmaModDataHandlers.deleteEntryLinksHandler'); + $mmContentLinksDelegateProvider.registerLinkHandler('mmaModData:edit', '$mmaModDataHandlers.editEntryLinksHandler'); +}) + +.run(function($mmCronDelegate) { + // Register sync handler. + $mmCronDelegate.register('mmaModData', '$mmaModDataHandlers.syncHandler'); +}); diff --git a/www/addons/mod/data/scss/styles.scss b/www/addons/mod/data/scss/styles.scss new file mode 100644 index 00000000000..4fcffde0547 --- /dev/null +++ b/www/addons/mod/data/scss/styles.scss @@ -0,0 +1,138 @@ + +.mm-site_mod_data { + .recordcheckbox { + display: none; + } +} + +.mm-data-contents { + overflow: visible; + white-space: normal; + word-break: break-word; + padding: $item-padding; + background-color: white; + border-top-width: $item-border-width; + border-bottom-width: $item-border-width; + border-style: solid; + border-color: $item-default-border; + + table, tbody { + display: block; + } + + tr { + @extend .row; + padding: 0; + } + + td, th { + @extend .col; + } +} + +#mma-mod_data-advanced-search-form, +#mma-mod_data-edit-form { + table { + width: 100%; + } + td { + vertical-align: top; + } + + textarea, + input[type="text"], + input[type="password"], + input[type="datetime"], + input[type="datetime-local"], + input[type="date"], + input[type="month"], + input[type="time"], + input[type="week"], + input[type="number"], + input[type="email"], + input[type="url"], + input[type="search"], + input[type="tel"], + input[type="color"], + .item-select, + mm-attachments>.item-border { + width: 100%; + margin: -1px; + border: 1px solid $gray; + padding: 16px 0 16px 16px; + height: 56px; + } + + input[type="datetime"], + input[type="datetime-local"], + input[type="date"] { + -webkit-appearance: none; + } + + mm-attachments .item-media { + width: 100%; + margin: -1px; + border: 1px solid $gray; + height: 56px; + } + + mm-multiple-select .item { + width: 100%; + margin: -1px; + border: 1px solid $gray; + padding: 16px 0 16px 16px; + } + + mm-attachments + .item-stacked-label { + border-top: 0px; + padding: 0; + margin-right: 1px; + + ion-label { + margin: 0; + padding-left: 16px; + } + + input { + border: 0; + margin: 0; + } + } + + mm-attachments .item { + width: 100%; + margin: -1px; + border: 1px solid $gray; + overflow: hidden; + } + + .item-checkbox { + margin-right: 1px; + } + + .item-input.item-select { + margin-bottom: -6px; + + select { + width: 100%; + left: 0; + max-width: none; + } + } + + .item-input.mm-latlong { + width: 100%; + margin: -1px; + padding-top: 0; + padding-bottom: 0; + padding-left: 0; + + input { + border: 0; + } + } + + .mm-item-has-rich-text-editor { + margin-right: 1px; + } +} \ No newline at end of file diff --git a/www/addons/mod/data/services/data.js b/www/addons/mod/data/services/data.js new file mode 100644 index 00000000000..29e819afac1 --- /dev/null +++ b/www/addons/mod/data/services/data.js @@ -0,0 +1,993 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Data service. + * + * @module mm.addons.mod_data + * @ngdoc controller + * @name $mmaModData + */ +.factory('$mmaModData', function($q, $mmSitesManager, mmaModDataComponent, $mmFilepool, $mmSite, mmaModDataPerPage, $mmApp, $mmUtil, + $mmaModDataOffline, $mmaModDataFieldsDelegate) { + var self = {}; + + /** + * Get cache key for database data WS calls. + * + * @param {Number} courseId Course ID. + * @return {String} Cache key. + */ + function getDatabaseDataCacheKey(courseId) { + return 'mmaModData:data:' + courseId; + } + + /** + * Get prefix cache key for all database activity data WS calls. + * + * @param {Number} dataId Data ID. + * @return {String} Cache key. + */ + function getDatabaseDataPrefixCacheKey(dataId) { + return 'mmaModData:' + dataId; + } + + + /** + * Get prefix cache key for all database access information data WS calls. + * + * @param {Number} dataId Data ID. + * @return {String} Cache key. + */ + function getDatabaseAccessInformationDataPrefixCacheKey(dataId) { + return getDatabaseDataPrefixCacheKey(dataId) + ':access:'; + } + + /** + * Get cache key for database access information data WS calls. + * + * @param {Number} dataId Data ID. + * @param {Number} [groupId] Group ID. + * @return {String} Cache key. + */ + function getDatabaseAccessInformationDataCacheKey(dataId, groupId) { + groupId = groupId || 0; + return getDatabaseAccessInformationDataPrefixCacheKey(dataId) + groupId; + } + + /** + * Get prefix cache key for database all entries data WS calls. + * + * @param {Number} dataId Data ID. + * @return {String} Cache key. + */ + function getEntriesPrefixCacheKey(dataId) { + return getDatabaseDataPrefixCacheKey(dataId) + ':entries:'; + } + + /** + * Get cache key for database entries data WS calls. + * + * @param {Number} dataId Data ID. + * @param {Number} [groupId] Group ID. + * @return {String} Cache key. + */ + function getEntriesCacheKey(dataId, groupId) { + groupId = groupId || 0; + return getEntriesPrefixCacheKey(dataId) + groupId; + } + + /** + * Get cache key for database entry data WS calls. + * + * @param {Number} dataId Data ID for caching purposes. + * @param {Number} entryId Entry ID. + * @return {String} Cache key. + */ + function getEntryCacheKey(dataId, entryId) { + return getDatabaseDataPrefixCacheKey(dataId) + ':entry:' + entryId; + } + + /** + * Get cache key for database fields data WS calls. + * + * @param {Number} dataId Data ID. + * @return {String} Cache key. + */ + function getFieldsCacheKey(dataId) { + return getDatabaseDataPrefixCacheKey(dataId) + ':fields'; + } + + /** + * Return whether or not the plugin is enabled in a certain site. Plugin is enabled if the database WS are available. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#isPluginEnabled + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved with true if plugin is enabled, rejected or resolved with false otherwise. + */ + self.isPluginEnabled = function(siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.wsAvailable('mod_data_get_databases_by_courses') && + site.wsAvailable('mod_data_get_data_access_information'); + }); + }; + + /** + * Get a database with key=value. If more than one is found, only the first will be returned. + * + * @param {Number} courseId Course ID. + * @param {String} key Name of the property to check. + * @param {Mixed} value Value to search. + * @param {String} [siteId] Site ID. If not defined, current site. + * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. + * @return {Promise} Promise resolved when the database is retrieved. + */ + function getDatabase(courseId, key, value, siteId, forceCache) { + return $mmSitesManager.getSite(siteId).then(function(site) { + var params = { + courseids: [courseId] + }, + preSets = { + cacheKey: getDatabaseDataCacheKey(courseId) + }; + + if (forceCache) { + preSets.omitExpires = true; + } + + return site.read('mod_data_get_databases_by_courses', params, preSets).then(function(response) { + if (response && response.databases) { + for (var x in response.databases) { + if (response.databases[x][key] == value) { + return response.databases[x]; + } + } + } + return $q.reject(); + }); + }); + } + + /** + * Get a database by course module ID. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#getDatabase + * @param {Number} courseId Course ID. + * @param {Number} cmId Course module ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. + * @return {Promise} Promise resolved when the database is retrieved. + */ + self.getDatabase = function(courseId, cmId, siteId, forceCache) { + return getDatabase(courseId, 'coursemodule', cmId, siteId, forceCache); + }; + + /** + * Get a database by ID. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#getDatabaseById + * @param {Number} courseId Course ID. + * @param {Number} id Data ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. + * @return {Promise} Promise resolved when the database is retrieved. + */ + self.getDatabaseById = function(courseId, id, siteId, forceCache) { + return getDatabase(courseId, 'id', id, siteId, forceCache); + }; + + /** + * Invalidates database data. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#invalidateDatabaseData + * @param {Number} courseId Course ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the database is invalidated. + */ + self.invalidateDatabaseData = function(courseId, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.invalidateWsCacheForKey(getDatabaseDataCacheKey(courseId)); + }); + }; + + /** + * Invalidates database data except files and module info. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#invalidateDatabaseWSData + * @param {Number} databaseId Data ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the data is invalidated. + */ + self.invalidateDatabaseWSData = function(databaseId, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.invalidateWsCacheForKeyStartingWith(getDatabaseDataPrefixCacheKey(databaseId)); + + }); + }; + + /** + * Get access information for a given database. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#getDatabaseAccessInformation + * @param {Number} dataId Data ID. + * @param {Number} [groupId] Group ID. + * @param {Boolean} offline True if it should return cached data. Has priority over ignoreCache. + * @param {Boolean} ignoreCache True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the database is retrieved. + */ + self.getDatabaseAccessInformation = function(dataId, groupId, offline, ignoreCache, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + var params = { + databaseid: dataId + }, + preSets = { + cacheKey: getDatabaseAccessInformationDataCacheKey(dataId, groupId) + }; + + if (typeof groupId !== "undefined") { + params.groupid = groupId; + } + + if (offline) { + preSets.omitExpires = true; + } else if (ignoreCache) { + preSets.getFromCache = 0; + preSets.emergencyCache = 0; + } + + return site.read('mod_data_get_data_access_information', params, preSets); + }); + }; + + /** + * Invalidates database access information data. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#invalidateDatabaseAccessInformationData + * @param {Number} dataId Data ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the data is invalidated. + */ + self.invalidateDatabaseAccessInformationData = function(dataId, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.invalidateWsCacheForKeyStartingWith(getDatabaseAccessInformationDataPrefixCacheKey(dataId)); + }); + }; + + /** + * Get entries for a specific database and group. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#getEntries + * @param {Number} dataId Data ID. + * @param {Number} [groupId] Group ID. + * @param {Number} [sort] Sort the records by this field id, reserved ids are: + * 0: timeadded + * -1: firstname + * -2: lastname + * -3: approved + * -4: timemodified. + * Empty for using the default database setting. + * @param {String} [order] The direction of the sorting: 'ASC' or 'DESC'. + * Empty for using the default database setting. + * @param {Number} [page] Page of records to return. + * @param {Number} [perPage] Records per page to return. Default on mmaModDataPerPage. + * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. + * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the database is retrieved. + */ + self.getEntries = function(dataId, groupId, sort, order, page, perPage, forceCache, ignoreCache, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + // Always use sort and order params to improve cache usage (entries are identified by params). + var params = { + databaseid: dataId, + returncontents: 1, + page: page || 0, + perpage: perPage || mmaModDataPerPage, + groupid: groupId || 0, + sort: sort || "0", + order: order || "DESC" + }, + preSets = { + cacheKey: getEntriesCacheKey(dataId, groupId) + }; + + if (forceCache) { + preSets.omitExpires = true; + } else if (ignoreCache) { + preSets.getFromCache = 0; + preSets.emergencyCache = 0; + } + + return site.read('mod_data_get_entries', params, preSets); + }); + }; + + /** + * Invalidates database entries data. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#invalidateEntriesData + * @param {Number} dataId Data ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the data is invalidated. + */ + self.invalidateEntriesData = function(dataId, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.invalidateWsCacheForKeyStartingWith(getEntriesPrefixCacheKey(dataId)); + }); + }; + + /** + * Get an entry of the database activity. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#getEntry + * @param {Number} dataId Data ID for caching purposes. + * @param {Number} entryId Entry ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the database entry is retrieved. + */ + self.getEntry = function(dataId, entryId, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + var params = { + entryid: entryId, + returncontents: 1 + }, + preSets = { + cacheKey: getEntryCacheKey(dataId, entryId) + }; + + return site.read('mod_data_get_entry', params, preSets); + }); + }; + + /** + * Invalidates database entry data. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#invalidateEntryData + * @param {Number} dataId Data ID for caching purposes. + * @param {Number} entryId Entry ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the data is invalidated. + */ + self.invalidateEntryData = function(dataId, entryId, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.invalidateWsCacheForKey(getEntryCacheKey(dataId, entryId)); + }); + }; + + /** + * Approves or unapproves an entry. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#approveEntry + * @param {Number} dataId Database ID. + * @param {Number} entryId Entry ID. + * @param {Boolean} approve Whether to approve (true) or unapprove the entry. + * @param {Number} courseId Course ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the action is done. + */ + self.approveEntry = function(dataId, entryId, approve, courseId, siteId) { + siteId = siteId || $mmSite.getId(); + + // Get if the opposite action is not synced. + var action = approve ? 'disapprove' : 'approve'; + return $mmaModDataOffline.getEntry(dataId, entryId, action, siteId).then(function() { + // Found. Just delete the action. + return $mmaModDataOffline.deleteEntry(dataId, entryId, action, siteId); + }).catch(function() { + + if (!$mmApp.isOnline()) { + // App is offline, store the action. + return storeOffline(); + } + + return self.approveEntryOnline(entryId, approve, siteId).catch(function(error) { + if (error && !error.wserror) { + // Couldn't connect to server, store in offline. + return storeOffline(); + } else { + // The WebService has thrown an error or offline not supported, reject. + return $q.reject(error.error); + } + }); + }); + + // Convenience function to store a data to be synchronized later. + function storeOffline() { + var action = approve ? 'approve' : 'disapprove'; + return $mmaModDataOffline.saveEntry(dataId, entryId, action, courseId, undefined, false, undefined, siteId); + } + }; + + /** + * Approves or unapproves an entry. It does not cache calls. It will fail if offline or cannot connect. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#approveEntryOnline + * @param {Number} entryId Entry ID. + * @param {Boolean} approve Whether to approve (true) or unapprove the entry. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the action is done. Rejected with object containing the error message + * (if any) and a boolean indicating if the error was returned by WS. + */ + self.approveEntryOnline = function(entryId, approve, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + var params = { + entryid: entryId, + approve: approve ? 1 : 0 + }; + + return site.write('mod_data_approve_entry', params).catch(function(error) { + return $q.reject({ + error: error, + wserror: $mmUtil.isWebServiceError(error) + }); + }); + }); + }; + + + /** + * Deletes an entry. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#deleteEntry + * @param {Number} dataId Database ID. + * @param {Number} entryId Entry ID. + * @param {Number} courseId Course ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the action is done. + */ + self.deleteEntry = function(dataId, entryId, courseId, siteId) { + siteId = siteId || $mmSite.getId(); + var justAdded = false; + + // Check if the opposite action is not synced and just delete it. + return $mmaModDataOffline.getEntryActions(dataId, entryId, siteId).then(function(entries) { + if (entries && entries.length) { + // Found. Delete other actions first. + var proms = []; + angular.forEach(entries, function(entry) { + if (entry.action == 'add') { + justAdded = true; + } + proms.push($mmaModDataOffline.deleteEntry(dataId, entryId, entry.action, siteId)); + }); + + return $q.all(proms); + } + }).then(function() { + if (justAdded) { + // The field was added offline, delete and stop. + return; + } + + if (!$mmApp.isOnline()) { + // App is offline, store the action. + return storeOffline(); + } + + return self.deleteEntryOnline(entryId, siteId).catch(function(error) { + if (error && !error.wserror) { + // Couldn't connect to server, store in offline. + return storeOffline(); + } else { + // The WebService has thrown an error or offline not supported, reject. + return $q.reject(error.error); + } + }); + }); + + // Convenience function to store a data to be synchronized later. + function storeOffline() { + return $mmaModDataOffline.saveEntry(dataId, entryId, 'delete', courseId, undefined, false, undefined, siteId); + } + }; + + /** + * Deletes an entry. It does not cache calls. It will fail if offline or cannot connect. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#deleteEntryOnline + * @param {Number} entryId Entry ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the action is done. Rejected with object containing + * the error message (if any) and a boolean indicating if the error was returned by WS. + */ + self.deleteEntryOnline = function(entryId, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + var params = { + entryid: entryId + }; + + return site.write('mod_data_delete_entry', params).catch(function(error) { + return $q.reject({ + error: error, + wserror: $mmUtil.isWebServiceError(error) + }); + }); + }); + }; + + /** + * Adds a new entry to a database. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#addEntry + * @param {Number} dataId Data instance ID. + * @param {Number} entryId EntryId or provisional entry ID when offline. + * @param {Number} courseId Course ID. + * @param {Object} contents The fields data to be created. + * @param {Number} [groupId] Group id, 0 means that the function will determine the user group. + * @param {Object} fields The fields that define the contents. + * @param {String} [siteId] Site ID. If not defined, current site. + * @param {Boolean} forceOffline Force editing entry in offline. + * @return {Promise} Promise resolved when the action is done. + */ + self.addEntry = function(dataId, entryId, courseId, contents, groupId, fields, siteId, forceOffline) { + siteId = siteId || $mmSite.getId(); + + if (!$mmApp.isOnline() || forceOffline) { + var notifications = checkFields(fields, contents); + if (notifications) { + return { + fieldnotifications: notifications + }; + } + } + + return self.addEntryOnline(dataId, contents, groupId, siteId).catch(function(error) { + if (error && !error.wserror) { + // Couldn't connect to server, store in offline. + return storeOffline(); + } else { + // The WebService has thrown an error or offline not supported, reject. + return $q.reject(error.error); + } + }); + + // Convenience function to store a data to be synchronized later. + function storeOffline() { + return $mmaModDataOffline.saveEntry(dataId, entryId, 'add', courseId, groupId, contents, undefined, siteId) + .then(function(entry) { + return { + // Return provissional entry Id. + newentryid: entry[1] + }; + }); + } + }; + + /** + * Adds a new entry to a database. It does not cache calls. It will fail if offline or cannot connect. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#addEntryOnline + * @param {Number} dataId Database ID. + * @param {Object} data The fields data to be created. + * @param {Number} [groupId] Group id, 0 means that the function will determine the user group. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the action is done. + */ + self.addEntryOnline = function(dataId, data, groupId, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + var params = { + databaseid: dataId, + data: data + }; + + if (typeof groupId !== "undefined") { + params.groupid = groupId; + } + + return site.write('mod_data_add_entry', params).catch(function(error) { + return $q.reject({ + error: error, + wserror: $mmUtil.isWebServiceError(error) + }); + }); + }); + }; + + /** + * Updates an existing entry. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#editEntry + * @param {Number} dataId Database ID. + * @param {Number} entryId Entry ID. + * @param {Number} courseId Course ID. + * @param {Object} contents The contents data to be updated. + * @param {Object} fields The fields that define the contents. + * @param {String} [siteId] Site ID. If not defined, current site. + * @param {Boolean} forceOffline Force editing entry in offline. + * @return {Promise} Promise resolved when the action is done. + */ + self.editEntry = function(dataId, entryId, courseId, contents, fields, siteId, forceOffline) { + siteId = siteId || $mmSite.getId(); + var justAdded = false, + groupId; + + if (!$mmApp.isOnline() || forceOffline) { + var notifications = checkFields(fields, contents); + if (notifications) { + return { + fieldnotifications: notifications + }; + } + } + + // Get other not not synced actions. + return $mmaModDataOffline.getEntryActions(dataId, entryId, siteId).then(function(entries) { + if (entries && entries.length) { + // Found. Delete add and edit actions first. + var proms = []; + angular.forEach(entries, function(entry) { + if (entry.action == 'add') { + justAdded = true; + groupId = entry.groupid; + proms.push($mmaModDataOffline.deleteEntry(dataId, entryId, entry.action, siteId)); + } else if (entry.action == 'edit') { + proms.push($mmaModDataOffline.deleteEntry(dataId, entryId, entry.action, siteId)); + } + }); + + return $q.all(proms); + } + }).then(function() { + if (justAdded) { + // The field was added offline, add again and stop. + return self.addEntry(dataId, entryId, courseId, contents, groupId, fields, siteId, forceOffline) + .then(function(result) { + result.updated = true; + return result; + }); + } + + if (!$mmApp.isOnline() || forceOffline) { + // App is offline, store the action. + return storeOffline(); + } + + return self.editEntryOnline(entryId, contents, siteId).catch(function(error) { + if (error && !error.wserror) { + // Couldn't connect to server, store in offline. + return storeOffline(); + } else { + // The WebService has thrown an error or offline not supported, reject. + return $q.reject(error.error); + } + }); + }); + + // Convenience function to store a data to be synchronized later. + function storeOffline() { + return $mmaModDataOffline.saveEntry(dataId, entryId, 'edit', courseId, undefined, contents, undefined, siteId) + .then(function() { + return { + updated: true + }; + }); + } + }; + + /** + * Convenience function to check fields requeriments here named "notifications" + * + * @param {Object} fields The fields that define the contents. + * @param {Object} contents The contents data of the fields. + * @return {Array} Array of notifications if any or false. + */ + function checkFields(fields, contents) { + var notifications = [], + notification, + contentsIndexed = {}; + + angular.forEach(contents, function(content) { + if (typeof contentsIndexed[content.fieldid] == "undefined") { + contentsIndexed[content.fieldid] = []; + } + contentsIndexed[content.fieldid].push(content); + }); + + // App is offline, check required fields. + angular.forEach(fields, function(field) { + notification = $mmaModDataFieldsDelegate.getFieldsNotifications(field, contentsIndexed[field.id]); + if (notification) { + notifications.push({ + fieldname: field.name, + notification: notification + }); + } + }); + + return notifications.length ? notifications : false; + } + + /** + * Updates an existing entry. It does not cache calls. It will fail if offline or cannot connect. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#editEntryOnline + * @param {Number} entryId Entry ID. + * @param {Object} data The fields data to be updated. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the action is done. + */ + self.editEntryOnline = function(entryId, data, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + var params = { + entryid: entryId, + data: data + }; + + return site.write('mod_data_update_entry', params).catch(function(error) { + return $q.reject({ + error: error, + wserror: $mmUtil.isWebServiceError(error) + }); + }); + }); + }; + + + /** + * Performs search over a database. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#searchEntries + * @param {Number} databaseId The data instance id. + * @param {Number} [groupId] Group id, 0 means that the function will determine the user group. + * @param {String} [search] Search text. It will be used if advSearch is not defined. + * @param {Array} [advSearch] Advanced search data. + * @param {String} [sort] Sort by this field. + * @param {Number} [order] The direction of the sorting. + * @param {Number} [page] Page of records to return. + * @param {Number} [perPage] Records per page to return. Default on mmaModDataPerPage. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the action is done. + */ + self.searchEntries = function(databaseId, groupId, search, advSearch, sort, order, page, perPage, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + var params = { + databaseid: databaseId, + groupid: groupId || 0, + returncontents: 1, + page: page || 0, + perpage: perPage || mmaModDataPerPage + }, + preSets = { + getFromCache: 0, + saveToCache: 1, + emergencyCache: 1 + }; + + if (typeof sort != "undefined") { + params.sort = sort; + } + + if (typeof order !== "undefined") { + params.order = order; + } + + if (typeof search !== "undefined") { + params.search = search; + } + + if (typeof advSearch !== "undefined") { + params.advsearch = advSearch; + } + + return site.read('mod_data_search_entries', params, preSets); + }); + }; + + /** + * Get the list of configured fields for the given database. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#getFields + * @param {Number} dataId Data ID. + * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. + * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the fields are retrieved. + */ + self.getFields = function(dataId, forceCache, ignoreCache, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + var params = { + databaseid: dataId + }, + preSets = { + cacheKey: getFieldsCacheKey(dataId) + }; + + if (forceCache) { + preSets.omitExpires = true; + } else if (ignoreCache) { + preSets.getFromCache = 0; + preSets.emergencyCache = 0; + } + + return site.read('mod_data_get_fields', params, preSets).then(function(response) { + if (response && response.fields) { + return response.fields; + } + return $q.reject(); + }); + }); + }; + + /** + * Invalidates database fields data. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#invalidateFieldsData + * @param {Number} dataId Data ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the data is invalidated. + */ + self.invalidateFieldsData = function(dataId, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.invalidateWsCacheForKey(getFieldsCacheKey(dataId)); + }); + }; + + /** + * Performs the whole fetch of the entries in the database. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataPrefetchHandler#fetchAllEntries + * @param {Number} dataId Data ID. + * @param {Number} [groupId] Group ID. + * @param {Number} [sort] Sort the records by this field id. See $mmaModData#getEntries for more information. + * @param {String} [order] The direction of the sorting. See $mmaModData#getEntries for more information. + * @param {Number} [perPage] Records per page to fetch. It has to match with the prefetch. + * Default on mmaModDataPerPage. + * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. + * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when done. + */ + self.fetchAllEntries = function(dataId, groupId, sort, order, perPage, forceCache, ignoreCache, siteId) { + siteId = siteId || $mmSite.getId(); + perPage = perPage || mmaModDataPerPage; + return fetchEntriesRecursive(dataId, groupId, sort, order, perPage, forceCache, ignoreCache, [], 0, siteId); + }; + + /** + * Recursive call on fetch all entries. + * + * @param {Number} dataId Data ID. + * @param {Number} groupId Group ID. + * @param {Number} sort Sort the records by this field id. See $mmaModData#getEntries for more information. + * @param {String} order The direction of the sorting. See $mmaModData#getEntries for more information. + * @param {Number} perPage Records per page to fetch. It has to match with the prefetch. + * @param {Boolean} forceCache True to always get the value from cache, false otherwise. Default false. + * @param {Boolean} ignoreCache True if it should ignore cached data (it will always fail in offline or server down). + * @param {Array} entries Entries already fetch (just to concatenate them). + * @param {Number} page Page of records to return. + * @param {String} siteId Site ID. + * @return {Promise} Promise resolved when done. + */ + function fetchEntriesRecursive(dataId, groupId, sort, order, perPage, forceCache, ignoreCache, entries, page, siteId) { + return self.getEntries(dataId, groupId, sort, order, page, perPage, forceCache, ignoreCache, siteId) + .then(function(result) { + entries = entries.concat(result.entries); + + var canLoadMore = ((page + 1) * perPage) < result.totalcount; + if (canLoadMore) { + return fetchEntriesRecursive(dataId, groupId, sort, order, perPage, forceCache, ignoreCache, entries, page + 1, + siteId); + } + return entries; + }); + } + + /** + * Invalidate the prefetched content except files. + * To invalidate files, use $mmaModData#invalidateFiles. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#invalidateContent + * @param {Number} moduleId The module ID. + * @param {Number} courseId Course ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} + */ + self.invalidateContent = function(moduleId, courseId, siteId) { + siteId = siteId || $mmSite.getId(); + return self.getDatabase(courseId, moduleId, siteId, true).then(function(data) { + var ps = []; + // Do not invalidate database data before getting database info, we need it! + ps.push(self.invalidateDatabaseData(courseId, siteId)); + ps.push(self.invalidateDatabaseWSData(data.id, siteId)); + + return $q.all(ps); + }); + }; + + /** + * Invalidate the prefetched files. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#invalidateFiles + * @param {Number} moduleId The module ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the files are invalidated. + */ + self.invalidateFiles = function(moduleId, siteId) { + return $mmFilepool.invalidateFilesByComponent(siteId, mmaModDataComponent, moduleId); + }; + + /** + * Report the database as being viewed. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#logView + * @param {String} id Data ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the WS call is successful. + */ + self.logView = function(id, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + var params = { + databaseid: id + }; + return site.write('mod_data_view_database', params); + }); + }; + + return self; +}); diff --git a/www/addons/mod/data/services/data_offline.js b/www/addons/mod/data/services/data_offline.js new file mode 100644 index 00000000000..916a46ae8cc --- /dev/null +++ b/www/addons/mod/data/services/data_offline.js @@ -0,0 +1,261 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +.constant('mmaModDataEntriesStore', 'mma_mod_data_entry') + +.config(function($mmSitesFactoryProvider, mmaModDataEntriesStore) { + var stores = [ + { + name: mmaModDataEntriesStore, + keyPath: ['dataid', 'entryid', 'action'], + indexes: [ + { + name: 'dataid' + }, + { + name: 'courseid' + }, + { + name: 'groupid' + }, + { + name: 'action' + }, + { + name: 'entryid' + }, + { + name: 'timemodified' + }, + { + name: 'dataAndEntry', + keyPath: ['dataid', 'entryid'] + } + ] + } + ]; + $mmSitesFactoryProvider.registerStores(stores); +}) + +/** + * Offline data factory. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataOffline + */ +.factory('$mmaModDataOffline', function($mmSitesManager, $log, $mmFS, mmaModDataEntriesStore) { + $log = $log.getInstance('$mmaModDataOffline'); + + var self = {}; + + /** + * Delete all the actions of an entry. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataOffline#deleteAllEntryActions + * @param {Number} dataId Database ID. + * @param {Number} entryId Database entry ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved if deleted, rejected if failure. + */ + self.deleteAllEntryActions = function(dataId, entryId, siteId) { + return self.getEntryActions(dataId, entryId, siteId).then(function(actions) { + var promises = []; + angular.forEach(actions, function(action) { + promises.push(self.deleteEntry(dataId, entryId, action.action, siteId)); + }); + return $q.all(promises); + }); + }; + + /** + * Delete an stored entry. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataOffline#deleteEntry + * @param {Number} dataId Database ID. + * @param {String} entryId Database entry Id. + * @param {String} action Action to be done + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved if deleted, rejected if failure. + */ + self.deleteEntry = function(dataId, entryId, action, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.getDb().remove(mmaModDataEntriesStore, [dataId, entryId, action]); + }); + }; + + /** + * Get all the stored entry data from all the databases. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataOffline#getAllEntries + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved with entries. + */ + self.getAllEntries = function(siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.getDb().getAll(mmaModDataEntriesStore); + }); + }; + + /** + * Get an stored entry data. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataOffline#getEntry + * @param {Number} dataId Database ID. + * @param {String} entryId Database entry Id. + * @param {String} action Action to be done + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved with entry. + */ + self.getEntry = function(dataId, entryId, action, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.getDb().get(mmaModDataEntriesStore, [dataId, entryId, action]); + }); + }; + + /** + * Get an all stored entry actions data. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataOffline#getEntryActions + * @param {Number} dataId Database ID. + * @param {String} entryId Database entry Id. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved with entry actions. + */ + self.getEntryActions = function(dataId, entryId, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.getDb().whereEqual(mmaModDataEntriesStore, 'dataAndEntry', [dataId, entryId]); + }); + }; + + /** + * Get all the stored entry data from a certain database. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataOffline#getDatabaseEntries + * @param {Number} dataId Database ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved with entries. + */ + self.getDatabaseEntries = function(dataId, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.getDb().whereEqual(mmaModDataEntriesStore, 'dataid', dataId); + }); + }; + + /** + * Check if there are offline entries to send. + * + * @module mm.addons.method + * @ngdoc method + * @name $mmaModDataOffline#hasOfflineData + * @param {Number} dataId Database ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved with boolean: true if has offline answers, false otherwise. + */ + self.hasOfflineData = function(dataId, siteId) { + return self.getDatabaseEntries(dataId, siteId).then(function(entries) { + return !!entries.length; + }).catch(function() { + // No offline data found, return false. + return false; + }); + }; + + /** + * Save an entry data to be sent later. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataOffline#saveEntry + * @param {Number} dataId Database ID. + * @param {String} entryId Database entry Id. If action is add entryId should be 0 and -timemodified will be used. + * @param {String} action Action to be done to the entry: [add, edit, delete, approve, disapprove] + * @param {Number} courseId Course ID of the database. + * @param {Number} [groupId] Group ID. ONly provided when adding. + * @param {Array} [fields] Array of field data of the entry if needed. + * @param {Number} [timemodified] The time the entry was modified. If not defined, current time. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved if stored, rejected if failure. + */ + self.saveEntry = function(dataId, entryId, action, courseId, groupId, fields, timemodified, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + timemodified = timemodified || new Date().getTime(); + entryId = typeof entryId == "undefined" || entryId === false ? -timemodified : entryId; + var entry = { + dataid: dataId, + courseid: courseId, + groupid: groupId, + action: action, + entryid: entryId, + fields: fields, + timemodified: timemodified + }; + return site.getDb().insert(mmaModDataEntriesStore, entry); + }); + }; + + /** + * Get the path to the folder where to store files for offline files in a database. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataOffline#getDatabaseFolder + * @param {Number} dataId Database ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved with the path. + */ + self.getDatabaseFolder = function(dataId, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + + var siteFolderPath = $mmFS.getSiteFolder(site.getId()), + folderPath = 'offlinedatabase/' + dataId; + + return $mmFS.concatenatePaths(siteFolderPath, folderPath); + }); + }; + + /** + * Get the path to the folder where to store files for a new offline entry. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataOffline#getEntryFieldFolder + * @param {Number} dataId Database ID. + * @param {Number} entryId The ID of the entry. + * @param {Number} fieldId Field ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved with the path. + */ + self.getEntryFieldFolder = function(dataId, entryId, fieldId ,siteId) { + return self.getDatabaseFolder(dataId, siteId).then(function(folderPath) { + return $mmFS.concatenatePaths(folderPath, entryId + '_' + fieldId); + }); + }; + + return self; +}); \ No newline at end of file diff --git a/www/addons/mod/data/services/data_sync.js b/www/addons/mod/data/services/data_sync.js new file mode 100644 index 00000000000..5618175fa6c --- /dev/null +++ b/www/addons/mod/data/services/data_sync.js @@ -0,0 +1,348 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Data synchronization service. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataSync + */ +.factory('$mmaModDataSync', function($log, $mmaModData, $mmSite, $mmSitesManager, $q, $mmaModDataOffline, $mmCourse, $mmUtil, + $mmApp, $mmEvents, $translate, mmaModDataSyncTime, $mmSync, mmaModDataEventAutomSynced, mmaModDataComponent, + $mmSyncBlock, $mmLang, $mmaModDataHelper) { + + $log = $log.getInstance('$mmaModDataSync'); + + // Inherit self from $mmSync. + var self = $mmSync.createChild(mmaModDataComponent, mmaModDataSyncTime); + + /** + * Check if a database has data to synchronize. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataSync#hasDataToSync + * @param {Number} dataId Database ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved with boolean: true if has data to sync, false otherwise. + */ + self.hasDataToSync = function(dataId, siteId) { + return $mmaModDataOffline.hasOfflineData(dataId, siteId); + }; + + /** + * Try to synchronize all data that need it and haven't been synchronized in a while. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataSync#syncAllDatabases + * @param {String} [siteId] Site ID to sync. If not defined, sync all sites. + * @return {Promise} Promise resolved when the sync is done. + */ + self.syncAllDatabases = function(siteId) { + if (!$mmApp.isOnline()) { + $log.debug('Cannot sync all databases because device is offline.'); + return $q.reject(); + } + + var promise; + if (!siteId) { + // No site ID defined, sync all sites. + $log.debug('Try to sync database in all sites.'); + promise = $mmSitesManager.getSitesIds(); + } else { + $log.debug('Try to sync database in site ' + siteId); + promise = $q.when([siteId]); + } + + return promise.then(function(siteIds) { + var sitePromises = []; + + angular.forEach(siteIds, function(siteId) { + // Sync submissions. + sitePromises.push($mmaModDataOffline.getAllEntries(siteId).then(function(offlineActions) { + var promises = {}; + + // Do not sync same database twice. + angular.forEach(offlineActions, function(action) { + if (typeof promises[action.dataid] != 'undefined') { + return; + } + + promises[action.dataid] = self.syncDatabaseIfNeeded(action.dataid, siteId) + .then(function(result) { + if (result && result.updated) { + // Sync done. Send event. + $mmEvents.trigger(mmaModDataEventAutomSynced, { + siteid: siteId, + dataid: action.dataid, + warnings: result.warnings + }); + } + }); + }); + // Promises will be an object so, convert to an array first; + promises = $mmUtil.objectToArray(promises); + + return $q.all(promises); + })); + }); + + return $q.all(sitePromises); + }); + }; + + /** + * Sync a database only if a certain time has passed since the last time. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataSync#syncDatabaseIfNeeded + * @param {Number} dataId Database ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the data is synced or if it doesn't need to be synced. + */ + self.syncDatabaseIfNeeded = function(dataId, siteId) { + return self.isSyncNeeded(dataId, siteId).then(function(needed) { + if (needed) { + return self.syncDatabase(dataId, siteId); + } + }); + }; + + /** + * Try to synchronize a database. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataSync#syncDatabase + * @param {Number} dataId Data ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved if sync is successful, rejected otherwise. + */ + self.syncDatabase = function(dataId, siteId) { + siteId = siteId || $mmSite.getId(); + + var syncPromise, + data, + courseId, + result = { + warnings: [], + updated: false + }; + + if (self.isSyncing(dataId, siteId)) { + // There's already a sync ongoing for this discussion, return the promise. + return self.getOngoingSync(dataId, siteId); + } + + // Verify that data isn't blocked. + if ($mmSyncBlock.isBlocked(mmaModDataComponent, dataId, siteId)) { + $log.debug('Cannot sync database ' + dataId + ' because it is blocked.'); + var modulename = $mmCourse.translateModuleName('data'); + return $mmLang.translateAndReject('mm.core.errorsyncblocked', {$a: modulename}); + } + + $log.debug('Try to sync database ' + dataId); + + // Get offline actions to be sent. + syncPromise = $mmaModDataOffline.getDatabaseEntries(dataId, siteId).catch(function() { + // No offline data found, return empty array. + return []; + }).then(function(offlineActions) { + if (!offlineActions.length) { + // Nothing to sync. + return; + } else if (!$mmApp.isOnline()) { + // Cannot sync in offline. + return $q.reject(); + } + + courseId = offlineActions[0].courseid; + + return $mmaModData.getDatabaseById(courseId, dataId, siteId).then(function(database) { + data = database; + + var promises = [], + offlineEntries = {}; + + angular.forEach(offlineActions, function(entry) { + if (typeof offlineEntries[entry.entryid] == "undefined") { + offlineEntries[entry.entryid] = []; + } + offlineEntries[entry.entryid].push(entry); + }); + + angular.forEach(offlineEntries, function(entryActions) { + promises.push(syncEntry(data, entryActions, result, siteId)); + }); + + return $q.all(promises); + }).then(function() { + if (result.updated) { + // Data has been sent to server. Now invalidate the WS calls. + return $mmaModData.invalidateContent(data.cmid, courseId, siteId).catch(function() { + // Ignore errors. + }); + } + }); + }).then(function() { + // Sync finished, set sync time. + return self.setSyncTime(dataId, siteId).catch(function() { + // Ignore errors. + }); + }).then(function() { + // All done, return the warnings. + return result; + }); + + return self.addOngoingSync(dataId, syncPromise, siteId); + }; + + /** + * Synchronize an entry. + * + * @param {Object} data Database. + * @param {Object} entryActions Entry actions. + * @param {Object} result Object with the result of the sync. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved if success, rejected otherwise. + */ + function syncEntry(data, entryActions, result, siteId) { + var discardError, + timePromise, + entryId = 0, + offlineId, + deleted = false, + promises = []; + + // Sort entries by timemodified. + entryActions = entryActions.sort(function(a, b) { + return a.timemodified - b.timemodified; + }); + + entryId = entryActions[0].entryid; + + if (entryId > 0) { + timePromise = $mmaModData.getEntry(data.id, entryId, siteId).then(function(entry) { + return entry.entry.timemodified; + }).catch(function() { + return -1; + }); + } else { + offlineId = entryId; + timePromise = $q.when(0); + } + + return timePromise.then(function(timemodified) { + if (timemodified < 0 || timemodified >= entryActions[0].timemodified) { + // The entry was not found in Moodle or the entry has been modified, discard the action. + result.updated = true; + discardError = $translate.instant('mma.mod_data.warningsubmissionmodified'); + return $mmaModDataOffline.deleteAllEntryActions(data.id, entryId, siteId); + } + + angular.forEach(entryActions, function(action) { + var actionPromise, + proms = []; + + entryId = action.entryid > 0 ? action.entryid : entryId; + + if (action.fields) { + angular.forEach(action.fields, function(field) { + // Upload Files if asked. + var value = JSON.parse(field.value); + if (value.online || value.offline) { + var files = value.online || [], + fileProm = value.offline ? $mmaModDataHelper.getStoredFiles(action.dataid, entryId, field.fieldid) : + $q.when([]); + + proms.push(fileProm.then(function(offlineFiles) { + files = files.concat(offlineFiles); + return $mmaModDataHelper.uploadOrStoreFiles(action.dataid, 0, entryId, field.fieldid, files, false, + siteId).then(function(filesResult) { + field.value = JSON.stringify(filesResult); + }); + })); + } + }); + } + + actionPromise = $q.all(proms).then(function() { + // Perform the action. + switch (action.action) { + case 'add': + return $mmaModData.addEntryOnline(action.dataid, action.fields, data.groupid, siteId) + .then(function(result) { + entryId = result.newentryid; + }); + case 'edit': + return $mmaModData.editEntryOnline(entryId, action.fields, siteId); + case 'approve': + return $mmaModData.approveEntryOnline(entryId, true, siteId); + case 'disapprove': + return $mmaModData.approveEntryOnline(entryId, false, siteId); + case 'delete': + return $mmaModData.deleteEntryOnline(entryId, siteId).then(function() { + deleted = true; + }); + } + }); + + promises.push(actionPromise.catch(function(error) { + if (error && error.wserror) { + // The WebService has thrown an error, this means it cannot be performed. Discard. + discardError = error.error; + } else { + // Couldn't connect to server, reject. + return $q.reject(error && error.error); + } + }).then(function() { + // Delete the offline data. + result.updated = true; + return $mmaModDataOffline.deleteEntry(action.dataid, action.entryid, action.action, siteId); + })); + }); + return $q.all(promises); + }).then(function() { + if (discardError) { + // Submission was discarded, add a warning. + var message = $translate.instant('mm.core.warningofflinedatadeleted', { + component: $mmCourse.translateModuleName('data'), + name: data.name, + error: discardError + }); + + if (result.warnings.indexOf(message) == -1) { + result.warnings.push(message); + } + } + + // Sync done. Send event. + $mmEvents.trigger(mmaModDataEventAutomSynced, { + siteid: siteId, + dataid: data.id, + entryid: entryId, + offlineentryid: offlineId, + warnings: result.warnings, + deleted: deleted + }); + }); + } + + return self; +}); diff --git a/www/addons/mod/data/services/fieldsdelegate.js b/www/addons/mod/data/services/fieldsdelegate.js new file mode 100644 index 00000000000..5e3f3c0cd0a --- /dev/null +++ b/www/addons/mod/data/services/fieldsdelegate.js @@ -0,0 +1,363 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Delegate to register database fields handlers. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataFieldsDelegate + * @description + * + * Delegate to register database fields handlers. + * You can use this service to register your own fields handlers to be used in a database. + * + * To register a handler: + * + * $mmaModDataFieldsDelegate.registerHandler('mmaYourAddon', 'pluginType', 'handlerName'); + * + * Please take into account that this delegate belongs to an addon so it might not be available in custom apps. + * We recommend using $mmAddonManager to inject this delegate to avoid errors. + * + * Example: + * + * .run(function($mmAddonManager) { + * var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate'); + * if ($mmaModDataFieldsDelegate) { + * $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldText', 'text', '$mmaModDataFieldTextHandler'); + * } + * }); + * + * @see $mmaModDataFieldsDelegate#registerHandler to see the methods your handle needs to implement. + */ +.factory('$mmaModDataFieldsDelegate', function($log, $mmSite, $mmUtil, $q) { + $log = $log.getInstance('$mmaModDataFieldsDelegate'); + + var handlers = {}, + enabledHandlers = {}, + self = {}, + lastUpdateHandlersStart; + + /** + * Get the handler for a certain field plugin. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataFieldsDelegate#getPluginHandler + * @param {String} pluginType Type of the plugin. + * @return {Object} Handler. Undefined if no handler found for the plugin. + */ + self.getPluginHandler = function(pluginType) { + if (typeof enabledHandlers[pluginType] != 'undefined') { + return enabledHandlers[pluginType]; + } + }; + + /** + * Get database data in the input data to search. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataFieldsDelegate#getFieldSearchData + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @return {Array} Name and data field. + */ + self.getFieldSearchData = function(field, inputData) { + var handler = self.getPluginHandler(field.type); + if (handler && handler.getFieldSearchData) { + return handler.getFieldSearchData(field, inputData); + } + return false; + }; + + /** + * Get database data in the input data to add or update entry. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataFieldsDelegate#getFieldEditData + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @param {Object} originalFieldData Original field entered data. + * @return {Array} Name and data field. + */ + self.getFieldEditData = function(field, inputData, originalFieldData) { + var handler = self.getPluginHandler(field.type); + if (handler && handler.getFieldEditData) { + return handler.getFieldEditData(field, inputData, originalFieldData); + } + return false; + }; + + /** + * Get database data in the input files to add or update entry. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataFieldsDelegate#getFieldEditFiles + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @param {Object} originalFieldData Original field entered data. + * @return {Array} Name and data field. + */ + self.getFieldEditFiles = function(field, inputData, originalFieldData) { + var handler = self.getPluginHandler(field.type); + if (handler && handler.getFieldEditFiles) { + return handler.getFieldEditFiles(field, inputData, originalFieldData); + } + return []; + }; + + /** + * Check if field type manage files or not. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataFieldsDelegate#hasFiles + * @param {Object} field Defines the field to be checked. + * @return {Boolean} If the field type manages files. + */ + self.hasFiles = function(field) { + var handler = self.getPluginHandler(field.type); + return handler && handler.getFieldEditFiles; + }; + + /** + * Check if the data has changed for a certain field. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataFieldsDelegate#hasFieldDataChanged + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the search form. + * @param {Object} originalFieldData Original field entered data. + * @return {Promise} Promise rejected if has changed, resolved if no changes. + */ + self.hasFieldDataChanged = function(field, inputData, originalFieldData) { + var handler = self.getPluginHandler(field.type); + if (handler && handler.hasFieldDataChanged) { + return $q.when(handler.hasFieldDataChanged(field, inputData, originalFieldData)).then(function(result) { + return result ? $q.reject() : $q.when(); + }); + } + return $q.when(); + }; + + /** + * Check and get field requeriments. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataFieldsDelegate#getFieldsNotification + * @param {Object} field Defines the field to be rendered. + * @param {Object} inputData Data entered in the edit form. + * @return {String} String with the notification or false. + */ + self.getFieldsNotifications = function(field, inputData) { + var handler = self.getPluginHandler(field.type); + if (handler && handler.getFieldsNotifications) { + return handler.getFieldsNotifications(field, inputData); + } + return false; + }; + + /** + * Override field content data with offline submission. + * + * @param {Object} field Defines the field to be rendered. + * @param {Object} originalContent Original data to be overriden. + * @param {Array} offlineContent Array with all the offline data to override. + * @param {Array} offlineFiles Array with all the offline files in the field. + * @return {Object} Data overriden + */ + self.overrideData = function(field, originalContent, offlineContent, offlineFiles) { + var handler = self.getPluginHandler(field.type); + if (handler && handler.overrideData && offlineContent) { + return handler.overrideData(originalContent || {}, offlineContent, offlineFiles); + } + return originalContent; + }; + + /** + * Get the directive to use for a certain database plugin. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataFieldsDelegate#getDirectiveForPlugin + * @param {Object} field Defines the field to be rendered. + * @return {String} Directive name. Undefined if no directive found. + */ + self.getDirectiveForPlugin = function(field) { + var handler = self.getPluginHandler(field.type); + if (handler) { + if (handler.getDirectiveName) { + return handler.getDirectiveName(field); + } + + // Fallback. + return 'mma-mod-data-field-' + field.type; + } + }; + + /** + * Check if a field plugin is supported. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataFieldsDelegate#isPluginSupported + * @param {String} pluginType Type of the plugin. + * @return {Boolean} True if supported, false otherwise. + */ + self.isPluginSupported = function(pluginType) { + return typeof enabledHandlers[pluginType] != 'undefined'; + }; + + + /** + * Register a field plugin handler. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataFieldsDelegate#registerHandler + * @param {String} addon Handler's name. + * @param {String} pluginType Type of the plugin the handler supports. + * @param {String|Object|Function} handler Must be resolved to an object defining the following properties. Or to a function + * returning an object defining these properties. See {@link $mmUtil#resolveObject}. + * - getFieldSearchData(field, inputData) Optional. + * Should return name and data entered to the field. + * - getFieldEditData(field, inputData, originalFieldData) Optional. + * Should return fieldid and data entered to the field in a promise + * or array. + * - hasFieldDataChanged(field, inputData, originalFieldData) Optional. + * Should return if field has been changed by the user. + * - getFieldEditFiles(field, inputData, originalFieldData) Optional. + * Should return an array of files stored in temp store. + * - getFieldsNotifications(field, inputData) Optional. + * Should return an array of notifications before sending data. + * - overrideData(originalContent, offlineContent, offlineFiles) Optional. + * Should return an object with the overriden content from offline + * submission. + */ + self.registerHandler = function(addon, pluginType, handler) { + if (typeof handlers[pluginType] !== 'undefined') { + $log.debug("Addon '" + addon + "' already registered as handler for '" + pluginType + "'"); + return false; + } + $log.debug("Registered handler '" + addon + "' for field plugin '" + pluginType + "'"); + handlers[pluginType] = { + addon: addon, + instance: undefined, + handler: handler + }; + + // Handlers are registered in the "run" phase, it can happen that a handler is registered after updateHandlers + // has been executed. If the user is logged in we'll run updateHandler to be sure it has been executed for this site. + if ($mmSite.isLoggedIn()) { + self.updateHandler(pluginType, handlers[pluginType]); + } + }; + + /** + * Check if a time belongs to the last update handlers call. + * This is to handle the cases where updateHandlers don't finish in the same order as they're called. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataFieldsDelegate#isLastUpdateCall + * @param {Number} time Time to check. + * @return {Boolean} True if equal, false otherwise. + */ + self.isLastUpdateCall = function(time) { + if (!lastUpdateHandlersStart) { + return true; + } + return time == lastUpdateHandlersStart; + }; + + + /** + * Check if a handler is enabled for a certain site and add/remove it to enabledHandlers. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataFieldsDelegate#updateHandler + * @param {String} pluginType The type of the plugin this handler handles. + * @param {Object} handlerInfo The handler details. + * @param {Number} time Time this update process started. + * @return {Promise} Resolved when done. + * @protected + */ + self.updateHandler = function(pluginType, handlerInfo, time) { + var siteId = $mmSite.getId(); + + + if (typeof handlerInfo.instance === 'undefined') { + handlerInfo.instance = $mmUtil.resolveObject(handlerInfo.handler, true); + } + + // Checks if site is enabled. + var enabled = $mmSite.isLoggedIn(); + + // Verify that this call is the last one that was started. + // Check that site hasn't changed since the check started. + if (self.isLastUpdateCall(time) && $mmSite.isLoggedIn() && $mmSite.getId() === siteId) { + if (enabled) { + enabledHandlers[pluginType] = handlerInfo.instance; + } else { + delete enabledHandlers[pluginType]; + } + } + }; + + /** + * Update the enabled handlers for the current site. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataFieldsDelegate#updateHandlers + * @return {Promise} Resolved when done. + * @protected + */ + self.updateHandlers = function() { + var promises = [], + now = new Date().getTime(); + + $log.debug('Updating handlers for current site.'); + + lastUpdateHandlersStart = now; + + // Loop over all the handlers. + angular.forEach(handlers, function(handlerInfo, pluginType) { + promises.push(self.updateHandler(pluginType, handlerInfo, now)); + }); + + return $q.all(promises).then(function() { + return true; + }, function() { + // Never reject. + return true; + }); + }; + + return self; +}) + +.run(function($mmEvents, mmCoreEventLogin, mmCoreEventSiteUpdated, $mmaModDataFieldsDelegate, mmCoreEventRemoteAddonsLoaded) { + $mmEvents.on(mmCoreEventLogin, $mmaModDataFieldsDelegate.updateHandlers); + $mmEvents.on(mmCoreEventSiteUpdated, $mmaModDataFieldsDelegate.updateHandlers); + $mmEvents.on(mmCoreEventRemoteAddonsLoaded, $mmaModDataFieldsDelegate.updateHandlers); +}); diff --git a/www/addons/mod/data/services/handlers.js b/www/addons/mod/data/services/handlers.js new file mode 100644 index 00000000000..28a535209c7 --- /dev/null +++ b/www/addons/mod/data/services/handlers.js @@ -0,0 +1,453 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Mod data handlers. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataHandlers + */ +.factory('$mmaModDataHandlers', function($mmCourse, $mmaModData, $state, $mmContentLinksHelper, $mmUtil, $mmEvents, $mmSite, $q, + mmaModDataComponent, $mmaModDataPrefetchHandler, mmCoreDownloading, mmCoreNotDownloaded, $mmContentLinkHandlerFactory, + mmCoreEventPackageStatusChanged, mmCoreOutdated, $mmCoursePrefetchDelegate, mmaModDataEventEntryChanged, $translate, + $mmaModDataSync) { + var self = {}; + + /** + * Course content handler. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHandlers#courseContent + */ + self.courseContent = function() { + + var self = {}; + + /** + * Whether or not the module is enabled for the site. + * + * @return {Boolean} + */ + self.isEnabled = function() { + return $mmaModData.isPluginEnabled(); + }; + + /** + * Get the controller. + * + * @param {Object} module The module info. + * @param {Number} courseId The course ID. + * @return {Function} + */ + self.getController = function(module, courseId) { + return function($scope) { + var downloadBtn = { + hidden: true, + icon: 'ion-ios-cloud-download-outline', + label: 'mm.core.download', + action: function(e) { + if (e) { + e.preventDefault(); + e.stopPropagation(); + } + download(); + } + }, + refreshBtn = { + hidden: true, + icon: 'ion-android-refresh', + label: 'mm.core.refresh', + action: function(e) { + if (e) { + e.preventDefault(); + e.stopPropagation(); + } + $mmaModData.invalidateContent(module.id, courseId).finally(function() { + download(); + }); + } + }; + + $scope.title = module.name; + $scope.icon = $mmCourse.getModuleIconSrc('data'); + $scope.class = 'mma-mod_data-handler'; + $scope.buttons = [downloadBtn, refreshBtn]; + $scope.spinner = true; // Show spinner while calculating status. + + $scope.action = function(e) { + if (e) { + e.preventDefault(); + e.stopPropagation(); + } + $state.go('site.mod_data', {module: module, moduleid: module.id, courseid: courseId}); + }; + + function download() { + + $scope.spinner = true; // Show spinner since this operation might take a while. + // We need to call getDownloadSize, the package might have been updated. + $mmaModDataPrefetchHandler.getDownloadSize(module, courseId).then(function(size) { + $mmUtil.confirmDownloadSize(size).then(function() { + return $mmaModDataPrefetchHandler.prefetch(module, courseId).catch(function(error) { + if (!$scope.$$destroyed) { + $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true); + return $q.reject(); + } + }); + }).catch(function() { + // User hasn't confirmed, stop spinner. + $scope.spinner = false; + }); + }).catch(function(error) { + $scope.spinner = false; + $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true); + }); + } + + // Show buttons according to module status. + function showStatus(status) { + if (status) { + $scope.spinner = status === mmCoreDownloading; + downloadBtn.hidden = status !== mmCoreNotDownloaded; + refreshBtn.hidden = status !== mmCoreOutdated; + } + } + + // Listen for changes on this module status. + var statusObserver = $mmEvents.on(mmCoreEventPackageStatusChanged, function(data) { + if (data.siteid === $mmSite.getId() && data.componentId === module.id && + data.component === mmaModDataComponent) { + showStatus(data.status); + } + }); + + // Get current status to decide which icon should be shown. + $mmCoursePrefetchDelegate.getModuleStatus(module, courseId).then(showStatus); + + $scope.$on('$destroy', function() { + statusObserver && statusObserver.off && statusObserver.off(); + }); + }; + }; + + return self; + }; + + /** + * Content links handler for module index page. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHandlers#indexLinksHandler + */ + self.indexLinksHandler = $mmContentLinksHelper.createModuleIndexLinkHandler('mmaModData', 'data', $mmaModData); + + + /** + * Content links handler for database show entry. + * Match mod/data/view.php?d=6&rid=5 with a valid data id and entryid. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHandlers#showEntryLinksHandler + */ + self.showEntryLinksHandler = $mmContentLinkHandlerFactory.createChild( + /\/mod\/data\/view\.php.*([\?\&](d|rid|page|group|mode)=\d+)/, '$mmCourseDelegate_mmaModData'); + + // Check if the showEntryLinksHandler is enabled for a certain site. See $mmContentLinkHandlerFactory#isEnabled. + self.showEntryLinksHandler.isEnabled = $mmaModData.isPluginEnabled; + + // Get actions to perform with the link. See $mmContentLinkHandlerFactory#getActions. + self.showEntryLinksHandler.getActions = function(siteIds, url, params, courseId) { + if (typeof params.d == 'undefined') { + // Id not defined. Cannot treat the URL. + return false; + } + + if ((!params.mode || params.mode != "single") && typeof params.rid == 'undefined') { + return false; + } + + return [{ + action: function(siteId) { + var modal = $mmUtil.showModalLoading(), + dataId = parseInt(params.d, 10), + rId = parseInt(params.rid, 10) || false, + group = parseInt(params.group, 10) || false, + page = parseInt(params.page, 10) || false; + + return $mmCourse.getModuleBasicInfoByInstance(dataId, 'data', siteId).then(function(module) { + var stateParams = { + moduleid: module.id, + module: module, + courseid: module.course + }; + + if (group) { + stateParams.group = group; + } + + if (params.mode && params.mode == "single") { + stateParams.page = page || 1; + } else if (rId) { + stateParams.entryid = rId; + } + + + return $mmContentLinksHelper.goInSite('site.mod_data-entry', stateParams, siteId); + }).finally(function() { + modal.dismiss(); + }); + } + }]; + }; + + /** + * Convenience function to help get courseId. + * @param {Number} dataId Database Id. + * @param {Number} siteId Site Id, if not set, current site will be used. + * @param {Number} courseId Course Id if already set. + * @return {Promise} Resolved with course Id when done. + */ + function getActivityCourseIdIfNotSet(dataId, siteId, courseId) { + if (courseId) { + return $q.when(courseId); + } + + return $mmCourse.getModuleBasicInfoByInstance(dataId, 'data', siteId).then(function(module) { + return module.course; + }); + } + + /** + * Content links handler for database approve/disapprove entry. + * Match mod/data/view.php?d=6&approve=5 with a valid data id and entryid. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHandlers#approveEntryLinksHandler + */ + self.approveEntryLinksHandler = $mmContentLinkHandlerFactory.createChild( + /\/mod\/data\/view\.php.*([\?\&](d|approve|disapprove)=\d+)/, '$mmCourseDelegate_mmaModData'); + + // Check if the approveEntryLinksHandler is enabled for a certain site. See $mmContentLinkHandlerFactory#isEnabled. + self.approveEntryLinksHandler.isEnabled = $mmaModData.isPluginEnabled; + + // Get actions to perform with the link. See $mmContentLinkHandlerFactory#getActions. + self.approveEntryLinksHandler.getActions = function(siteIds, url, params, courseId) { + if (typeof params.d == 'undefined' || (typeof params.approve == 'undefined' && typeof params.disapprove == 'undefined')) { + // Required fields not defined. Cannot treat the URL. + return false; + } + + return [{ + action: function(siteId) { + var modal = $mmUtil.showModalLoading(), + dataId = parseInt(params.d, 10), + entryId = parseInt(params.approve, 10) || parseInt(params.disapprove, 10), + approve = parseInt(params.approve, 10) ? true : false; + + return getActivityCourseIdIfNotSet(dataId, siteId, courseId).then(function(cId) { + courseId = cId; + + // Approve/disapprove entry. + return $mmaModData.approveEntry(dataId, entryId, approve, courseId, siteId).catch(function(message) { + modal.dismiss(); + $mmUtil.showErrorModalDefault(message, 'mma.mod_data.errorapproving', true); + + return $q.reject(); + }); + }).then(function() { + var promises = []; + promises.push($mmaModData.invalidateEntryData(dataId, entryId, siteId)); + promises.push($mmaModData.invalidateEntriesData(dataId, siteId)); + + return $q.all(promises); + }).then(function() { + $mmEvents.trigger(mmaModDataEventEntryChanged, {dataId: dataId, entryId: entryId, siteId: siteId}); + + modal.dismiss(); + $mmUtil.showToast(approve ? 'mma.mod_data.recordapproved' : 'mma.mod_data.recorddisapproved', true, 3000); + }).finally(function() { + // Just in case. In fact we need to dismiss the modal before showing a toast or error message. + modal.dismiss(); + }); + } + }]; + }; + + /** + * Content links handler for database delete entry. + * Match mod/data/view.php?d=6&delete=5 with a valid data id and entryid. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHandlers#deleteEntryLinksHandler + */ + self.deleteEntryLinksHandler = $mmContentLinkHandlerFactory.createChild( + /\/mod\/data\/view\.php.*([\?\&](d|delete)=\d+)/, '$mmCourseDelegate_mmaModData'); + + // Check if the deleteEntryLinksHandler is enabled for a certain site. See $mmContentLinkHandlerFactory#isEnabled. + self.deleteEntryLinksHandler.isEnabled = $mmaModData.isPluginEnabled; + + // Get actions to perform with the link. See $mmContentLinkHandlerFactory#getActions. + self.deleteEntryLinksHandler.getActions = function(siteIds, url, params, courseId) { + if (typeof params.d == 'undefined' || typeof params.delete == 'undefined') { + // Required fields not defined. Cannot treat the URL. + return false; + } + + return [{ + action: function(siteId) { + // Confirm before delete. + return $mmUtil.showConfirm($translate.instant('mma.mod_data.confirmdeleterecord')).then(function() { + var modal = $mmUtil.showModalLoading(), + dataId = parseInt(params.d, 10), + entryId = parseInt(params.delete, 10); + + return getActivityCourseIdIfNotSet(dataId, siteId, courseId).then(function(cId) { + courseId = cId; + + // Delete entry. + return $mmaModData.deleteEntry(dataId, entryId, courseId, siteId, true).catch(function(message) { + modal.dismiss(); + $mmUtil.showErrorModalDefault(message, 'mma.mod_data.errordeleting', true); + + return $q.reject(); + }); + }).then(function() { + var promises = []; + promises.push($mmaModData.invalidateEntryData(dataId, entryId, siteId)); + promises.push($mmaModData.invalidateEntriesData(dataId, siteId)); + + return $q.all(promises); + }).then(function() { + $mmEvents.trigger(mmaModDataEventEntryChanged, {dataId: dataId, entryId: entryId, siteId: siteId, + deleted: true}); + + modal.dismiss(); + $mmUtil.showToast('mma.mod_data.recorddeleted', true, 3000); + }).finally(function() { + // Just in case. In fact we need to dismiss the modal before showing a toast or error message. + modal.dismiss(); + }); + }); + } + }]; + }; + + /** + * Content links handler for database add or edit entry. + * Match mod/data/edit.php?d=6&rid=6 with a valid data and optional record id. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHandlers#editEntryLinksHandler + */ + self.editEntryLinksHandler = $mmContentLinkHandlerFactory.createChild( + /\/mod\/data\/edit\.php.*([\?\&](d|rid)=\d+)/, '$mmCourseDelegate_mmaModData'); + + // Check if the showEntryLinksHandler is enabled for a certain site. See $mmContentLinkHandlerFactory#isEnabled. + self.editEntryLinksHandler.isEnabled = $mmaModData.isPluginEnabled; + + // Get actions to perform with the link. See $mmContentLinkHandlerFactory#getActions. + self.editEntryLinksHandler.getActions = function(siteIds, url, params, courseId) { + if (typeof params.d == 'undefined') { + // Id not defined. Cannot treat the URL. + return false; + } + + return [{ + action: function(siteId) { + var modal = $mmUtil.showModalLoading(), + dataId = parseInt(params.d, 10), + rId = parseInt(params.rid, 10) || false; + + return $mmCourse.getModuleBasicInfoByInstance(dataId, 'data', siteId).then(function(module) { + var stateParams = { + moduleid: module.id, + module: module, + courseid: module.course + }; + + if (rId) { + stateParams.entryid = rId; + } + + return $mmContentLinksHelper.goInSite('site.mod_data-edit', stateParams, siteId); + }).finally(function() { + modal.dismiss(); + }); + } + }]; + }; + + /** + * Synchronization handler. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHandlers#syncHandler + */ + self.syncHandler = function() { + + var self = {}; + + /** + * Execute the process. + * Receives the ID of the site affected, undefined for all sites. + * + * @param {String} [siteId] ID of the site affected, undefined for all sites. + * @return {Promise} Promise resolved when done, rejected if failure. + */ + self.execute = function(siteId) { + return $mmaModDataSync.syncAllDatabases(siteId); + }; + + /** + * Get the time between consecutive executions. + * + * @return {Number} Time between consecutive executions (in ms). + */ + self.getInterval = function() { + return 600000; // 10 minutes. + }; + + /** + * Whether it's a synchronization process or not. + * + * @return {Boolean} True if is a sync process, false otherwise. + */ + self.isSync = function() { + return true; + }; + + /** + * Whether the process uses network or not. + * + * @return {Boolean} True if uses network, false otherwise. + */ + self.usesNetwork = function() { + return true; + }; + + return self; + }; + + return self; +}); diff --git a/www/addons/mod/data/services/helper.js b/www/addons/mod/data/services/helper.js new file mode 100644 index 00000000000..a07ccd36b4f --- /dev/null +++ b/www/addons/mod/data/services/helper.js @@ -0,0 +1,711 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Helper to gather some common functions for database. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataHelper + */ +.factory('$mmaModDataHelper', function($mmaModData, $mmaModDataFieldsDelegate, $q, mmaModDataComponent, $mmFileUploader, $mmSite, + $mmaModDataOffline, $mmFS, $mmFileUploaderHelper, $mmSitesManager, $translate) { + + var self = { + searchOther: { + 'fn': 'firstname', + 'ln': 'lastname' + } + }; + + /** + * Displays fields for being shown. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#displayShowFields + * @param {String} template Template HMTL. + * @param {Array} fields Fields that defines every content in the entry. + * @param {Object} entry Entry. + * @param {String} mode Mode list or show. + * @param {Object} actions Actions that can be performed to the record. + * @return {String} Generated HTML. + */ + self.displayShowFields = function(template, fields, entry, mode, actions) { + if (!template) { + return ""; + } + + var replace, render; + + // Replace the fields found on template. + angular.forEach(fields, function(field) { + replace = "[[" + field.name + "]]"; + replace = replace.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + replace = new RegExp(replace, 'gi'); + + // Replace field by a generic directive. + render = ''; + template = template.replace(replace, render); + }); + + angular.forEach(actions, function(enabled, action) { + replace = new RegExp("##" + action + "##", 'gi'); + if (enabled) { + if (action == 'moreurl') { + // Render more url directly because it can be part of an HTML attribute. + render = $mmSite.getURL() + '/mod/data/view.php?d={{data.id}}&rid=' + entry.id; + } else if (action == 'approvalstatus') { + render = $translate.instant('mma.mod_data.' + (entry.approved ? 'approved' : 'notapproved')); + } else { + render = ''; + } + template = template.replace(replace, render); + } else { + template = template.replace(replace, ""); + } + }); + + return template; + }; + + /** + * Returns an object with all the actions that the user can do over the record. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#getActions + * @param {Object} database Database activity. + * @param {Object} accessInfo Access info to the activity. + * @param {Object} record Entry or record where the actions will be performed. + * @return {Object} Keyed with the action names and boolean to evalute if it can or cannot be done. + */ + self.getActions = function(database, accessInfo, record) { + var replacements = {}; + + replacements.more = true; + replacements.moreurl = true; + replacements.user = true; + replacements.userpicture = true; + replacements.timeadded = true; + replacements.timemodified = true; + + replacements.edit = record.canmanageentry && !record.deleted; // This already checks capabilities and readonly period. + replacements.delete = record.canmanageentry; + replacements.approve = database.approval && accessInfo.canapprove && !record.approved && !record.deleted; + replacements.disapprove = database.approval && accessInfo.canapprove && record.approved && !record.deleted; + + replacements.approvalstatus = database.approval; + replacements.comments = database.comments; + + // Unsupported actions. + replacements.delcheck = false; + replacements.export = false; + + return replacements; + }; + + /** + * Returns the record with the offline actions applied. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#applyOfflineActions + * @param {Object} record Entry to modify. + * @param {Object} offlineActions Offline data with the actions done. + * @param {Object} fields Entry defined fields indexed by fieldid. + * @return {Object} Modified entry. + */ + self.applyOfflineActions = function(record, offlineActions, fields) { + var promises = []; + angular.forEach(offlineActions, function(action) { + switch (action.action) { + case 'approve': + record.approved = true; + break; + case 'disapprove': + record.approved = false; + break; + case 'delete': + record.deleted = true; + break; + case 'add': + case 'edit': + var offlineContents = {}; + angular.forEach(action.fields, function(offlineContent) { + if (typeof offlineContents[offlineContent.fieldid] == "undefined") { + offlineContents[offlineContent.fieldid] = {}; + } + + if (offlineContent.subfield) { + offlineContents[offlineContent.fieldid][offlineContent.subfield] = JSON.parse(offlineContent.value); + } else { + offlineContents[offlineContent.fieldid][''] = JSON.parse(offlineContent.value); + } + }); + + // Override field contents. + angular.forEach(fields, function(field) { + if ($mmaModDataFieldsDelegate.hasFiles(field)) { + promises.push(self.getStoredFiles(record.dataid, record.id, field.id).then(function(offlineFiles) { + record.contents[field.id] = $mmaModDataFieldsDelegate.overrideData(field, record.contents[field.id], + offlineContents[field.id], offlineFiles); + })); + } else { + record.contents[field.id] = $mmaModDataFieldsDelegate.overrideData(field, record.contents[field.id], + offlineContents[field.id]); + } + }); + break; + } + }); + return $q.all(promises).then(function() { + return record; + }); + }; + + /** + * Displays Advanced Search Fields. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#displayAdvancedSearchFields + * @param {String} template Template HMTL. + * @param {Array} fields Fields that defines every content in the entry. + * @return {String} Generated HTML. + */ + self.displayAdvancedSearchFields = function(template, fields) { + if (!template) { + return ""; + } + + var replace; + + // Replace the fields found on template. + angular.forEach(fields, function(field) { + replace = "[[" + field.name + "]]"; + replace = replace.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + replace = new RegExp(replace, 'gi'); + + // Replace field by a generic directive. + var render = ''; + template = template.replace(replace, render); + }); + + // Not pluginable other search elements. + angular.forEach(self.searchOther, function(field, name) { + replace = new RegExp("##" + field + "##", 'gi'); + + // Replace field by the text input. + var render = ''; + template = template.replace(replace, render); + }); + return template; + }; + + /** + * Return the form data. + * + * @param {Object} form Form (DOM element). + * @return {Object} Data retrieved from form. + */ + function getFormData(form) { + var formData = {}; + + angular.forEach(form.elements, function(element) { + var name = element.name || ''; + // Ignore submit inputs. + if (!name || element.type == 'submit' || element.tagName == 'BUTTON') { + return; + } + + // Get the value. + if (element.type == 'checkbox') { + if (typeof formData[name] == "undefined") { + formData[name] = {}; + } + formData[name][element.value] = !!element.checked; + } else if (element.type == 'radio') { + if (element.checked) { + formData[name] = element.value; + } + } else { + formData[name] = element.value; + } + }); + + return formData; + } + + /** + * Retrieve the entered data in search in a form. + * We don't use ng-model because it doesn't detect changes done by JavaScript. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#getSearchDataFromForm + * @param {Object} form Form (DOM element). + * @param {Array} fields Fields that defines every content in the entry. + * @return {Object} Object with the answers. + */ + self.getSearchDataFromForm = function(form, fields) { + if (!form || !form.elements) { + return {}; + } + + var searchedData = getFormData(form); + + // Filter and translate fields to each field plugin. + var advancedSearch = []; + angular.forEach(fields, function(field) { + var fieldData = $mmaModDataFieldsDelegate.getFieldSearchData(field, searchedData); + if (fieldData) { + angular.forEach(fieldData, function(data) { + data.value = JSON.stringify(data.value); + // WS wants values in Json format. + advancedSearch.push(data); + }); + } + }); + + // Not pluginable other search elements. + angular.forEach(self.searchOther, function(field, name) { + if (searchedData[name]) { + // WS wants values in Json format. + advancedSearch.push({ + name: name, + value: JSON.stringify(searchedData[name]) + }); + } + }); + + return advancedSearch; + }; + + /** + * Displays Edit Search Fields. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#displayEditFields + * @param {String} template Template HMTL. + * @param {Array} fields Fields that defines every content in the entry. + * @param {Array} [contents] Contents for the editing entry (if editing). + * @return {String} Generated HTML. + */ + self.displayEditFields = function(template, fields) { + if (!template) { + return ""; + } + + var replace; + + // Replace the fields found on template. + angular.forEach(fields, function(field) { + replace = "[[" + field.name + "]]"; + replace = replace.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + replace = new RegExp(replace, 'gi'); + + // Replace field by a generic directive. + var render = ''; + template = template.replace(replace, render); + + // Replace the field id tag. + replace = "[[" + field.name + "#id]]"; + replace = replace.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + replace = new RegExp(replace, 'gi'); + + template = template.replace(replace, 'field_'+ field.id); + }); + + return template; + }; + + /** + * Retrieve the entered data in the edit form. + * We don't use ng-model because it doesn't detect changes done by JavaScript. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#getEditDataFromForm + * @param {Object} form Form (DOM element). + * @param {Array} fields Fields that defines every content in the entry. + * @param {Number} [dataId] Database Id. If set, files will be uploaded and itemId set. + * @param {Number} entryId Entry Id. + * @param {Object} entryContents Original entry contents indexed by field id. + * @param {Boolean} offline True to prepare the data for an offline uploading, false otherwise. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} That contains object with the answers. + */ + self.getEditDataFromForm = function(form, fields, dataId, entryId, entryContents, offline, siteId) { + if (!form || !form.elements) { + return $q.when({}); + } + + siteId = siteId || $mmSite.getId(); + + var formData = getFormData(form); + + // Filter and translate fields to each field plugin. + var edit = [], + promises = []; + angular.forEach(fields, function(field) { + promises.push($q.when($mmaModDataFieldsDelegate.getFieldEditData(field, formData, entryContents[field.id])) + .then(function (fieldData) { + if (fieldData) { + var proms = []; + + angular.forEach(fieldData, function(data) { + var dataProm; + + // Upload Files if asked. + if (dataId && data.files) { + dataProm = self.uploadOrStoreFiles(dataId, 0, entryId, data.fieldid, data.files, offline, siteId).then(function(filesResult) { + delete data.files; + data.value = filesResult; + }); + } else { + dataProm = $q.when(); + } + + proms.push(dataProm.then(function() { + if (data.value) { + data.value = JSON.stringify(data.value); + } + if (typeof data.subfield == "undefined") { + data.subfield = ""; + } + + // WS wants values in Json format. + edit.push(data); + })); + }); + + return $q.all(proms); + } + })); + }); + + return $q.all(promises).then(function() { + return edit; + }); + }; + + /** + * Retrieve the temp files to be updated. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#getEditTmpFiles + * @param {Object} form Form (DOM element). + * @param {Array} fields Fields that defines every content in the entry. + * @param {Number} [dataId] Database Id. If set, fils will be uploaded and itemId set. + * @param {Object} entryContents Original entry contents indexed by field id. + * @return {Promise} That contains object with the files. + */ + self.getEditTmpFiles = function(form, fields, dataId, entryContents) { + if (!form || !form.elements) { + return $q.when([]); + } + + var formData = getFormData(form); + + // Filter and translate fields to each field plugin. + var promises = []; + angular.forEach(fields, function(field) { + promises.push( + $q.when($mmaModDataFieldsDelegate.getFieldEditFiles(field, formData, entryContents[field.id])) + ); + }); + + return $q.all(promises).then(function(fieldsFiles) { + var files = []; + + angular.forEach(fieldsFiles, function(fieldFiles) { + files = files.concat(fieldFiles); + }); + return files; + }); + }; + + /** + * Check if data has been changed by the user. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#hasEditDataChanged + * @param {Object} form Form (DOM element). + * @param {Array} fields Fields that defines every content in the entry. + * @param {Number} [dataId] Database Id. If set, fils will be uploaded and itemId set. + * @param {Object} entryContents Original entry contents indexed by field id. + * @return {Promise} True if changed, false if not. + */ + self.hasEditDataChanged = function(form, fields, dataId, entryContents) { + var inputData = getFormData(form), + promises = []; + + angular.forEach(fields, function(field) { + promises.push($mmaModDataFieldsDelegate.hasFieldDataChanged(field, inputData, entryContents[field.id])); + }); + // Will reject on first change detected. + return $q.all(promises).then(function() { + // No changes. + return false; + }).catch(function() { + // Has changes. + return true; + }); + }; + + /** + * Upload or store some files, depending if the user is offline or not. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#uploadOrStoreFiles + * @param {Number} dataId Database ID. + * @param {Number} [itemId] Draft ID to use. Undefined or 0 to create a new draft ID. + * @param {Number} entryId Entry ID or, if creating, timemodified. + * @param {Number} fieldId Field ID. + * @param {Object[]} files List of files. + * @param {Boolean} offline True if files sould be stored for offline, false to upload them. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved if success. + */ + self.uploadOrStoreFiles = function(dataId, itemId, entryId, fieldId, files, offline, siteId) { + if (files.length) { + if (offline) { + return self.storeFiles(dataId, entryId, fieldId, files, siteId); + } + return $mmFileUploader.uploadOrReuploadFiles(files, mmaModDataComponent, itemId, siteId); + } + return $q.when(0); + }; + + /** + * Given a list of files (either online files or local files), store the local files in a local folder + * to be submitted later. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#storeFiles + * @param {Number} dataId Database ID. + * @param {Number} entryId Entry ID or, if creating, timemodified. + * @param {Number} fieldId Field ID. + * @param {Object[]} files List of files. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved if success, rejected otherwise. + */ + self.storeFiles = function(dataId, entryId, fieldId, files, siteId) { + // Get the folder where to store the files. + return $mmaModDataOffline.getEntryFieldFolder(dataId, entryId, fieldId, siteId).then(function(folderPath) { + return $mmFileUploader.storeFilesToUpload(folderPath, files); + }); + }; + + /** + * Delete stored attachment files for an entry. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#deleteStoredFiles + * @param {Number} dataId Database ID. + * @param {Number} entryId Entry ID or, if creating, timemodified. + * @param {Number} fieldId Field ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when deleted. + */ + self.deleteStoredFiles = function(dataId, entryId, fieldId, siteId) { + return $mmaModDataOffline.getEntryFieldFolder(dataId, entryId, fieldId, siteId).then(function(folderPath) { + return $mmFS.removeDir(folderPath); + }); + }; + + /** + * Get a list of stored attachment files for a new entry. See $mmaModDataHelper#storeFiles. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#getStoredFiles + * @param {Number} dataId Database ID. + * @param {Number} entryId Entry ID or, if creating, timemodified. + * @param {Number} fieldId Field ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved with the files. + */ + self.getStoredFiles = function(dataId, entryId, fieldId, siteId) { + return $mmaModDataOffline.getEntryFieldFolder(dataId, entryId, fieldId, siteId).then(function(folderPath) { + return $mmFileUploaderHelper.getStoredFiles(folderPath).catch(function() { + // Ignore not found files. + return []; + }); + }); + }; + + /** + * Add a prefix to all rules in a CSS string. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#prefixCSS + * @param {String} css CSS code to be prefixed. + * @param {String} prefix Prefix css selector. + * @return {String} Prefixed CSS. + */ + self.prefixCSS = function(css, prefix) { + if (!css) { + return ""; + } + // Remove comments first. + var regExp = /\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$/gm; + css = css.replace(regExp, ""); + // Add prefix. + regExp = /([^]*?)({[^]*?}|,)/g; + return css.replace(regExp, prefix + " $1 $2"); + }; + + /** + * Get page info related to an entry. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#getPageInfoByEntry + * @param {Number} dataId Data ID. + * @param {Number} entryId Entry ID. + * @param {Number} groupId Group ID. + * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. + * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} [siteId] Site ID. Current if not defined. + * @return {Promise} Containing page number, if has next and have following page. + */ + self.getPageInfoByEntry = function(dataId, entryId, groupId, forceCache, ignoreCache, siteId) { + return self.getAllEntriesIds(dataId, groupId, forceCache, ignoreCache, siteId).then(function(entries) { + for (var index in entries) { + if (entries[index] == entryId) { + index = parseInt(index, 10); + return { + previousId: entries[index - 1] || false, + nextId: entries[index + 1] || false, + entryId: entryId, + page: index + 1, // Parsed to natural language. + numEntries: entries.length + }; + } + } + return false; + }); + }; + + /** + * Get page info related to an entry by page number. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#getPageInfoByPage + * @param {Number} dataId Data ID. + * @param {Number} page Page number. + * @param {Number} groupId Group ID. + * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. + * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} [siteId] Site ID. Current if not defined. + * @return {Promise} Containing page number, if has next and have following page. + */ + self.getPageInfoByPage = function(dataId, page, groupId, forceCache, ignoreCache, siteId) { + return self.getAllEntriesIds(dataId, groupId, forceCache, ignoreCache, siteId).then(function(entries) { + var index = parseInt(page, 10) - 1, + entryId = entries[index]; + if (entryId) { + return { + previousId: entries[index - 1] || false, + nextId: entries[index + 1] || false, + entryId: entryId, + page: page, // Parsed to natural language. + numEntries: entries.length + }; + } + return false; + }); + }; + + /** + * Fetch all entries and return it's Id + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#getAllEntriesIds + * @param {Number} dataId Data ID. + * @param {Number} groupId Group ID. + * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. + * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} [siteId] Site ID. Current if not defined. + * @return {Promise} Resolved with an array of entry ID. + */ + self.getAllEntriesIds = function(dataId, groupId, forceCache, ignoreCache, siteId) { + return $mmaModData.fetchAllEntries(dataId, groupId, undefined, undefined, undefined, forceCache, ignoreCache, siteId) + .then(function(entries) { + return entries.map(function(entry) { + return entry.id; + }); + }); + }; + + /** + * Get an online or offline entry. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#getEntry + * @param {Object} data Database. + * @param {Number} entryId Entry ID. + * @param {Object} [offlineActions] Offline data with the actions done. Required for offline entries. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved with the entry. + */ + self.getEntry = function(data, entryId, offlineActions, siteId) { + if (entryId > 0) { + // It's an online entry, get it from WS. + return $mmaModData.getEntry(data.id, entryId, siteId); + } + + // It's an offline entry, search it in the offline actions. + return $mmSitesManager.getSite(siteId).then(function(site) { + for (var x in offlineActions) { + if (offlineActions[x].action == 'add') { + var offlineEntry = offlineActions[x], + siteInfo = site.getInfo(), + entryData = { + id: offlineEntry.entryid, + canmanageentry: true, + approved: !data.approval || data.manageapproved, + dataid: offlineEntry.dataid, + groupid: offlineEntry.groupid, + timecreated: -offlineEntry.entryid, + timemodified: -offlineEntry.entryid, + userid: siteInfo.userid, + fullname: siteInfo.fullname, + contents: {} + }; + + return {entry: entryData}; + } + } + }); + }; + + return self; +}); diff --git a/www/addons/mod/data/services/prefetch_handler.js b/www/addons/mod/data/services/prefetch_handler.js new file mode 100644 index 00000000000..bdcf40f3a66 --- /dev/null +++ b/www/addons/mod/data/services/prefetch_handler.js @@ -0,0 +1,364 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.mod_data') + +/** + * Mod data prefetch handler. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataPrefetchHandler + */ +.factory('$mmaModDataPrefetchHandler', function($mmaModData, mmaModDataComponent, $mmFilepool, $q, $mmUtil, $mmPrefetchFactory, + $mmSite, $mmGroups, $mmCourse, $mmComments) { + + var self = $mmPrefetchFactory.createPrefetchHandler(mmaModDataComponent); + + // RegExp to check if a module has updates based on the result of $mmCoursePrefetchDelegate#getCourseUpdates. + self.updatesNames = /^configuration$|^.*files$|^entries$|^gradeitems$|^outcomes$|^comments$|^ratings/; + + /** + * Download the module. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataPrefetchHandler#download + * @param {Object} module The module object returned by WS. + * @param {Number} courseId Course ID the module belongs to. + * @return {Promise} Promise resolved when all files have been downloaded. Data returned is not reliable. + */ + self.download = function(module, courseId) { + // Database cannot be downloaded right away, only prefetched. + return self.prefetch(module, courseId); + }; + + /** + * Get the list of downloadable files. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataPrefetchHandler#getFiles + * @param {Object} module Module to get the files. + * @param {Number} courseId Course ID the module belongs to. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved with the list of files. + */ + self.getFiles = function(module, courseId, siteId) { + siteId = siteId || $mmSite.getId(); + + return getDatabaseInfoHelper(module, courseId, true, undefined, undefined, siteId).then(function(info) { + return info.files; + }); + }; + + /** + * Helper function to get all database info just once. + * + * @param {Object} module Module to get the files. + * @param {Number} courseId Course ID the module belongs to. + * @param {Boolean} [omitFail] True to always return even if fails. Default false. + * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. + * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} siteId Site ID. + * @return {Promise} Promise resolved with the info fetched. + */ + function getDatabaseInfoHelper(module, courseId, omitFail, forceCache, ignoreCache, siteId) { + var database, + groups = [], + entries = [], + files = []; + + return $mmaModData.getDatabase(courseId, module.id, siteId, forceCache).then(function(data) { + files = self.getIntroFilesFromInstance(module, data); + + database = data; + return $mmGroups.getActivityGroupInfo(module.id, false, undefined, siteId).then(function(groupInfo) { + if (!groupInfo.groups || groupInfo.groups.length == 0) { + groupInfo.groups = [{id: 0}]; + } + groups = groupInfo.groups; + + return getAllUniqueEntries(database.id, groups, forceCache, ignoreCache, siteId); + }); + }).then(function(uniqueEntries) { + entries = uniqueEntries; + files = files.concat(getEntriesFiles(entries)); + + return { + database: database, + groups: groups, + entries: entries, + files: files + }; + }).catch(function(message) { + if (omitFail) { + // Any error, return the info we have. + return { + database: database, + groups: groups, + entries: entries, + files: files + }; + } + return $q.reject(message); + }); + } + + /** + * Retrieves all the entries for all the groups and then returns only unique entries. + * + * @param {Number} dataId Database Id. + * @param {Array} groups Array of groups in the activity. + * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. + * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} siteId Site ID. + * @return {Promise} All unique entries. + */ + function getAllUniqueEntries(dataId, groups, forceCache, ignoreCache, siteId) { + var promises = []; + + angular.forEach(groups, function(group) { + promises.push($mmaModData.fetchAllEntries(dataId, group.id, undefined, undefined, undefined, forceCache, + ignoreCache, siteId)); + }); + + return $q.all(promises).then(function(responses) { + var uniqueEntries = {}; + + angular.forEach(responses, function(groupEntries) { + angular.forEach(groupEntries, function(entry) { + uniqueEntries[entry.id] = entry; + }); + }); + + return uniqueEntries; + }); + } + + /** + * Returns the file contained in the entries. + * + * @param {Array} entries List of entries to get files from. + * @return {Array} List of files. + */ + function getEntriesFiles(entries) { + var files = []; + + angular.forEach(entries, function(entry) { + angular.forEach(entry.contents, function(content) { + files = files.concat(content.files); + }); + }); + + return files; + } + + /** + * Returns database intro files. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataPrefetchHandler#getIntroFiles + * @param {Object} module The module object returned by WS. + * @param {Number} courseId Course ID. + * @return {Promise} Promise resolved with list of intro files. + */ + self.getIntroFiles = function(module, courseId) { + return $mmaModData.getDatabase(courseId, module.id).catch(function() { + // Not found, return undefined so module description is used. + }).then(function(database) { + return self.getIntroFilesFromInstance(module, database); + }); + }; + + /** + * Get revision of a data. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataPrefetchHandler#getRevision + * @param {Object} module Module to get the revision. + * @param {Number} courseId Course ID the module belongs to. + * @return {Number} Promise resolved with revision. + */ + self.getRevision = function(module, courseId) { + // Data will always be controlled using the getCourseUpdates. + return 0; + }; + + /** + * Get timemodified of a data. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataPrefetchHandler#getTimemodified + * @param {Object} module Module to get the timemodified. + * @param {Number} courseId Course ID the module belongs to. + * @return {Promise} Promise resolved with timemodified. + */ + self.getTimemodified = function(module, courseId) { + var siteId = $mmSite.getId(); + + return $mmaModData.getDatabase(courseId, module.id, siteId).then(function(database) { + var files = self.getIntroFilesFromInstance(module, database); + + return Math.max(database.timemodified || 0, $mmFilepool.getTimemodifiedFromFileList(files)); + }).catch(function() { + return 0; + }); + }; + + /** + * Invalidate the prefetched content. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataPrefetchHandler#invalidateContent + * @param {Number} moduleId The module ID. + * @param {Number} courseId Course ID of the module. + * @return {Promise} + */ + self.invalidateContent = function(moduleId, courseId) { + return $mmaModData.invalidateContent(moduleId, courseId); + }; + + /** + * Invalidates WS calls needed to determine module status. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataPrefetchHandler#invalidateModule + * @param {Object} module Module to invalidate. + * @param {Number} courseId Course ID the module belongs to. + * @return {Promise} Promise resolved when done. + */ + self.invalidateModule = function(module, courseId) { + return $mmaModData.invalidateDatabaseData(courseId); + }; + + /** + * Check if a database is downloadable. + * A database isn't downloadable if it's not open yet. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataPrefetchHandler#isDownloadable + * @param {Object} module Module to check. + * @param {Number} courseId Course ID the module belongs to. + * @return {Promise} Promise resolved with true if downloadable, resolved with false otherwise. + */ + self.isDownloadable = function(module, courseId) { + return $mmaModData.getDatabase(courseId, module.id, false, true).then(function(database) { + return $mmaModData.getDatabaseAccessInformation(database.id).then(function(accessData) { + // Check if database is restricted by time. + if (!accessData.timeavailable) { + var time = $mmUtil.timestamp(); + + // It is restricted, checking times. + if (database.timeavailablefrom && time < database.timeavailablefrom) { + return false; + } + if (database.timeavailableto && time > database.timeavailableto) { + return false; + } + } + return true; + }); + }); + }; + + /** + * Whether or not the module is enabled for the site. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataPrefetchHandler#isEnabled + * @return {Boolean} + */ + self.isEnabled = function() { + return $mmaModData.isPluginEnabled(); + }; + + /** + * Prefetch the module. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataPrefetchHandler#prefetch + * @param {Object} module The module object returned by WS. + * @param {Number} courseId Course ID the module belongs to. + * @param {Boolean} single True if we're downloading a single module, false if we're downloading a whole section. + * @return {Promise} Promise resolved when all files have been downloaded. Data returned is not reliable. + */ + self.prefetch = function(module, courseId, single) { + return self.prefetchPackage(module, courseId, single, prefetchDatabase); + }; + + /** + * Prefetch a database. + * + * @param {Object} module The module object returned by WS. + * @param {Number} courseId Course ID the module belongs to. + * @param {Boolean} single True if we're downloading a single module, false if we're downloading a whole section. + * @param {String} siteId Site ID. + * @return {Promise} Promise resolved with an object with 'revision' and 'timemod'. + */ + function prefetchDatabase(module, courseId, single, siteId) { + siteId = siteId || $mmSite.getId(); + + // Prefetch the database data. + return getDatabaseInfoHelper(module, courseId, false, false, true, siteId).then(function(info) { + var database = info.database, + promises = []; + + promises.push($mmaModData.getFields(database.id, false, true, siteId)); + + promises.push($mmFilepool.addFilesToQueueByUrl(siteId, info.files, self.component, module.id)); + + angular.forEach(info.groups, function(group) { + promises.push($mmaModData.getDatabaseAccessInformation(database.id, group.id, false, true, siteId)); + }); + + angular.forEach(info.entries, function(entry) { + promises.push($mmaModData.getEntry(database.id, entry.id, siteId)); + if (database.comments) { + promises.push($mmComments.getComments('module', database.coursemodule, 'mod_data', entry.id, 'database_entry', + 0, siteId)); + } + }); + + // Add Basic Info to manage links. + promises.push($mmCourse.getModuleBasicInfoByInstance(database.id, 'data', siteId)); + + return $q.all(promises); + }).then(function() { + // Get revision and timemodified. + + var promises = []; + promises.push(self.getRevision(module, courseId)); + promises.push(self.getTimemodified(module, courseId)); + + // Return revision and timemodified. + return $q.all(promises).then(function(list) { + return { + revision: list[0], + timemod: list[1] + }; + }); + }); + } + + return self; +}); diff --git a/www/addons/mod/data/templates/action.html b/www/addons/mod/data/templates/action.html new file mode 100644 index 00000000000..8c111539f47 --- /dev/null +++ b/www/addons/mod/data/templates/action.html @@ -0,0 +1,18 @@ + + + + + + + + + +{{ entry.timecreated * 1000 | mmFormatDate:"dffulldate" }} +{{ entry.timemodified * 1000 | mmFormatDate:"dffulldate" }} + + + {{ 'mm.core.pictureof' | translate:{$a: entry.fullname} }} + {{ 'mm.core.pictureof' | translate:{$a: entry.fullname} }} + + +{{entry.fullname}} diff --git a/www/addons/mod/data/templates/edit.html b/www/addons/mod/data/templates/edit.html new file mode 100644 index 00000000000..275ed7517ea --- /dev/null +++ b/www/addons/mod/data/templates/edit.html @@ -0,0 +1,27 @@ + + {{ title }} + + {{ 'mm.core.save' | translate }} + + + +
+ {{ 'mm.core.groupsseparate' | translate }} + {{ 'mm.core.groupsvisible' | translate }} + +
+
+ + +
+ + {{ editForm }} + +
+
+
+
+
diff --git a/www/addons/mod/data/templates/entry.html b/www/addons/mod/data/templates/entry.html new file mode 100644 index 00000000000..65dd300b012 --- /dev/null +++ b/www/addons/mod/data/templates/entry.html @@ -0,0 +1,44 @@ + + {{ title }} + + + + + + + + + + + +
+ {{ 'mm.core.hasdatatosync' | translate:{$a: moduleName} }} +
+ +
+ {{ 'mm.core.groupsseparate' | translate }} + {{ 'mm.core.groupsvisible' | translate }} + +
+
+ + + + {{ entryRendered }} + +
+ +
+ + +
+
+
+
diff --git a/www/addons/mod/data/templates/field.html b/www/addons/mod/data/templates/field.html new file mode 100644 index 00000000000..e0e75996ba2 --- /dev/null +++ b/www/addons/mod/data/templates/field.html @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/www/addons/mod/data/templates/index.html b/www/addons/mod/data/templates/index.html new file mode 100644 index 00000000000..fb2446fbac7 --- /dev/null +++ b/www/addons/mod/data/templates/index.html @@ -0,0 +1,87 @@ + + {{ title }} + + + + + + + + + + + + + + + +
+
+ {{ description }} +
+
+ + +
+ {{ 'mm.core.hasdatatosync' | translate:{$a: moduleName} }} +
+ +
+ {{ 'mm.core.groupsseparate' | translate }} + {{ 'mm.core.groupsvisible' | translate }} + +
+
+ {{ 'mma.mod_data.notopenyet' | translate:{$a: timeAvailableFromReadable} }} +
+ +
+ {{ 'mma.mod_data.expired' | translate:{$a: timeAvailableToReadable} }} +
+ +
+ {{ 'mma.mod_data.entrieslefttoaddtoview' | translate:{$a: {entrieslefttoview: access.entrieslefttoview} } }} +
+ +
+ {{ 'mma.mod_data.entrieslefttoadd' | translate:{$a: {entriesleft: access.entrieslefttoadd} } }} +
+ + + +
+ + + + {{ entriesRendered }} + +
+ +
+ + +
+ + +
+ +
+
+ + + {{ 'mma.mod_data.resetsettings' | translate}} + +
+
+
diff --git a/www/addons/mod/data/templates/search-modal.html b/www/addons/mod/data/templates/search-modal.html new file mode 100644 index 00000000000..8402fcd17a3 --- /dev/null +++ b/www/addons/mod/data/templates/search-modal.html @@ -0,0 +1,42 @@ + + + +

{{ 'mma.mod_data.search' | translate}}

+ +
+ + +
+ +
+ {{ 'mm.core.sortby' | translate }} + +
+ + {{ 'mma.mod_data.ascending' | translate }} + {{ 'mma.mod_data.descending' | translate }} + +
+ + {{ advancedSearch }} + +
+
+
+
\ No newline at end of file diff --git a/www/addons/mod/feedback/lang/cs.json b/www/addons/mod/feedback/lang/cs.json index 50c98674c0f..af958dc96ff 100644 --- a/www/addons/mod/feedback/lang/cs.json +++ b/www/addons/mod/feedback/lang/cs.json @@ -6,7 +6,7 @@ "captchaofflinewarning": "Dotazník se souborem captcha nemůže být dokončen, pokud není nakonfigurován režim offline nebo s vypnutým serverem.", "complete_the_form": "Klikněte zde a odpovězte na otázky...", "completed_feedbacks": "Odevzdané odpovědi", - "continue_the_form": "Pokračovat ve formuláři", + "continue_the_form": "Pokračovat v zodpovídání otázek ...", "feedback_is_not_open": "Dotazník není přístupný", "feedback_submitted_offline": "Tento dotazník byl uložen k pozdějšímu odevzdání.", "feedbackclose": "Povolit odpovědi", diff --git a/www/addons/mod/feedback/lang/da.json b/www/addons/mod/feedback/lang/da.json index 55d1b3cd1ba..6147eb30f82 100644 --- a/www/addons/mod/feedback/lang/da.json +++ b/www/addons/mod/feedback/lang/da.json @@ -5,7 +5,7 @@ "average": "Gennemsnit", "complete_the_form": "Svar på spørgsmålene...", "completed_feedbacks": "Afleverede svar", - "continue_the_form": "Fortsæt formularen", + "continue_the_form": "Fortsæt med at besvare spørgsmålene", "feedback_is_not_open": "Feedbacken er ikke åben", "feedbackclose": "Tillad svar til", "feedbackopen": "Tillad svar fra", diff --git a/www/addons/mod/feedback/lang/de.json b/www/addons/mod/feedback/lang/de.json index 7c665bbb337..4bb27721583 100644 --- a/www/addons/mod/feedback/lang/de.json +++ b/www/addons/mod/feedback/lang/de.json @@ -3,10 +3,10 @@ "anonymous": "Anonym", "anonymous_entries": "Anonyme Einträge ({{$a}})", "average": "Mittelwert", - "captchaofflinewarning": "Ein Feedback mit Captcha kann offline nicht beendet werden. Captcha funktioniert nicht, wenn der Server nicht konfiguriert ist oder der Server nicht antwortet.", + "captchaofflinewarning": "Ein Feedback mit Captcha kann nicht offline beendet werden. Captcha funktioniert nur, wenn der Server antwortet.", "complete_the_form": "Formular ausfüllen...", "completed_feedbacks": "Ausgefüllte Feedbacks", - "continue_the_form": "Ausfüllen fortsetzen", + "continue_the_form": "Beantwortung der Fragen fortsetzen ...", "feedback_is_not_open": "Feedback ist zu diesem Zeitpunkt nicht möglich", "feedback_submitted_offline": "Das Feedback wurde gespeichert, um es später zu übemitteln.", "feedbackclose": "Antworten erlauben bis", diff --git a/www/addons/mod/feedback/lang/el.json b/www/addons/mod/feedback/lang/el.json index 7dd8e2abab8..1d5dec70464 100644 --- a/www/addons/mod/feedback/lang/el.json +++ b/www/addons/mod/feedback/lang/el.json @@ -3,10 +3,12 @@ "anonymous": "Ανώνυμα", "anonymous_entries": "Ανώνυμες καταχωρήσεις", "average": "Μέσος όρος", + "captchaofflinewarning": "Η ανατροφοδότηση με την χρήση captcha δεν μπορεί να ολοκληρωθεί εάν δεν έχει διαμορφωθεί, εάν βρίσκεστε εκτός λειτουργίας ή με ο server δεν λειτουργεί.", "complete_the_form": "Απαντήστε τις ερωτήσεις...", "completed_feedbacks": "Απαντήσεις που έχουν υποβληθεί", "continue_the_form": "Συνεχίστε τη φόρμα", "feedback_is_not_open": "Το σχόλιο δεν είναι ανοιχτό", + "feedback_submitted_offline": "Αυτή η ανατροφοδότηση έχει αποθηκευτεί για να υποβληθεί αργότερα.", "feedbackclose": "Κλείσε το σχόλιο στις", "feedbackopen": "Άνοιξε το σχόλιο στις", "mapcourses": "Αντιστοίχηση σχόλιου σε μαθήματα", diff --git a/www/addons/mod/feedback/lang/es-mx.json b/www/addons/mod/feedback/lang/es-mx.json index 6c9cfa558f6..48c0b709868 100644 --- a/www/addons/mod/feedback/lang/es-mx.json +++ b/www/addons/mod/feedback/lang/es-mx.json @@ -3,10 +3,10 @@ "anonymous": "Anónima", "anonymous_entries": "Respuestas anónimas ({{$a}})", "average": "Promedio", - "captchaofflinewarning": "La retroalimentación con captcha no puede ser completada si no está configurada, si está en modo fuera-de-línea o con el servidor tirado.", + "captchaofflinewarning": "La retroalimentación con captcha no puede ser completada fuera-de-línea, o si no está configurada, o con el servidor tirado.", "complete_the_form": "Responda a las preguntas...", "completed_feedbacks": "Respuestas enviadas", - "continue_the_form": "Continuar con el formato", + "continue_the_form": "Continuar contestando las preguntas...", "feedback_is_not_open": "La retroalimentación no está disponible", "feedback_submitted_offline": "Esta retroalimentación ha sido guardada para enviarse más tarde.", "feedbackclose": "Permitir respuestas a", diff --git a/www/addons/mod/feedback/lang/es.json b/www/addons/mod/feedback/lang/es.json index b0d70fa540b..d6fc51f295d 100644 --- a/www/addons/mod/feedback/lang/es.json +++ b/www/addons/mod/feedback/lang/es.json @@ -3,10 +3,12 @@ "anonymous": "Anónima", "anonymous_entries": "Respuestas anónimas", "average": "Promedio", + "captchaofflinewarning": "La retroalimentación con captcha no puede ser completada si no está configurada, si está en modo fuera-de-línea o con el servidor caído.", "complete_the_form": "Responda a las preguntas...", "completed_feedbacks": "Respuestas enviadas", "continue_the_form": "Continuar con el formulario", "feedback_is_not_open": "La encuesta no está disponible", + "feedback_submitted_offline": "Esta retroalimentación ha sido guardada para enviarse más tarde.", "feedbackclose": "Permitir respuestas a", "feedbackopen": "Permitir respuestas de", "mapcourses": "Asignar encuesta a cursos", diff --git a/www/addons/mod/feedback/lang/eu.json b/www/addons/mod/feedback/lang/eu.json index 1f74e6b554e..b0a1488eb4f 100644 --- a/www/addons/mod/feedback/lang/eu.json +++ b/www/addons/mod/feedback/lang/eu.json @@ -9,8 +9,8 @@ "continue_the_form": "Jarraitu formularioarekin", "feedback_is_not_open": "Inkesta ez dago zabalik", "feedback_submitted_offline": "Feedback hau beranduago bidaltzeko gorde da.", - "feedbackclose": "Noiz itxi inkesta", - "feedbackopen": "Noiz zabaldu inkesta", + "feedbackclose": "Noiz arte baimendu erantzunak", + "feedbackopen": "Noiztik baimendu erantzunak", "mapcourses": "Esleitu feedback-a ikastaroetarako", "mode": "Modua", "next_page": "Hurrengo orria", @@ -18,7 +18,7 @@ "non_anonymous_entries": "Sarrera anonimorik ez ({{$a}})", "non_respondents_students": "Erantzun ez duten ikasleak ({{$a}})", "not_selected": "Aukeratu gabea", - "not_started": "hasi gabea", + "not_started": "Hasi gabea", "numberoutofrange": "Tartetik kanpoko zenbakia", "overview": "Ikuspegi orokorra", "page_after_submit": "Osaketa-mezua", @@ -30,6 +30,6 @@ "save_entries": "Bidali zure erantzunak", "show_entries": "Erakutsi erantzunak", "show_nonrespondents": "Erakutsi erantzun gabeak", - "started": "hasita", + "started": "Hasita", "this_feedback_is_already_submitted": "Dagoeneko egina duzu jarduera hau." } \ No newline at end of file diff --git a/www/addons/mod/feedback/lang/fr.json b/www/addons/mod/feedback/lang/fr.json index e043077cb6a..032ec9ba573 100644 --- a/www/addons/mod/feedback/lang/fr.json +++ b/www/addons/mod/feedback/lang/fr.json @@ -3,10 +3,12 @@ "anonymous": "Anonyme", "anonymous_entries": "Réponses anonymes ({{$a}})", "average": "Moyenne", + "captchaofflinewarning": "Le feedback avec captcha ne peut pas être terminé hors ligne, ou s'il n'est pas configuré, ou si le serveur est arrêté.", "complete_the_form": "Répondre aux questions...", "completed_feedbacks": "Réponses envoyées", - "continue_the_form": "Continuer le formulaire", + "continue_the_form": "Continuer à répondre aux questions...", "feedback_is_not_open": "Le feedback n'est pas ouvert", + "feedback_submitted_offline": "Ce feedback a été enregistré pour être remis plus tard.", "feedbackclose": "Permettre les réponses jusqu'au", "feedbackopen": "Permettre les réponses dès le", "mapcourses": "Associer le feedback aux cours", diff --git a/www/addons/mod/feedback/lang/he.json b/www/addons/mod/feedback/lang/he.json index 52e5c8f67b8..d1cac22f250 100644 --- a/www/addons/mod/feedback/lang/he.json +++ b/www/addons/mod/feedback/lang/he.json @@ -1,7 +1,7 @@ { "analysis": "ניתוח", "anonymous": "אנונימי", - "anonymous_entries": "משובים אנונימיים", + "anonymous_entries": "משובים אנונימיים ({{$a}})", "average": "ממוצע", "complete_the_form": "מענה על השאלות...", "completed_feedbacks": "תשובות אשר הוגשו", diff --git a/www/addons/mod/feedback/lang/hu.json b/www/addons/mod/feedback/lang/hu.json index 4c096d23974..40c06756007 100644 --- a/www/addons/mod/feedback/lang/hu.json +++ b/www/addons/mod/feedback/lang/hu.json @@ -5,7 +5,7 @@ "average": "Átlag", "complete_the_form": "Válaszoljon a kérdésekre...", "completed_feedbacks": "Leadott válaszok", - "continue_the_form": "Űrlap folytatása", + "continue_the_form": "Kérdések megválaszolásának folytatása...", "feedback_is_not_open": "A visszajelzés nincs nyitva", "feedbackclose": "Válaszok engedélyezése a címzettnek", "feedbackopen": "Válaszok engedélyezése a feladótól", diff --git a/www/addons/mod/feedback/lang/ja.json b/www/addons/mod/feedback/lang/ja.json index 63503d3cc28..1fa5c5c7b9a 100644 --- a/www/addons/mod/feedback/lang/ja.json +++ b/www/addons/mod/feedback/lang/ja.json @@ -3,10 +3,12 @@ "anonymous": "匿名", "anonymous_entries": "匿名エントリ ({{$a}})", "average": "平均", + "captchaofflinewarning": "Capchaつきのフィードバックは、未設定の場合、オフラインモードの場合、サーバがダウンしている場合には完了できません。", "complete_the_form": "質問に回答する ...", "completed_feedbacks": "送信済み回答", - "continue_the_form": "フォームを続ける", + "continue_the_form": "質問への回答を続ける ...", "feedback_is_not_open": "フィードバックは利用できません。", + "feedback_submitted_offline": "このフィードバックを、あとで提出するために保存しました。", "feedbackclose": "フィードバック終了日時", "feedbackopen": "フィードバック開始日時", "mapcourses": "フィードバックをコースにマップする", diff --git a/www/addons/mod/feedback/lang/lt.json b/www/addons/mod/feedback/lang/lt.json index dbe395c1dd6..e08688c5507 100644 --- a/www/addons/mod/feedback/lang/lt.json +++ b/www/addons/mod/feedback/lang/lt.json @@ -5,7 +5,7 @@ "average": "Vidurkis", "complete_the_form": "Atsakyti klausimus...", "completed_feedbacks": "Pateikti atsakymai", - "continue_the_form": "Tęsti formą", + "continue_the_form": "Tęsti atsakymus į klausimus...", "feedback_is_not_open": "Atsiliepimas neatidarytas", "feedbackclose": "Uždaryti atsiliepimą", "feedbackopen": "Atidaryti atsiliepimą", diff --git a/www/addons/mod/feedback/lang/nl.json b/www/addons/mod/feedback/lang/nl.json index 92250c29608..46203a58213 100644 --- a/www/addons/mod/feedback/lang/nl.json +++ b/www/addons/mod/feedback/lang/nl.json @@ -3,10 +3,10 @@ "anonymous": "Anoniem", "anonymous_entries": "Anoniem ingevulde formulieren ({{$a}})", "average": "Gemiddelde", - "captchaofflinewarning": "Feedback met captcha kan niet voltooid worden als dat niet geconfigureerd is, in offline modus of wanneer de server onbereikbaar is.", + "captchaofflinewarning": "Feedback met captcha kan niet offline voltooid worden of wanneer dat niet geconfigureerd is of wanneer de server onbereikbaar is.", "complete_the_form": "Beantwoord de vragen...", "completed_feedbacks": "Ingevulde antwoorden", - "continue_the_form": "Ga verder met dit formulier", + "continue_the_form": "Ga verder met het beantwoorden van de vragen...", "feedback_is_not_open": "De feedback is niet open", "feedback_submitted_offline": "Deze feedback is bewaard om later in te sturen.", "feedbackclose": "Antwoorden toestaan tot", diff --git a/www/addons/mod/feedback/lang/pt-br.json b/www/addons/mod/feedback/lang/pt-br.json index 98fb2ece613..bc007fed595 100644 --- a/www/addons/mod/feedback/lang/pt-br.json +++ b/www/addons/mod/feedback/lang/pt-br.json @@ -1,7 +1,7 @@ { "analysis": "Análise", "anonymous": "Anônimo", - "anonymous_entries": "Entradas anônimas", + "anonymous_entries": "Entradas anônimas ({{$a}})", "average": "Média", "complete_the_form": "Responda as questões...", "completed_feedbacks": "Respostas submetidas", @@ -13,10 +13,11 @@ "mode": "Modo", "next_page": "Próxima página", "non_anonymous": "O nome do usuário será registrado e mostrado com as respostas", - "non_anonymous_entries": "entradas não anônimas", - "non_respondents_students": "estudantes não respondentes", + "non_anonymous_entries": "Entradas não anônimas ({{$a}})", + "non_respondents_students": "Estudantes não respondentes ({{$a}})", "not_selected": "Não selecionado", "not_started": "não iniciado", + "numberoutofrange": "Valor fora do intervalo", "overview": "Visão geral", "page_after_submit": "Mensagem de conclusão", "preview": "Previsão", diff --git a/www/addons/mod/feedback/lang/pt.json b/www/addons/mod/feedback/lang/pt.json index a6ba4bcbd66..23aced64222 100644 --- a/www/addons/mod/feedback/lang/pt.json +++ b/www/addons/mod/feedback/lang/pt.json @@ -6,7 +6,7 @@ "captchaofflinewarning": "Inquérito com captcha não pode ser concluído se não estiver configurado, nem em modo offline ou com o servidor em baixo.", "complete_the_form": "Responder às questões...", "completed_feedbacks": "Respostas submetidas", - "continue_the_form": "Continuar o inquérito", + "continue_the_form": "Continuar a responder às perguntas...", "feedback_is_not_open": "O inquérito não está aberto", "feedback_submitted_offline": "O Inquérito foi gravado para ser enviado mais tarde.", "feedbackclose": "Permitir respostas até", @@ -30,6 +30,6 @@ "save_entries": "Submeter respostas", "show_entries": "Respostas", "show_nonrespondents": "Utilizadores que não responderam", - "started": "iniciado", + "started": "Iniciado", "this_feedback_is_already_submitted": "Já completou esta atividade" } \ No newline at end of file diff --git a/www/addons/mod/feedback/lang/sr-cr.json b/www/addons/mod/feedback/lang/sr-cr.json new file mode 100644 index 00000000000..a1cdc9bcc78 --- /dev/null +++ b/www/addons/mod/feedback/lang/sr-cr.json @@ -0,0 +1,35 @@ +{ + "analysis": "Анализа", + "anonymous": "Анонимни упитник", + "anonymous_entries": "Анонимни одговори ({{$a}})", + "average": "Просечно", + "captchaofflinewarning": "Упитник са Captcha елементом не може да буде завршен ако није конфигурисан, ако сте у офлајн режиму или ако је сервер искључен.", + "complete_the_form": "Одговори на питања...", + "completed_feedbacks": "Анализа одговорa", + "continue_the_form": "Настави са одговарањем на питања...", + "feedback_is_not_open": "Упитник није отворен", + "feedback_submitted_offline": "Овај упитник је сачуван како би касније био предат.", + "feedbackclose": "Упитник доступан до", + "feedbackopen": "Упитник доступан од", + "mapcourses": "Повежи упитник са курсевима", + "mode": "Врста упитника", + "next_page": "Следећа страница", + "non_anonymous": "Име корисника биће записано и приказано заједно са одговорима", + "non_anonymous_entries": "Неанонимни одговори ({{$a}})", + "non_respondents_students": "Полазници који нису одговорили на упитник ({{$a}})", + "not_selected": "Није изабрано", + "not_started": "Није започето", + "numberoutofrange": "Број изван опсега", + "overview": "Преглед", + "page_after_submit": "Порука која ће бити приказана кориснику након што попуни упитник", + "preview": "Преглед", + "previous_page": "Претходна страница", + "questions": "Питања", + "response_nr": "Одговор бр.", + "responses": "Одговори", + "save_entries": "Пошаљи своје одговоре", + "show_entries": "Прикажи одговоре", + "show_nonrespondents": "Прикажи кориснике које нису одговорили на упитник", + "started": "Започето", + "this_feedback_is_already_submitted": "Већ сте попунили овај упитник." +} \ No newline at end of file diff --git a/www/addons/mod/feedback/lang/sr-lt.json b/www/addons/mod/feedback/lang/sr-lt.json new file mode 100644 index 00000000000..8f2198ecfcc --- /dev/null +++ b/www/addons/mod/feedback/lang/sr-lt.json @@ -0,0 +1,35 @@ +{ + "analysis": "Analiza", + "anonymous": "Anonimni upitnik", + "anonymous_entries": "Anonimni odgovori ({{$a}})", + "average": "Prosečno", + "captchaofflinewarning": "Upitnik sa Captcha elementom ne može da bude završen ako nije konfigurisan, ako ste u oflajn režimu ili ako je server isključen.", + "complete_the_form": "Odgovori na pitanja...", + "completed_feedbacks": "Analiza odgovora", + "continue_the_form": "Nastavi sa odgovaranjem na pitanja...", + "feedback_is_not_open": "Upitnik nije otvoren", + "feedback_submitted_offline": "Ovaj upitnik je sačuvan kako bi kasnije bio predat.", + "feedbackclose": "Upitnik dostupan do", + "feedbackopen": "Upitnik dostupan od", + "mapcourses": "Poveži upitnik sa kursevima", + "mode": "Vrsta upitnika", + "next_page": "Sledeća stranica", + "non_anonymous": "Ime korisnika biće zapisano i prikazano zajedno sa odgovorima", + "non_anonymous_entries": "Neanonimni odgovori ({{$a}})", + "non_respondents_students": "Polaznici koji nisu odgovorili na upitnik ({{$a}})", + "not_selected": "Nije izabrano", + "not_started": "Nije započeto", + "numberoutofrange": "Broj izvan opsega", + "overview": "Pregled", + "page_after_submit": "Poruka koja će biti prikazana korisniku nakon što popuni upitnik", + "preview": "Pregled", + "previous_page": "Prethodna stranica", + "questions": "Pitanja", + "response_nr": "Odgovor br.", + "responses": "Odgovori", + "save_entries": "Pošalji svoje odgovore", + "show_entries": "Prikaži odgovore", + "show_nonrespondents": "Prikaži korisnike koje nisu odgovorili na upitnik", + "started": "Započeto", + "this_feedback_is_already_submitted": "Već ste popunili ovaj upitnik." +} \ No newline at end of file diff --git a/www/addons/mod/feedback/lang/sv.json b/www/addons/mod/feedback/lang/sv.json index c749faa8094..b2b4102df5d 100644 --- a/www/addons/mod/feedback/lang/sv.json +++ b/www/addons/mod/feedback/lang/sv.json @@ -16,7 +16,7 @@ "non_anonymous_entries": "Inga anonyma bidrag", "non_respondents_students": "Studenter/elever/deltagare/lärande som inte har lämnat några svar", "not_selected": "Inte vald", - "not_started": "inte påbörjad", + "not_started": "Inte påbörjad", "overview": "Översikt", "page_after_submit": "Sida efter inskickning", "preview": "Förhandsgranska", diff --git a/www/addons/mod/feedback/lang/tr.json b/www/addons/mod/feedback/lang/tr.json index b1c57c37b04..e4720de3ad0 100644 --- a/www/addons/mod/feedback/lang/tr.json +++ b/www/addons/mod/feedback/lang/tr.json @@ -1,14 +1,14 @@ { "analysis": "Analiz", "anonymous": "Anonim", - "anonymous_entries": "Anonim kayıtlar", + "anonymous_entries": "Anonim kayıtlar ({{$a}})", "average": "Ortalama", "complete_the_form": "Soruları cevaplayın...", "completed_feedbacks": "Gönderilen cevaplar", - "continue_the_form": "Devam et", + "continue_the_form": "Soruları cevaplamaya devam et...", "feedback_is_not_open": "Geribildirim açık değil", - "feedbackclose": "Geribildirimi kapat", - "feedbackopen": "Geribildirimi aç", + "feedbackclose": "Şuna yazılan cevaplara izin ver:", + "feedbackopen": "Şunlardan gelen cevaplara izin ver:", "mapcourses": "Geribildirimi derslere eşleştirin", "mode": "Mod", "next_page": "Sonraki sayfa", @@ -19,11 +19,11 @@ "not_started": "Başlatılmadı", "numberoutofrange": "Aralık dışı numara", "overview": "Gözat", - "page_after_submit": "Geribildirim doldurulduktan sonraki sayfa", + "page_after_submit": "Tamamlama bildirimi", "preview": "Önizleme", "previous_page": "Önceki sayfa", "questions": "Sorular", - "response_nr": "Yanıt No.", + "response_nr": "Yanıt numarası", "responses": "Yanıtlar", "save_entries": "Cevaplarınızı gönderin", "show_entries": "Yanıtları göster", diff --git a/www/addons/mod/feedback/services/handlers.js b/www/addons/mod/feedback/services/handlers.js index 48661bcd919..04b5f6d2613 100644 --- a/www/addons/mod/feedback/services/handlers.js +++ b/www/addons/mod/feedback/services/handlers.js @@ -22,7 +22,7 @@ angular.module('mm.addons.mod_feedback') * @name $mmaModFeedbackHandlers */ .factory('$mmaModFeedbackHandlers', function($mmCourse, $mmaModFeedback, $state, $mmContentLinksHelper, $mmUtil, $mmEvents, $mmSite, - mmaModFeedbackComponent, $mmaModFeedbackPrefetchHandler, mmCoreDownloading, mmCoreNotDownloaded, $mmaModFeedbackSync, + mmaModFeedbackComponent, $mmaModFeedbackPrefetchHandler, mmCoreDownloading, mmCoreNotDownloaded, $mmaModFeedbackSync, $q, mmCoreEventPackageStatusChanged, mmCoreOutdated, $mmCoursePrefetchDelegate, $mmContentLinkHandlerFactory) { var self = {}; @@ -102,9 +102,10 @@ angular.module('mm.addons.mod_feedback') // We need to call getDownloadSize, the package might have been updated. $mmaModFeedbackPrefetchHandler.getDownloadSize(module, courseId).then(function(size) { $mmUtil.confirmDownloadSize(size).then(function() { - $mmaModFeedbackPrefetchHandler.prefetch(module, courseId).catch(function() { + return $mmaModFeedbackPrefetchHandler.prefetch(module, courseId).catch(function(error) { if (!$scope.$$destroyed) { - $mmUtil.showErrorModal('mm.core.errordownloading', true); + $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true); + return $q.reject(); } }); }).catch(function() { diff --git a/www/addons/mod/folder/lang/da.json b/www/addons/mod/folder/lang/da.json index c53b3a994ed..2337bed4841 100644 --- a/www/addons/mod/folder/lang/da.json +++ b/www/addons/mod/folder/lang/da.json @@ -1,4 +1,4 @@ { - "emptyfilelist": "Der er ingen filer at vise", + "emptyfilelist": "Der er ingen filer at vise.", "errorwhilegettingfolder": "Fejl ved hentning af mappedata." } \ No newline at end of file diff --git a/www/addons/mod/folder/lang/es_mx.json b/www/addons/mod/folder/lang/es_mx.json deleted file mode 100644 index 3a342984727..00000000000 --- a/www/addons/mod/folder/lang/es_mx.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "emptyfilelist": "No hay archivos que mostrar" -} \ No newline at end of file diff --git a/www/addons/mod/folder/lang/he.json b/www/addons/mod/folder/lang/he.json index 1c2ec27977b..55811600621 100644 --- a/www/addons/mod/folder/lang/he.json +++ b/www/addons/mod/folder/lang/he.json @@ -1,3 +1,3 @@ { - "emptyfilelist": "אין קבצים להציג" + "emptyfilelist": "אין קבצים להציג." } \ No newline at end of file diff --git a/www/addons/mod/folder/lang/ja.json b/www/addons/mod/folder/lang/ja.json index 39c4d9fcfbd..61980e500fc 100644 --- a/www/addons/mod/folder/lang/ja.json +++ b/www/addons/mod/folder/lang/ja.json @@ -1,3 +1,4 @@ { - "emptyfilelist": "表示するファイルはありません。" + "emptyfilelist": "表示するファイルがありません。", + "errorwhilegettingfolder": "フォルダのデータを取得中にエラーが発生しました。" } \ No newline at end of file diff --git a/www/addons/mod/folder/lang/pt_br.json b/www/addons/mod/folder/lang/pt_br.json deleted file mode 100644 index 0821fd73ad7..00000000000 --- a/www/addons/mod/folder/lang/pt_br.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "emptyfilelist": "Não há arquivos para exibir" -} \ No newline at end of file diff --git a/www/addons/mod/folder/lang/ro.json b/www/addons/mod/folder/lang/ro.json index a66c107ebcd..0277b91b35f 100644 --- a/www/addons/mod/folder/lang/ro.json +++ b/www/addons/mod/folder/lang/ro.json @@ -1,4 +1,4 @@ { - "emptyfilelist": "Nu sunt fișiere disponibile pentru vizualizare.", + "emptyfilelist": "Nu există fișiere", "errorwhilegettingfolder": "A apărut o eroare la obținerea dosarului cu datele cerute." } \ No newline at end of file diff --git a/www/addons/mod/folder/lang/sr-cr.json b/www/addons/mod/folder/lang/sr-cr.json new file mode 100644 index 00000000000..a65fb8697c7 --- /dev/null +++ b/www/addons/mod/folder/lang/sr-cr.json @@ -0,0 +1,4 @@ +{ + "emptyfilelist": "Нема датотека за приказ.", + "errorwhilegettingfolder": "Грешка приликом преузимања података за 'Директоријум'" +} \ No newline at end of file diff --git a/www/addons/mod/folder/lang/sr-lt.json b/www/addons/mod/folder/lang/sr-lt.json new file mode 100644 index 00000000000..9bfdf403335 --- /dev/null +++ b/www/addons/mod/folder/lang/sr-lt.json @@ -0,0 +1,4 @@ +{ + "emptyfilelist": "Nema datoteka za prikaz.", + "errorwhilegettingfolder": "Greška prilikom preuzimanja podataka za 'Direktorijum'" +} \ No newline at end of file diff --git a/www/addons/mod/folder/lang/uk.json b/www/addons/mod/folder/lang/uk.json index 28ec6cd8e8a..1357444e2a4 100644 --- a/www/addons/mod/folder/lang/uk.json +++ b/www/addons/mod/folder/lang/uk.json @@ -1,4 +1,4 @@ { - "emptyfilelist": "Немає файдів для показу", + "emptyfilelist": "Немає файлів для показу", "errorwhilegettingfolder": "Помилка отримання інформації про папку" } \ No newline at end of file diff --git a/www/addons/mod/folder/lang/zh_cn.json b/www/addons/mod/folder/lang/zh_cn.json deleted file mode 100644 index edc8a70a528..00000000000 --- a/www/addons/mod/folder/lang/zh_cn.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "emptyfilelist": "没有可显示的文件" -} \ No newline at end of file diff --git a/www/addons/mod/folder/lang/zh_tw.json b/www/addons/mod/folder/lang/zh_tw.json deleted file mode 100644 index c53d23b870f..00000000000 --- a/www/addons/mod/folder/lang/zh_tw.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "emptyfilelist": "沒有可以顯示的檔案" -} \ No newline at end of file diff --git a/www/addons/mod/forum/lang/ca.json b/www/addons/mod/forum/lang/ca.json index 5f1be9cd58c..42bf0d4d3d0 100644 --- a/www/addons/mod/forum/lang/ca.json +++ b/www/addons/mod/forum/lang/ca.json @@ -5,6 +5,7 @@ "cannotcreatediscussion": "No s'ha pogut obrir un debat nou", "couldnotadd": "Un error desconegut ha impedit afegir el vostre missatge", "discussion": "Debat", + "discussionlocked": "Aquest fil de debat ha finalitzat, així que no admet respostes.", "discussionpinned": "Fixat", "discussionsubscription": "Subscripció als debats", "edit": "Edita", diff --git a/www/addons/mod/forum/lang/da.json b/www/addons/mod/forum/lang/da.json index 38dca8ad7f1..bdbd7c0a872 100644 --- a/www/addons/mod/forum/lang/da.json +++ b/www/addons/mod/forum/lang/da.json @@ -9,7 +9,7 @@ "discussionsubscription": "Abonnement på tråd", "edit": "Rediger", "erroremptymessage": "Indlægget kan ikke være tomt.", - "erroremptysubject": "Indlæggets emne kan ikke være tomt.", + "erroremptysubject": "Emnefeltet kan ikke være tomt", "errorgetforum": "Fejl ved hentning af forumdata.", "errorgetgroups": "Fejl ved hentning af gruppeindstillinger.", "forumnodiscussionsyet": "Der er endnu ingen indlæg i dette forum.", diff --git a/www/addons/mod/forum/lang/es-mx.json b/www/addons/mod/forum/lang/es-mx.json index c3743416512..48404906707 100644 --- a/www/addons/mod/forum/lang/es-mx.json +++ b/www/addons/mod/forum/lang/es-mx.json @@ -10,7 +10,7 @@ "discussionsubscription": "Suscripción a discusión", "edit": "Editar", "erroremptymessage": "El mensaje no puede estar vacío", - "erroremptysubject": "El asunto de la publicación no puede estar vacío", + "erroremptysubject": "El asunto del mensaje no puede estar vacío.", "errorgetforum": "Error al obtener datos del foro.", "errorgetgroups": "Error al obtener configuraciones de grupo.", "forumnodiscussionsyet": "Todavía no hay tópicos de discusión en este foro.", diff --git a/www/addons/mod/forum/lang/es_mx.json b/www/addons/mod/forum/lang/es_mx.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/www/addons/mod/forum/lang/es_mx.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/www/addons/mod/forum/lang/he.json b/www/addons/mod/forum/lang/he.json index 665cc87e1b4..21f3b132b0c 100644 --- a/www/addons/mod/forum/lang/he.json +++ b/www/addons/mod/forum/lang/he.json @@ -5,11 +5,12 @@ "cannotcreatediscussion": "כשלון ביצירת דיון חדש.", "couldnotadd": "ההודעה שלך לא פורסמה עקב תקלה בלתי מזוהה", "discussion": "דיון", + "discussionlocked": "הדיון ננעל, כך שלא ניתן יותר להגיב אליו.", "discussionpinned": "בראש הרשימה", "discussionsubscription": "מנוי לעדכונים בדיון", "edit": "עריכה", "erroremptymessage": "הודעת הפרסום איננה יכולה להיות ריקה", - "erroremptysubject": "הנושא הפרסום אינו יכול להיות ריק", + "erroremptysubject": "נושא ההודעה אינו יכול להיות ריק", "errorgetforum": "שגיאה בטעינת מידע הפורום.", "errorgetgroups": "שגיאה בטעינת הגדרות קבוצה.", "forumnodiscussionsyet": "עדיין לא קיימים נושאי דיונים בפורום זה.", diff --git a/www/addons/mod/forum/lang/ja.json b/www/addons/mod/forum/lang/ja.json index c6861af9156..df4dba7bc16 100644 --- a/www/addons/mod/forum/lang/ja.json +++ b/www/addons/mod/forum/lang/ja.json @@ -3,22 +3,28 @@ "cannotadddiscussion": "このフォーラムにディスカッションを追加するにはグループのメンバーである必要があります。", "cannotadddiscussionall": "あなたにはすべての参加者のための新しいディスカッショントピックを追加するパーミッションがありません。", "cannotcreatediscussion": "新しいディスカッションを作成できませんでした。", - "couldnotadd": "不明なエラーのため、あなたの投稿を追加できませんでした。", + "couldnotadd": "不明なエラーのためあなたの投稿を追加できませんでした。", "discussion": "ディスカッション", "discussionlocked": "このディスカッションはロックされているため、あなたは返信することはできません。", "discussionpinned": "ピン留め", "discussionsubscription": "ディスカッション購読", "edit": "編集", "erroremptymessage": "投稿メッセージを空にすることはできません。", - "erroremptysubject": "投稿件名を空にすることはできません。", + "erroremptysubject": "投稿の件名は必須です", + "errorgetforum": "フォーラムのデータ取得中にエラーが発生しました。", + "errorgetgroups": "グループ設定の取得中にエラーが発生しました。", "forumnodiscussionsyet": "このフォーラムにはまだディスカッショントピックがありません", "group": "グループ", "message": "メッセージ", "modeflatnewestfirst": "返信を新しいものからフラット表示する", "modeflatoldestfirst": "返信を古いものからフラット表示する", "modenested": "返信をネスト表示する", + "numdiscussions": "ディスカッション数 {{numdiscussions}}", + "numreplies": "返信数 {{numreplies}}", "posttoforum": "フォーラムに投稿する", "re": "Re:", + "refreshdiscussions": "ディスカッションをリフレッシュ", + "refreshposts": "ディスカッション投稿をリフレッシュ", "reply": "返信", "subject": "件名", "unread": "未読", diff --git a/www/addons/mod/forum/lang/lt.json b/www/addons/mod/forum/lang/lt.json index 82a99a7e4f4..93f37fba562 100644 --- a/www/addons/mod/forum/lang/lt.json +++ b/www/addons/mod/forum/lang/lt.json @@ -10,7 +10,7 @@ "discussionsubscription": "Diskusijos prenumerata", "edit": "Redaguoti", "erroremptymessage": "Skelbimo žinutė negali būti tuščia", - "erroremptysubject": "Pranešimo temos langelis negali būti tuščias", + "erroremptysubject": "Skelbimo tema negali būti tuščia.", "errorgetforum": "Klaida gaunant forumo duomenis.", "errorgetgroups": "Klaida gaunant grupės nustatymus.", "forumnodiscussionsyet": "Pokalbio temų forume dar nėra.", diff --git a/www/addons/mod/forum/lang/pl.json b/www/addons/mod/forum/lang/pl.json index 67a495dd1a6..0f761c4b8ec 100644 --- a/www/addons/mod/forum/lang/pl.json +++ b/www/addons/mod/forum/lang/pl.json @@ -7,7 +7,7 @@ "discussion": "Temat", "discussionlocked": "Dyskusja została zablokowana, więc nie możesz już odpowiedzieć.", "discussionpinned": "Przypięta", - "discussionsubscription": "Subskrypcja dyskusja", + "discussionsubscription": "Subskrypcja dyskusji", "edit": "Edycja", "erroremptymessage": "Wiadomość nie może być pusta", "erroremptysubject": "Tytuł wpisu nie może być pusty.", diff --git a/www/addons/mod/forum/lang/pt-br.json b/www/addons/mod/forum/lang/pt-br.json index f7d9cf730e2..a4df46a5972 100644 --- a/www/addons/mod/forum/lang/pt-br.json +++ b/www/addons/mod/forum/lang/pt-br.json @@ -5,10 +5,12 @@ "cannotcreatediscussion": "Não foi possível criar uma nova discussão", "couldnotadd": "Não foi possível publicar a sua mensagem. Infelizmente a causa do erro não foi identificada.", "discussion": "Tópico", + "discussionlocked": "Esta discussão foi bloqueada e já não é possível responder a ela.", + "discussionpinned": "Destacado", "discussionsubscription": "Assinatura de discussão", "edit": "Editar", "erroremptymessage": "A mensagem não pode ser vazia.", - "erroremptysubject": "Assunto não pode estar vazio", + "erroremptysubject": "O assunto da mensagem não pode ser vazio.", "errorgetforum": "Erro ao buscar dados de fórum.", "errorgetgroups": "Erro ao obter configurações do grupo.", "forumnodiscussionsyet": "Não existem tópicos neste fórum ainda", diff --git a/www/addons/mod/forum/lang/pt_br.json b/www/addons/mod/forum/lang/pt_br.json deleted file mode 100644 index 9f3e79857ff..00000000000 --- a/www/addons/mod/forum/lang/pt_br.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "forumnodiscussionsyet": "Não existem tópicos neste fórum ainda" -} \ No newline at end of file diff --git a/www/addons/mod/forum/lang/ro.json b/www/addons/mod/forum/lang/ro.json index 99d4fc77c16..2dd31a2be41 100644 --- a/www/addons/mod/forum/lang/ro.json +++ b/www/addons/mod/forum/lang/ro.json @@ -7,7 +7,7 @@ "discussion": "Discuție", "edit": "Modifică", "erroremptymessage": "Mesajul nu poate fi necompletat", - "erroremptysubject": "Subiectul nu poate rămâne necompletat", + "erroremptysubject": "Subiectul nu poate fi necompletat", "errorgetforum": "A apărut o eroare la obținerea datelor despre forum.", "errorgetgroups": "Eroare la obținerea setărilor pentru grup.", "forumnodiscussionsyet": "Nu există subiecte deschise în acest forum.", diff --git a/www/addons/mod/forum/lang/sr-cr.json b/www/addons/mod/forum/lang/sr-cr.json new file mode 100644 index 00000000000..0b8b9f761b2 --- /dev/null +++ b/www/addons/mod/forum/lang/sr-cr.json @@ -0,0 +1,32 @@ +{ + "addanewdiscussion": "Додај нову тему за дискусију", + "cannotadddiscussion": "Додавање дискусије у оквиру овог форума захтева групно чланство.", + "cannotadddiscussionall": "Немате дозволу да додајете нову тему за дискусију за све учеснике.", + "cannotcreatediscussion": "Није било могуће отворити нову дискусију", + "couldnotadd": "Нажалост, није могуће додати Вашу поруку због непознате грешке", + "discussion": "Дискусија", + "discussionlocked": "Ова дискусија је закључана тако да више не можете одговарати на њој.", + "discussionpinned": "Фиксирана", + "discussionsubscription": "Претплата на дискусију", + "edit": "Уреди", + "erroremptymessage": "Тело поруке не може бити празно", + "erroremptysubject": "Тема поруке не може бити празна", + "errorgetforum": "Грешка приликом преузимања података за 'Форум'", + "errorgetgroups": "Грешка приликом преузимања подешавања група.", + "forumnodiscussionsyet": "Још нема тема за дискусију на овом форуму.", + "group": "Група", + "message": "Порука", + "modeflatnewestfirst": "Приказ одговора, почевши прво с најновијим", + "modeflatoldestfirst": "Приказ одговора, почевши прво с најстаријим", + "modenested": "Приказ одговора у угнежђеној форми", + "numdiscussions": "{{numdiscussions}} дискусије/а", + "numreplies": "{{numreplies}} одговора", + "posttoforum": "Пошаљи поруку на форум", + "re": "Одговор:", + "refreshdiscussions": "Освежи дискусије", + "refreshposts": "Освежи постове", + "reply": "Одговори", + "subject": "Тема", + "unread": "Непрочитано", + "unreadpostsnumber": "Број непрочитаних порука: {{$a}}" +} \ No newline at end of file diff --git a/www/addons/mod/forum/lang/sr-lt.json b/www/addons/mod/forum/lang/sr-lt.json new file mode 100644 index 00000000000..c71aef2a6fc --- /dev/null +++ b/www/addons/mod/forum/lang/sr-lt.json @@ -0,0 +1,32 @@ +{ + "addanewdiscussion": "Dodaj novu temu za diskusiju", + "cannotadddiscussion": "Dodavanje diskusije u okviru ovog foruma zahteva grupno članstvo.", + "cannotadddiscussionall": "Nemate dozvolu da dodajete novu temu za diskusiju za sve učesnike.", + "cannotcreatediscussion": "Nije bilo moguće otvoriti novu diskusiju", + "couldnotadd": "Nažalost, nije moguće dodati Vašu poruku zbog nepoznate greške", + "discussion": "Diskusija", + "discussionlocked": "Ova diskusija je zaključana tako da više ne možete odgovarati na njoj.", + "discussionpinned": "Fiksirana", + "discussionsubscription": "Pretplata na diskusiju", + "edit": "Uredi", + "erroremptymessage": "Telo poruke ne može biti prazno", + "erroremptysubject": "Tema poruke ne može biti prazna", + "errorgetforum": "Greška prilikom preuzimanja podataka za 'Forum'", + "errorgetgroups": "Greška prilikom preuzimanja podešavanja grupa.", + "forumnodiscussionsyet": "Greška prilikom preuzimanja podešavanja grupa.", + "group": "Grupa", + "message": "Poruka", + "modeflatnewestfirst": "Prikaz odgovora, počevši prvo s najnovijim", + "modeflatoldestfirst": "Prikaz odgovora, počevši prvo s najstarijim", + "modenested": "Prikaz odgovora u ugnežđenoj formi", + "numdiscussions": "{{numdiscussions}} diskusije/a", + "numreplies": "{{numreplies}} odgovora", + "posttoforum": "Pošalji poruku na forum", + "re": "Odgovor:", + "refreshdiscussions": "Osveži diskusije", + "refreshposts": "Osveži postove", + "reply": "Odgovori", + "subject": "Tema", + "unread": "Nepročitano", + "unreadpostsnumber": "Broj nepročitanih poruka: {{$a}}" +} \ No newline at end of file diff --git a/www/addons/mod/forum/lang/sv.json b/www/addons/mod/forum/lang/sv.json index 676e5ba9fa1..41354d355f0 100644 --- a/www/addons/mod/forum/lang/sv.json +++ b/www/addons/mod/forum/lang/sv.json @@ -3,9 +3,11 @@ "cannotadddiscussion": "För att lägga till diskussionsämnen till det här forumet krävs det att man är medlem av en grupp.", "cannotadddiscussionall": "Du har inte tillstånd att lägga till ett nytt diskussionsämne för alla deltagare. ", "cannotcreatediscussion": "Det gick inte att skapa en ny diskussion", - "couldnotadd": "Det gick inte att lägga till Ditt inlägg på grund av okänt fel.", + "couldnotadd": "Det gick inte att lägga till ditt inlägg på grund av okänt fel.", "discussion": "Diskussionsämne", - "discussionsubscription": "Diskussions prenumeration", + "discussionlocked": "Denna diskussion är stängd och du kan inte längre göra inlägg i den.", + "discussionpinned": "Fastnålad", + "discussionsubscription": "Prenumeration på diskussion", "edit": "Redigera", "erroremptymessage": "Meddelandet i inlägget kan inte vara tomt", "erroremptysubject": "Rubriken kan inte vara tom", diff --git a/www/addons/mod/forum/lang/zh-tw.json b/www/addons/mod/forum/lang/zh-tw.json index a2d74d28770..6a91914a48c 100644 --- a/www/addons/mod/forum/lang/zh-tw.json +++ b/www/addons/mod/forum/lang/zh-tw.json @@ -10,7 +10,7 @@ "discussionsubscription": "議題訂閱", "edit": "編輯", "erroremptymessage": "貼文的訊息不能是空白", - "erroremptysubject": "貼文的標題不可以是空的", + "erroremptysubject": "貼文的主旨不能是空白", "errorgetforum": "讀取討論區資料發生錯誤", "errorgetgroups": "讀取群組設定發生錯誤", "forumnodiscussionsyet": "這個討論區還沒有討論主題", diff --git a/www/addons/mod/forum/lang/zh_cn.json b/www/addons/mod/forum/lang/zh_cn.json deleted file mode 100644 index 266cde0a80d..00000000000 --- a/www/addons/mod/forum/lang/zh_cn.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "forumnodiscussionsyet": "此论坛中还没有讨论话题" -} \ No newline at end of file diff --git a/www/addons/mod/forum/lang/zh_tw.json b/www/addons/mod/forum/lang/zh_tw.json deleted file mode 100644 index 21e18ea567e..00000000000 --- a/www/addons/mod/forum/lang/zh_tw.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "forumnodiscussionsyet": "這個討論區還沒有討論主題" -} \ No newline at end of file diff --git a/www/addons/mod/forum/services/handlers.js b/www/addons/mod/forum/services/handlers.js index dd5160f0a50..c8db7b531ac 100644 --- a/www/addons/mod/forum/services/handlers.js +++ b/www/addons/mod/forum/services/handlers.js @@ -21,7 +21,7 @@ angular.module('mm.addons.mod_forum') * @ngdoc service * @name $mmaModForumHandlers */ -.factory('$mmaModForumHandlers', function($mmCourse, $mmaModForum, $state, $mmUtil, $mmContentLinksHelper, $mmEvents, $mmSite, +.factory('$mmaModForumHandlers', function($mmCourse, $mmaModForum, $state, $mmUtil, $mmContentLinksHelper, $mmEvents, $mmSite, $q, $mmaModForumPrefetchHandler, $mmCoursePrefetchDelegate, mmCoreDownloading, mmCoreNotDownloaded, mmCoreOutdated, mmaModForumComponent, mmCoreEventPackageStatusChanged, $mmaModForumSync, $mmContentLinkHandlerFactory) { var self = {}; @@ -110,9 +110,10 @@ angular.module('mm.addons.mod_forum') // Get download size to ask for confirm if it's high. $mmaModForumPrefetchHandler.getDownloadSize(module, courseId).then(function(size) { $mmUtil.confirmDownloadSize(size).then(function() { - $mmaModForumPrefetchHandler.prefetch(module, courseId).catch(function() { + return $mmaModForumPrefetchHandler.prefetch(module, courseId).catch(function(error) { if (!$scope.$$destroyed) { - $mmUtil.showErrorModal('mm.core.errordownloading', true); + $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true); + return $q.reject(); } }); }).catch(function() { diff --git a/www/addons/mod/glossary/controllers/index.js b/www/addons/mod/glossary/controllers/index.js index 29913639991..168344cafcd 100644 --- a/www/addons/mod/glossary/controllers/index.js +++ b/www/addons/mod/glossary/controllers/index.js @@ -168,8 +168,10 @@ angular.module('mm.addons.mod_glossary') var promises = []; // Ignore search mode that is not set yet. if (fetchMode != 'search' || $scope.searchQuery) { - var args = angular.extend([], fetchArguments); - promises.push(fetchInvalidate.apply(this, args)); + if (fetchInvalidate) { + var args = angular.extend([], fetchArguments); + promises.push(fetchInvalidate.apply(this, args)); + } promises.push($mmaModGlossary.invalidateCourseGlossaries(courseId)); } if (glossary && glossary.id) { @@ -356,9 +358,9 @@ angular.module('mm.addons.mod_glossary') $scope.canLoadMore = (limitFrom + limitNum) < result.count; $scope.showNoEntries = ($scope.entries.length + $scope.offlineEntries.length) <= 0; - }).catch(function() { + }).catch(function(error) { if (append) { - $mmUtil.showErrorModal('mma.mod_glossary.errorloadingentries', true); + $mmUtil.showErrorModalDefault(error, 'mma.mod_glossary.errorloadingentries', true); } $scope.canLoadMore = false; // Set to false to prevent infinite calls with infinite-loading. return $q.reject(); diff --git a/www/addons/mod/glossary/lang/ar.json b/www/addons/mod/glossary/lang/ar.json index e92d720edeb..b52d6059283 100644 --- a/www/addons/mod/glossary/lang/ar.json +++ b/www/addons/mod/glossary/lang/ar.json @@ -1,10 +1,10 @@ { - "attachment": "مرفقات", + "attachment": "ملف مرفق", "browsemode": "النمط العرضي", "byauthor": "التجميع طبقا للمؤلف", "bynewestfirst": "الأحدث أولا", "byrecentlyupdated": "تم تحديثه مؤخرا", "bysearch": "بحث", - "casesensitive": "استخدم التعابير المعتادة", - "categories": "تصنيفات المقررات الدراسية" + "casesensitive": "مطابقة حالة الأحرف", + "categories": "التصنيفات" } \ No newline at end of file diff --git a/www/addons/mod/glossary/lang/bg.json b/www/addons/mod/glossary/lang/bg.json index dc6e44a0dcd..593e987ab1a 100644 --- a/www/addons/mod/glossary/lang/bg.json +++ b/www/addons/mod/glossary/lang/bg.json @@ -1,6 +1,6 @@ { - "attachment": "Прикрепване на значката към съобщението.", + "attachment": "Прикачен файл", "browsemode": "Режим на преглеждане", - "casesensitive": "Използване на регулярни изрази", - "categories": "Категории курсове" + "casesensitive": "Чувствителност главни/малки букви", + "categories": "Категории" } \ No newline at end of file diff --git a/www/addons/mod/glossary/lang/ca.json b/www/addons/mod/glossary/lang/ca.json index 191d2db0090..f5a0cfc5ded 100644 --- a/www/addons/mod/glossary/lang/ca.json +++ b/www/addons/mod/glossary/lang/ca.json @@ -1,5 +1,5 @@ { - "attachment": "Adjunt", + "attachment": "Adjunta la insígnia al missatge", "browsemode": "Navegueu per les entrades", "byalphabet": "Alfabèticament", "byauthor": "Agrupat per autor", @@ -8,8 +8,8 @@ "byrecentlyupdated": "Actualitzat recentment", "bysearch": "Cerca", "cannoteditentry": "No es pot editar l'entrada", - "casesensitive": "Utilitzeu expressions regulars", - "categories": "Categories de cursos", + "casesensitive": "Distingeix majúscules", + "categories": "Categories", "entriestobesynced": "Entrades per sincronitzar", "entrypendingapproval": "Aquesta entrada està pendent d'aprovació.", "errorloadingentries": "S'ha produït un error en carregar les entrades.", diff --git a/www/addons/mod/glossary/lang/cs.json b/www/addons/mod/glossary/lang/cs.json index 3421f566a83..9d81e677a27 100644 --- a/www/addons/mod/glossary/lang/cs.json +++ b/www/addons/mod/glossary/lang/cs.json @@ -1,5 +1,5 @@ { - "attachment": "Připojit odznak do zprávy", + "attachment": "Příloha", "browsemode": "Prohlížení příspěvků", "byalphabet": "Abecedně", "byauthor": "Skupina podle autora", @@ -8,8 +8,8 @@ "byrecentlyupdated": "Posledně aktualizované", "bysearch": "Hledat", "cannoteditentry": "Záznam nelze upravit", - "casesensitive": "Používat regulární výrazy", - "categories": "Kategorie kurzů", + "casesensitive": "Rozlišovat malá/VELKÁ", + "categories": "Kategorie", "entriestobesynced": "Příspěvky, které mají být synchronizovány", "entrypendingapproval": "Tato položka čeká na schválení", "errorloadingentries": "Při načítání položek došlo k chybě", diff --git a/www/addons/mod/glossary/lang/da.json b/www/addons/mod/glossary/lang/da.json index bd0f0d93d2e..2e7da2ee000 100644 --- a/www/addons/mod/glossary/lang/da.json +++ b/www/addons/mod/glossary/lang/da.json @@ -1,13 +1,13 @@ { - "attachment": "Tilføj badge til besked", - "browsemode": "Forhåndsvisning", + "attachment": "Bilag", + "browsemode": "Skim indlæg", "byalphabet": "Alfabetisk", "byauthor": "Grupper efter forfatter", "bynewestfirst": "Nyeste først", "byrecentlyupdated": "Senest opdateret", "bysearch": "Søg", - "casesensitive": "Brug regulære udtryk", - "categories": "Kursuskategorier", + "casesensitive": "Store og små bogstaver", + "categories": "Kategorier", "entrypendingapproval": "Dette opslag afventer godkendelse", "errorloadingentries": "Der opstod en fejl under indlæsning af opslag", "errorloadingentry": "Der opstod en fejl under indlæsning af opslaget", diff --git a/www/addons/mod/glossary/lang/de.json b/www/addons/mod/glossary/lang/de.json index 6b5589a0b0c..03bb7f1a602 100644 --- a/www/addons/mod/glossary/lang/de.json +++ b/www/addons/mod/glossary/lang/de.json @@ -1,5 +1,5 @@ { - "attachment": "Auszeichnung an Mitteilung anhängen", + "attachment": "Anhang", "browsemode": "Einträge durchblättern", "byalphabet": "Alphabetisch", "byauthor": "Nach Autor/in", @@ -8,8 +8,8 @@ "byrecentlyupdated": "Gerade aktualisiert", "bysearch": "Suchen", "cannoteditentry": "Eintrag nicht bearbeitbar", - "casesensitive": "Reguläre Ausdrücke verwenden", - "categories": "Kursbereiche", + "casesensitive": "Groß-/Kleinschreibung", + "categories": "Kategorien", "entriestobesynced": "Einträge zum Synchronisieren", "entrypendingapproval": "Dieser Eintrag wartet auf eine Freigabe.", "errorloadingentries": "Fehler beim Laden von Einträgen", diff --git a/www/addons/mod/glossary/lang/el.json b/www/addons/mod/glossary/lang/el.json index c79bed26793..6a40931cf03 100644 --- a/www/addons/mod/glossary/lang/el.json +++ b/www/addons/mod/glossary/lang/el.json @@ -1,13 +1,16 @@ { - "attachment": "Συνημμένα", + "attachment": "Επισυναπτόμενο", "browsemode": "Περιήγηση στις καταχωρήσεις", "byalphabet": "Αλφαβητικά", "byauthor": "Ομαδοποίηση ανά συγγραφέα", + "bycategory": "Ομαδοποίηση ανά κατηγορία", "bynewestfirst": "Νεότερα πρώτα", "byrecentlyupdated": "Ανανεώθηκαν πρόσφατα", "bysearch": "Αναζήτηση", - "casesensitive": "Χρήση κανονικών εκφράσεων", - "categories": "Κατηγορίες μαθημάτων", + "cannoteditentry": "Δεν είναι δυνατή η επεξεργασία της καταχώρισης", + "casesensitive": "Διάκριση μικρών/κεφαλαίων", + "categories": "Κατηγορίες", + "entriestobesynced": "Entries που πρέπει να συγχρονιστούν", "entrypendingapproval": "Εκκρεμεί η έγκριση για αυτή την καταχώρηση.", "errorloadingentries": "Παρουσιάστηκε σφάλμα κατά τη φόρτωση των καταχωρήσεων.", "errorloadingentry": "Παρουσιάστηκε σφάλμα κατά τη φόρτωση της καταχώρησης.", diff --git a/www/addons/mod/glossary/lang/es-mx.json b/www/addons/mod/glossary/lang/es-mx.json index 158ea571325..8cb29128da9 100644 --- a/www/addons/mod/glossary/lang/es-mx.json +++ b/www/addons/mod/glossary/lang/es-mx.json @@ -1,5 +1,5 @@ { - "attachment": "Adjunto", + "attachment": "Anexar insignia al mensaje", "browsemode": "Ver entradas", "byalphabet": "Alfabéticamente", "byauthor": "Agrupar por autor", @@ -8,7 +8,7 @@ "byrecentlyupdated": "Recientemente actualizado", "bysearch": "Buscar", "cannoteditentry": "No puede editarse entrada", - "casesensitive": "Usar expresiones regulares", + "casesensitive": "Diferencia entre MAYÚSCULAS y minúsculas", "categories": "Categorías", "entriestobesynced": "Entradas para ser sincronizadas", "entrypendingapproval": "Esta entrada está pendiente de aprobación.", diff --git a/www/addons/mod/glossary/lang/es.json b/www/addons/mod/glossary/lang/es.json index 02d8e633d5c..ba144c727bc 100644 --- a/www/addons/mod/glossary/lang/es.json +++ b/www/addons/mod/glossary/lang/es.json @@ -1,13 +1,16 @@ { - "attachment": "Adjunto", + "attachment": "Adjuntar insignia al mensaje", "browsemode": "Navegar por las entradas", "byalphabet": "Alfabéticamente", "byauthor": "Agrupado por autor", + "bycategory": "Agrupar por categoría", "bynewestfirst": "El más reciente primero", "byrecentlyupdated": "Actualizado recientemente", "bysearch": "Busca", - "casesensitive": "Usar expresiones regulares", + "cannoteditentry": "No se puede editar la entrada", + "casesensitive": "Diferencia entre mayúsculas y minúsculas", "categories": "Categorías", + "entriestobesynced": "Entradas pendientes de ser sincronizadas", "entrypendingapproval": "Esta entrada está pendiente de aprobación.", "errorloadingentries": "Ha ocurrido un error cargando las entradas.", "errorloadingentry": "Ha ocurrido un error cargando la entrada.", diff --git a/www/addons/mod/glossary/lang/eu.json b/www/addons/mod/glossary/lang/eu.json index c6ab2a7e186..5aa5b982604 100644 --- a/www/addons/mod/glossary/lang/eu.json +++ b/www/addons/mod/glossary/lang/eu.json @@ -1,5 +1,5 @@ { - "attachment": "Erantsi domina mezuari", + "attachment": "Eranskina", "browsemode": "Aztertu sarrerak", "byalphabet": "Alfabetikoki", "byauthor": "Taldekatu egilearen arabera", @@ -8,8 +8,8 @@ "byrecentlyupdated": "Duela gutxi eguneratuak", "bysearch": "Bilatu", "cannoteditentry": "Ezin da sarrera editatu", - "casesensitive": "Erabil adierazpen erregularrak", - "categories": "Ikastaro-kategoriak", + "casesensitive": "Letra larriak eta xeheak bereiziz", + "categories": "Kategoriak", "entriestobesynced": "Sinkronizatu beharreko sarrerak", "entrypendingapproval": "Sarrera hau onarpenaren zain dago.", "errorloadingentries": "Errorea gertatu da sarrerak kargatzean.", diff --git a/www/addons/mod/glossary/lang/fa.json b/www/addons/mod/glossary/lang/fa.json index 637de884db4..8b6788b82aa 100644 --- a/www/addons/mod/glossary/lang/fa.json +++ b/www/addons/mod/glossary/lang/fa.json @@ -1,6 +1,6 @@ { - "attachment": "فایل پیوست", + "attachment": "ضمیمه کردن مدال به پیام", "browsemode": "حالت پیش‌نمایش", - "casesensitive": "استفاده از عبارت‌های منظم", - "categories": "طبقه‌های درسی" + "casesensitive": "حساس بودن به بزرگ و کوچکی حروف", + "categories": "دسته‌ها" } \ No newline at end of file diff --git a/www/addons/mod/glossary/lang/fr.json b/www/addons/mod/glossary/lang/fr.json index 712afea4266..f72096c8b1b 100644 --- a/www/addons/mod/glossary/lang/fr.json +++ b/www/addons/mod/glossary/lang/fr.json @@ -1,5 +1,5 @@ { - "attachment": "Joindre le badge à un courriel", + "attachment": "Annexe", "browsemode": "Parcourir les articles", "byalphabet": "Alphabétiquement", "byauthor": "Grouper par auteur", @@ -8,8 +8,8 @@ "byrecentlyupdated": "Modifiés récemment", "bysearch": "Rechercher", "cannoteditentry": "Impossible de modifier l'article", - "casesensitive": "Utiliser les expressions régulières", - "categories": "Catégories de cours", + "casesensitive": "Casse des caractères", + "categories": "Catégories", "entriestobesynced": "Articles à synchroniser", "entrypendingapproval": "Cet article est en attente d'approbation", "errorloadingentries": "Une erreur est survenue lors du chargement des articles.", diff --git a/www/addons/mod/glossary/lang/he.json b/www/addons/mod/glossary/lang/he.json index abad848638c..e4d971b4c35 100644 --- a/www/addons/mod/glossary/lang/he.json +++ b/www/addons/mod/glossary/lang/he.json @@ -1,6 +1,6 @@ { - "attachment": "צירוף ההישג להודעה", + "attachment": "קובץ מצורף", "browsemode": "מצב תצוגה מקדימה", - "casesensitive": "השתמש בביטויים רגולריים", - "categories": "קטגוריות קורסים" + "casesensitive": "תלוי אותיות רישיות", + "categories": "קטגוריות חישוב ציונים" } \ No newline at end of file diff --git a/www/addons/mod/glossary/lang/hu.json b/www/addons/mod/glossary/lang/hu.json index acb16b009bd..c74a20c85ed 100644 --- a/www/addons/mod/glossary/lang/hu.json +++ b/www/addons/mod/glossary/lang/hu.json @@ -1,6 +1,6 @@ { - "attachment": "Csatolt állomány:", + "attachment": "Kitűző hozzákapcsolása az üzenethez", "browsemode": "Előzetes megtekintés üzemmódja", - "casesensitive": "Reguláris kifejezések használata", - "categories": "Kurzuskategóriák" + "casesensitive": "Kis-/nagybetű különböző", + "categories": "Kategóriák" } \ No newline at end of file diff --git a/www/addons/mod/glossary/lang/it.json b/www/addons/mod/glossary/lang/it.json index 581b16835e1..aa1cfe7fe09 100644 --- a/www/addons/mod/glossary/lang/it.json +++ b/www/addons/mod/glossary/lang/it.json @@ -1,10 +1,10 @@ { - "attachment": "Allega badge al messaggio", + "attachment": "Allegato", "browsemode": "Modalità anteprima", "byrecentlyupdated": "Aggiornati di recente", "bysearch": "Cerca", - "casesensitive": "Utilizza regular expression", - "categories": "Categorie di corso", + "casesensitive": "Rilevanza maiuscolo/minuscolo", + "categories": "Categorie", "entrypendingapproval": "Questa voce è in attesa di approvazione.", "errorloadingentries": "Si è verificato un errore durante il caricamento delle voci.", "errorloadingentry": "Si è verificato un errore durante il caricamento della voce.", diff --git a/www/addons/mod/glossary/lang/ja.json b/www/addons/mod/glossary/lang/ja.json index b518d805074..b68170abdd2 100644 --- a/www/addons/mod/glossary/lang/ja.json +++ b/www/addons/mod/glossary/lang/ja.json @@ -1,6 +1,20 @@ { - "attachment": "添付", - "browsemode": "プレビューモード", - "casesensitive": "正規表現を使用する", - "categories": "コースカテゴリ" + "attachment": "メッセージにバッジを添付する", + "browsemode": "エントリをブラウズ", + "byalphabet": "アルファベット順", + "byauthor": "著者でグループ", + "bycategory": "カテゴリでグループ", + "bynewestfirst": "新規順", + "byrecentlyupdated": "最近の更新", + "bysearch": "検索", + "cannoteditentry": "エントリの編集ができませんでした", + "casesensitive": "大文字小文字の区別", + "categories": "カテゴリ", + "entriestobesynced": "エントリの同期ができませんでした", + "entrypendingapproval": "このエントリは承認待ちです。", + "errorloadingentries": "エントリ読み込み中にエラーが発生しました。", + "errorloadingentry": "エントリ読み込み中にエラーが発生しました。", + "errorloadingglossary": "用語集を読み込み中にエラーが発生しました。", + "noentriesfound": "エントリが見つかりませんでした。", + "searchquery": "検索内容" } \ No newline at end of file diff --git a/www/addons/mod/glossary/lang/lt.json b/www/addons/mod/glossary/lang/lt.json index 18f6cc6763e..016538035b9 100644 --- a/www/addons/mod/glossary/lang/lt.json +++ b/www/addons/mod/glossary/lang/lt.json @@ -1,13 +1,13 @@ { - "attachment": "Prikabinti pasiekimą prie pranešimo", + "attachment": "Priedas", "browsemode": "Peržiūrėti įrašus", "byalphabet": "Abėcėlės tvarka", "byauthor": "Pagal autorių", "bynewestfirst": "Naujausi", "byrecentlyupdated": "Neseniai atnaujinti", "bysearch": "Paieška", - "casesensitive": "Naudoti reguliariąsias išraiškas", - "categories": "Kursų kategorijos", + "casesensitive": "Didžiųjų ir mažųjų raidžių skyrimas", + "categories": "Kategorijos", "entrypendingapproval": "Patvirtinti įrašą.", "errorloadingentries": "Klaida keliant įrašus.", "errorloadingentry": "Klaida įkeliant įrašą.", diff --git a/www/addons/mod/glossary/lang/nl.json b/www/addons/mod/glossary/lang/nl.json index 7c06a87db9a..5a53d5a1d7a 100644 --- a/www/addons/mod/glossary/lang/nl.json +++ b/www/addons/mod/glossary/lang/nl.json @@ -1,5 +1,5 @@ { - "attachment": "Badge als bijlage bij bericht", + "attachment": "Bijlage", "browsemode": "Blader door items", "byalphabet": "Alfabetisch", "byauthor": "Groepeer per auteur", @@ -8,8 +8,8 @@ "byrecentlyupdated": "Onlangs gewijzigd", "bysearch": "Zoek", "cannoteditentry": "Kan item niet bewerken", - "casesensitive": "Regular expressions gebruiken", - "categories": "Cursuscategorieën", + "casesensitive": "Gevoeligheid voor hoofd/kleine letters", + "categories": "Categorieën", "entriestobesynced": "Items niet gesynchroniseerd", "entrypendingapproval": "Dit item wacht op goedkeuring.", "errorloadingentries": "Fout bij het laden van de items.", diff --git a/www/addons/mod/glossary/lang/pl.json b/www/addons/mod/glossary/lang/pl.json index 7effb708160..dc3225deb6a 100644 --- a/www/addons/mod/glossary/lang/pl.json +++ b/www/addons/mod/glossary/lang/pl.json @@ -1,6 +1,6 @@ { - "attachment": "Dołącz odznakę do wiadomości", + "attachment": "Załącznik", "browsemode": "Tryb przeglądania", - "casesensitive": "Użyj wyrażeń regularnych", - "categories": "Kategorie kursów" + "casesensitive": "Uwzględnianie wielkości liter", + "categories": "Kategorie" } \ No newline at end of file diff --git a/www/addons/mod/glossary/lang/pt-br.json b/www/addons/mod/glossary/lang/pt-br.json index 7eeca932a54..57059a9b327 100644 --- a/www/addons/mod/glossary/lang/pt-br.json +++ b/www/addons/mod/glossary/lang/pt-br.json @@ -1,5 +1,5 @@ { - "attachment": "Anexar emblema à mensagem", + "attachment": "Anexo", "browsemode": "Navegar nas entradas", "byalphabet": "Alfabeticamente", "byauthor": "Agrupar por autor", @@ -8,8 +8,8 @@ "byrecentlyupdated": "Recentemente atualizados", "bysearch": "Pesquisa", "cannoteditentry": "Não é possível editar o item", - "casesensitive": "Usar expressões regulares", - "categories": "Categorias de Cursos", + "casesensitive": "Considerar diferenças entre maiúsculas e minúsculas", + "categories": "Categorias", "entriestobesynced": "Itens a serem sincronizados", "entrypendingapproval": "A entrada está pendente de aprovação.", "errorloadingentries": "Ocorreu um erro enquanto carregava entradas.", diff --git a/www/addons/mod/glossary/lang/pt.json b/www/addons/mod/glossary/lang/pt.json index 151febb1e95..6887c9ff44c 100644 --- a/www/addons/mod/glossary/lang/pt.json +++ b/www/addons/mod/glossary/lang/pt.json @@ -1,5 +1,5 @@ { - "attachment": "Anexar Medalha à mensagem", + "attachment": "Anexo", "browsemode": "Ver entradas", "byalphabet": "Alfabeticamente", "byauthor": "Agrupar por autor", @@ -8,8 +8,8 @@ "byrecentlyupdated": "Recentemente atualizados", "bysearch": "Pesquisar", "cannoteditentry": "Não é possível editar a entrada", - "casesensitive": "Usar regular expressions", - "categories": "Categorias de disciplinas", + "casesensitive": "Respeitar maiúsculas/minúsculas", + "categories": "Categorias", "entriestobesynced": "Entradas a ser sincronizadas", "entrypendingapproval": "Este termo aguarda aprovação.", "errorloadingentries": "Ocorreu um erro ao carregar os termos.", diff --git a/www/addons/mod/glossary/lang/ro.json b/www/addons/mod/glossary/lang/ro.json index 1711d27b159..697bdf70ba4 100644 --- a/www/addons/mod/glossary/lang/ro.json +++ b/www/addons/mod/glossary/lang/ro.json @@ -1,13 +1,13 @@ { - "attachment": "Atașament", - "browsemode": "Căutați în datele introduse", + "attachment": "Adaugă o etichetă mesajului", + "browsemode": "Mod Căutare", "byalphabet": "Alfabetic", "byauthor": "Grupare după autor", "bynewestfirst": "Cele mai noi sunt dispuse primele", "byrecentlyupdated": "Actualizări recente", "bysearch": "Căutare", - "casesensitive": "Foloseşte Regular Expressions", - "categories": "Categorii de cursuri", + "casesensitive": "Senzitivitate caractere", + "categories": "Categorii", "entrypendingapproval": "Această", "errorloadingentries": "A apărut o eroare la încărcarea intrărilor.", "errorloadingentry": "A apărut o eroare la încărcarea intrărilor.", diff --git a/www/addons/mod/glossary/lang/ru.json b/www/addons/mod/glossary/lang/ru.json index 05189841b97..487d64188b1 100644 --- a/www/addons/mod/glossary/lang/ru.json +++ b/www/addons/mod/glossary/lang/ru.json @@ -1,10 +1,10 @@ { - "attachment": "Вложение:", + "attachment": "Прикрепить значок к сообщению", "browsemode": "Режим предпросмотра", "byalphabet": "Алфавитно", "byauthor": "Группировать по автору", "bycategory": "Группировать по категориям", "bysearch": "Поиск", - "casesensitive": "Использовать регулярные выражения", - "categories": "Категории курсов" + "casesensitive": "Чувствительность ответа к регистру", + "categories": "Категории" } \ No newline at end of file diff --git a/www/addons/mod/glossary/lang/sr-cr.json b/www/addons/mod/glossary/lang/sr-cr.json new file mode 100644 index 00000000000..79d5aec0558 --- /dev/null +++ b/www/addons/mod/glossary/lang/sr-cr.json @@ -0,0 +1,20 @@ +{ + "attachment": "Прилог", + "browsemode": "Прегледај појмове", + "byalphabet": "Азбучним редом", + "byauthor": "Групиши по аутору", + "bycategory": "Групиши по категорији", + "bynewestfirst": "Најновији прво", + "byrecentlyupdated": "Недавно ажурирани", + "bysearch": "Претражи", + "cannoteditentry": "Не можете да уређујете појам", + "casesensitive": "Користи регуларне изразе", + "categories": "Категорије курсева", + "entriestobesynced": "Појмови за синхронизацију", + "entrypendingapproval": "Овај појам чека одобрење.", + "errorloadingentries": "Дошло је до грешке приликом учитавања појмова.", + "errorloadingentry": "Дошло је до грешке приликом учитавања појма.", + "errorloadingglossary": "Дошло је до грешке приликом учитавања речника.", + "noentriesfound": "Није пронађен ниједан појам.", + "searchquery": "Упит за претрагу" +} \ No newline at end of file diff --git a/www/addons/mod/glossary/lang/sr-lt.json b/www/addons/mod/glossary/lang/sr-lt.json new file mode 100644 index 00000000000..4edfb5a1f41 --- /dev/null +++ b/www/addons/mod/glossary/lang/sr-lt.json @@ -0,0 +1,20 @@ +{ + "attachment": "Prilog", + "browsemode": "Pregledaj pojmove", + "byalphabet": "Abecednim redom", + "byauthor": "Grupiši po autoru", + "bycategory": "Grupiši po kategoriji", + "bynewestfirst": "Najnoviji prvo", + "byrecentlyupdated": "Nedavno ažurirani", + "bysearch": "Pretraži", + "cannoteditentry": "Ne možete da uređujete pojam", + "casesensitive": "Koristi regularne izraze", + "categories": "Kategorije kurseva", + "entriestobesynced": "Pojmovi za sinhronizaciju", + "entrypendingapproval": "Ovaj pojam čeka odobrenje.", + "errorloadingentries": "Došlo je do greške prilikom učitavanja pojmova.", + "errorloadingentry": "Došlo je do greške prilikom učitavanja pojma.", + "errorloadingglossary": "Došlo je do greške prilikom učitavanja rečnika.", + "noentriesfound": "Nije pronađen nijedan pojam.", + "searchquery": "Upit za pretragu" +} \ No newline at end of file diff --git a/www/addons/mod/glossary/lang/sv.json b/www/addons/mod/glossary/lang/sv.json index f9dc8d60f6a..7fb8c3d2643 100644 --- a/www/addons/mod/glossary/lang/sv.json +++ b/www/addons/mod/glossary/lang/sv.json @@ -1,13 +1,13 @@ { - "attachment": "Bifoga märke med meddelande", + "attachment": "Bilaga", "browsemode": "Bläddrar bland poster", "byalphabet": "Alfabetiskt", "byauthor": "Sortera efter författare", "bynewestfirst": "Nyaste först", "byrecentlyupdated": "Nyligen uppdaterade", "bysearch": "Sök", - "casesensitive": "Använd standarduttryck", - "categories": "Kurskategorier", + "casesensitive": "Stor eller liten bokstav gör skillnad", + "categories": "Kategorier", "entrypendingapproval": "Detta inlägg väntar på godkännande", "errorloadingentries": "Ett fel uppstod vid inläsning av inläggen", "errorloadingentry": "Ett fel uppstod vid inläsning av inlägget", diff --git a/www/addons/mod/glossary/lang/tr.json b/www/addons/mod/glossary/lang/tr.json index ed836454608..6acccdba883 100644 --- a/www/addons/mod/glossary/lang/tr.json +++ b/www/addons/mod/glossary/lang/tr.json @@ -1,6 +1,6 @@ { - "attachment": "Rozete mesaj ekle", + "attachment": "Dosya", "browsemode": "Önizleme Modu", - "casesensitive": "Düzenli İfadeleri Kullan", - "categories": "Ders Kategorileri" + "casesensitive": "Harf duyarlılığı", + "categories": "Kategoriler" } \ No newline at end of file diff --git a/www/addons/mod/glossary/lang/uk.json b/www/addons/mod/glossary/lang/uk.json index 5452c0da423..fecbe90319d 100644 --- a/www/addons/mod/glossary/lang/uk.json +++ b/www/addons/mod/glossary/lang/uk.json @@ -1,15 +1,15 @@ { - "attachment": "Долучення", + "attachment": "Прикріпити відзнаку до повідомлення", "browsemode": "Перегляд записів", "byalphabet": "По алфавіту", "byauthor": "Групувати за автором", "bycategory": "Групувати за категорією", "bynewestfirst": "Новіші перші", - "byrecentlyupdated": "Недавно оновлені", + "byrecentlyupdated": "Нещодавно оновлені", "bysearch": "Пошук", - "cannoteditentry": "Неможливо задагувати запис", - "casesensitive": "Використовувати регулярні вирази", - "categories": "Категорії курсів", + "cannoteditentry": "Неможливо редагувати запис", + "casesensitive": "Чутливість відповіді до регістра", + "categories": "Категорії", "entriestobesynced": "Записи будуть синхронізовані", "entrypendingapproval": "Цей запис очікує схвалення.", "errorloadingentries": "Сталася помилка під час завантаження записів.", diff --git a/www/addons/mod/glossary/lang/zh-cn.json b/www/addons/mod/glossary/lang/zh-cn.json index 761fdac404e..3af5cbb310e 100644 --- a/www/addons/mod/glossary/lang/zh-cn.json +++ b/www/addons/mod/glossary/lang/zh-cn.json @@ -1,6 +1,6 @@ { - "attachment": "附件发送", + "attachment": "附件", "browsemode": "预览模式", - "casesensitive": "使用正则表达式", - "categories": "课程分类" + "casesensitive": "区分大小写字母", + "categories": "类别" } \ No newline at end of file diff --git a/www/addons/mod/glossary/lang/zh-tw.json b/www/addons/mod/glossary/lang/zh-tw.json index d89166a41e8..8c24d72719a 100644 --- a/www/addons/mod/glossary/lang/zh-tw.json +++ b/www/addons/mod/glossary/lang/zh-tw.json @@ -1,13 +1,13 @@ { - "attachment": "在訊息上附加上獎章", + "attachment": "附件", "browsemode": "瀏覽條目", "byalphabet": "按字母順序排列", "byauthor": "以作者為分群", "bynewestfirst": "最新的優先", "byrecentlyupdated": "最近的更新", "bysearch": "搜尋", - "casesensitive": "區分大小寫", - "categories": "課程類別", + "casesensitive": "區分字母的大小寫", + "categories": "類別", "entrypendingapproval": "這個項目已被暫緩核可", "errorloadingentries": "載入項目時發生錯誤", "errorloadingentry": "載入項目時發生錯誤", diff --git a/www/addons/mod/glossary/services/handlers.js b/www/addons/mod/glossary/services/handlers.js index 0cf6d199865..80834abf457 100644 --- a/www/addons/mod/glossary/services/handlers.js +++ b/www/addons/mod/glossary/services/handlers.js @@ -105,9 +105,10 @@ angular.module('mm.addons.mod_glossary') // Get download size to ask for confirm if it's high. $mmaModGlossaryPrefetchHandler.getDownloadSize(module, courseId).then(function(size) { $mmUtil.confirmDownloadSize(size).then(function() { - $mmaModGlossaryPrefetchHandler.prefetch(module, courseId).catch(function() { + return $mmaModGlossaryPrefetchHandler.prefetch(module, courseId).catch(function(error) { if (!$scope.$$destroyed) { - $mmUtil.showErrorModal('mm.core.errordownloading', true); + $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true); + return $q.reject(); } }); }).catch(function() { diff --git a/www/addons/mod/imscp/controllers/index.js b/www/addons/mod/imscp/controllers/index.js index 506860b14c5..41f6ebd7227 100644 --- a/www/addons/mod/imscp/controllers/index.js +++ b/www/addons/mod/imscp/controllers/index.js @@ -101,8 +101,8 @@ angular.module('mm.addons.mod_imscp') // We could load the main file but the download failed. Show error message. $mmUtil.showErrorModal('mm.core.errordownloadingsomefiles', true); } - }).catch(function() { - $mmUtil.showErrorModal('mma.mod_imscp.deploymenterror', true); + }).catch(function(error) { + $mmUtil.showErrorModalDefault(error, 'mma.mod_imscp.deploymenterror', true); return $q.reject(); }); }).finally(function() { diff --git a/www/addons/mod/imscp/lang/es_mx.json b/www/addons/mod/imscp/lang/es_mx.json deleted file mode 100644 index 175d34d526d..00000000000 --- a/www/addons/mod/imscp/lang/es_mx.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "deploymenterror": "¡Error en paquete de contenidos!" -} \ No newline at end of file diff --git a/www/addons/mod/imscp/lang/ja.json b/www/addons/mod/imscp/lang/ja.json index 66c407ae43e..5bd979018e4 100644 --- a/www/addons/mod/imscp/lang/ja.json +++ b/www/addons/mod/imscp/lang/ja.json @@ -1,3 +1,4 @@ { - "deploymenterror": "コンテンツパッケージエラー!" + "deploymenterror": "コンテンツパッケージエラー!", + "showmoduledescription": "説明の表示" } \ No newline at end of file diff --git a/www/addons/mod/imscp/lang/pt_br.json b/www/addons/mod/imscp/lang/pt_br.json deleted file mode 100644 index cb7e6aec6a1..00000000000 --- a/www/addons/mod/imscp/lang/pt_br.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "deploymenterror": "Erro no conte" -} \ No newline at end of file diff --git a/www/addons/mod/imscp/lang/sr-cr.json b/www/addons/mod/imscp/lang/sr-cr.json new file mode 100644 index 00000000000..939547b3b5f --- /dev/null +++ b/www/addons/mod/imscp/lang/sr-cr.json @@ -0,0 +1,3 @@ +{ + "showmoduledescription": "Прикажи опис" +} \ No newline at end of file diff --git a/www/addons/mod/imscp/lang/sr-lt.json b/www/addons/mod/imscp/lang/sr-lt.json new file mode 100644 index 00000000000..8519e32307b --- /dev/null +++ b/www/addons/mod/imscp/lang/sr-lt.json @@ -0,0 +1,3 @@ +{ + "showmoduledescription": "Prikaži opis" +} \ No newline at end of file diff --git a/www/addons/mod/imscp/lang/zh_cn.json b/www/addons/mod/imscp/lang/zh_cn.json deleted file mode 100644 index 29923d4664e..00000000000 --- a/www/addons/mod/imscp/lang/zh_cn.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "deploymenterror": "内容包有错!" -} \ No newline at end of file diff --git a/www/addons/mod/imscp/lang/zh_tw.json b/www/addons/mod/imscp/lang/zh_tw.json deleted file mode 100644 index f2f35ec5337..00000000000 --- a/www/addons/mod/imscp/lang/zh_tw.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "deploymenterror": "內容包有錯誤!" -} \ No newline at end of file diff --git a/www/addons/mod/label/lang/es_mx.json b/www/addons/mod/label/lang/es_mx.json deleted file mode 100644 index 129eb9e3838..00000000000 --- a/www/addons/mod/label/lang/es_mx.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Etiqueta" -} \ No newline at end of file diff --git a/www/addons/mod/label/lang/he.json b/www/addons/mod/label/lang/he.json index 232aff3b2bf..7f0814d0381 100644 --- a/www/addons/mod/label/lang/he.json +++ b/www/addons/mod/label/lang/he.json @@ -1,3 +1,3 @@ { - "label": "תווית לשאלה מותנית (באנגלית)" + "label": "תווית" } \ No newline at end of file diff --git a/www/addons/mod/label/lang/pt_br.json b/www/addons/mod/label/lang/pt_br.json deleted file mode 100644 index fdfc1ff9392..00000000000 --- a/www/addons/mod/label/lang/pt_br.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Rótulo" -} \ No newline at end of file diff --git a/www/addons/mod/label/lang/sr-cr.json b/www/addons/mod/label/lang/sr-cr.json new file mode 100644 index 00000000000..ee0697520d2 --- /dev/null +++ b/www/addons/mod/label/lang/sr-cr.json @@ -0,0 +1,3 @@ +{ + "label": "Натпис" +} \ No newline at end of file diff --git a/www/addons/mod/label/lang/sr-lt.json b/www/addons/mod/label/lang/sr-lt.json new file mode 100644 index 00000000000..c2a3f10a06e --- /dev/null +++ b/www/addons/mod/label/lang/sr-lt.json @@ -0,0 +1,3 @@ +{ + "label": "Natpis" +} \ No newline at end of file diff --git a/www/addons/mod/label/lang/zh_cn.json b/www/addons/mod/label/lang/zh_cn.json deleted file mode 100644 index 4bbc4110d7a..00000000000 --- a/www/addons/mod/label/lang/zh_cn.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "标签" -} \ No newline at end of file diff --git a/www/addons/mod/label/lang/zh_tw.json b/www/addons/mod/label/lang/zh_tw.json deleted file mode 100644 index c1a016fd047..00000000000 --- a/www/addons/mod/label/lang/zh_tw.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "標籤" -} \ No newline at end of file diff --git a/www/addons/mod/lesson/controllers/player.js b/www/addons/mod/lesson/controllers/player.js index 7c2e5f840d5..b7eb0b459c1 100644 --- a/www/addons/mod/lesson/controllers/player.js +++ b/www/addons/mod/lesson/controllers/player.js @@ -190,7 +190,7 @@ angular.module('mm.addons.mod_lesson') $scope.pageData = data; $scope.title = data.page.title; - $scope.pageContent = data.page.contents; + $scope.pageContent = $mmaModLessonHelper.getPageContentsFromPageData(data); $scope.pageLoaded = true; $scope.currentPage = pageId; $scope.messages = $scope.messages.concat(data.messages); diff --git a/www/addons/mod/lesson/lang/ar.json b/www/addons/mod/lesson/lang/ar.json index e314397c4ae..4f326bb530d 100644 --- a/www/addons/mod/lesson/lang/ar.json +++ b/www/addons/mod/lesson/lang/ar.json @@ -1,5 +1,6 @@ { "answer": "أجب", + "attempt": "محاولة: {{$a}}", "averagescore": "متوسط الدرجة", "averagetime": "متوسط الوقت", "branchtable": "محتوى", @@ -36,7 +37,7 @@ "review": "مراجعة", "reviewlesson": "مراجعة الدرس", "reviewquestionback": "نعم، أرغب في المحاولة ثانياً", - "submit": "سلم", + "submit": "سلم/قدم", "thatsthecorrectanswer": "هذه إجابة صحيحة", "thatsthewronganswer": "هذه إجابة خاطئة", "timeremaining": "الزمن المتبقى", diff --git a/www/addons/mod/lesson/lang/bg.json b/www/addons/mod/lesson/lang/bg.json index a1b9df04b2a..599f091c09d 100644 --- a/www/addons/mod/lesson/lang/bg.json +++ b/www/addons/mod/lesson/lang/bg.json @@ -1,5 +1,6 @@ { "answer": "Отговор", + "attempt": "{{$a}} опит", "attemptsremaining": "Имате оставащ(и) {{$a}} опит(a)", "averagescore": "Среден резултат", "averagetime": "Средно време", diff --git a/www/addons/mod/lesson/lang/ca.json b/www/addons/mod/lesson/lang/ca.json index ad28463c750..8978fa00b80 100644 --- a/www/addons/mod/lesson/lang/ca.json +++ b/www/addons/mod/lesson/lang/ca.json @@ -1,5 +1,6 @@ { "answer": "Resposta", + "attempt": "Intent: {{$a}}", "attemptheader": "Intent", "attemptsremaining": "Us resten {{$a}} intents", "averagescore": "Puntuació mitjana", diff --git a/www/addons/mod/lesson/lang/cs.json b/www/addons/mod/lesson/lang/cs.json index c6b5605a360..9918f0689c7 100644 --- a/www/addons/mod/lesson/lang/cs.json +++ b/www/addons/mod/lesson/lang/cs.json @@ -1,5 +1,6 @@ { "answer": "Odpověď", + "attempt": "Pokus: {{$a}}", "attemptheader": "Pokus", "attemptsremaining": "Zbývající počet pokusů: {{$a}}", "averagescore": "Průměrná známka", diff --git a/www/addons/mod/lesson/lang/da.json b/www/addons/mod/lesson/lang/da.json index d00ff2ab04e..54d6c8482c3 100644 --- a/www/addons/mod/lesson/lang/da.json +++ b/www/addons/mod/lesson/lang/da.json @@ -1,5 +1,6 @@ { "answer": "Svar", + "attempt": "Forsøg: {{$a}}", "attemptheader": "Forsøg", "attemptsremaining": "Du har {{$a}} forsøg endnu", "averagescore": "Gennemsnitlig score", diff --git a/www/addons/mod/lesson/lang/de.json b/www/addons/mod/lesson/lang/de.json index 60f5cf0ae98..dd4695db26b 100644 --- a/www/addons/mod/lesson/lang/de.json +++ b/www/addons/mod/lesson/lang/de.json @@ -1,5 +1,6 @@ { "answer": "Antwort", + "attempt": "Versuch: {{$a}}", "attemptheader": "Versuch", "attemptsremaining": "Verbleibende Versuche: {{$a}}", "averagescore": "Durchschnittliche Bewertung", @@ -21,6 +22,7 @@ "emptypassword": "Das Kennwort muss eingegeben werden", "enterpassword": "Bitte geben Sie das Kennwort ein:", "eolstudentoutoftimenoanswers": "Sie haben keine Fragen beantwortet. Sie erhalten daher 0 Punkte für die Lektion.", + "errorprefetchrandombranch": "Diese Lektion enthält einen Sprung zu einer zufälligen Seite. Sie kann nicht in der App versucht werden, ohne im Web begonnen zu sein.", "errorreviewretakenotlast": "Dieser Versuch kann nicht erneut angesehen werden, weil ein weiterer Versuch beendet wurde.", "finish": "Fertigstellen", "finishretakeoffline": "Dieser Versuch wurde offline beendet.", diff --git a/www/addons/mod/lesson/lang/el.json b/www/addons/mod/lesson/lang/el.json index d2c0aa91741..cff02dafbf6 100644 --- a/www/addons/mod/lesson/lang/el.json +++ b/www/addons/mod/lesson/lang/el.json @@ -1,5 +1,6 @@ { "answer": "Απάντηση", + "attempt": "Προσπάθεια: {{$a}}", "attemptsremaining": "Σας απομένουν {{$a}} προσπάθειες", "averagescore": "Μέσος βαθμός", "averagetime": "Μέσος χρόνος", @@ -19,6 +20,8 @@ "emptypassword": "Ο κωδικός πρόσβασης δεν μπορεί να είναι κενός", "enterpassword": "Παρακαλώ εισάγετε τον κωδικό:", "eolstudentoutoftimenoanswers": "Δεν απαντήσατε καμία ερώτηση. Πήρατε 0 σε αυτή την ενότητα.", + "errorreviewretakenotlast": "Αυτή η προσπάθεια δεν μπορεί πλέον να αναθεωρηθεί επειδή μια άλλη προσπάθεια έχει ήδη ολοκληρωθεί.", + "finishretakeoffline": "Αυτή η προσπάθεια έχει ολοκληρωθεί εκτός σύνδεσης.", "firstwrong": "Δυστυχώς δεν μπορείτε να κερδίσετε αυτό το βαθμό γιατί η απάντησή σας ήταν λάθος. Θέλετε να συνεχίσετε να μαντεύετε, μόνο για τη χαρά της μάθησης (δεν θα λάβετε το βαθμολογικό μπόνους);", "grade": "Βαθμός", "highscore": "Υψηλός βαθμός", @@ -49,6 +52,9 @@ "rawgrade": "Βαθμός χωρίς επεξεργασία", "reports": "Αναφορές", "response": "Ανταπόκριση", + "retakefinishedinsync": "Μια προσπάθεια εκτός σύνδεσης συγχρονίστηκε. Θέλετε να την αναθεωρήσετε;", + "retakelabelfull": "{{retake}}: {{grade}} {{timestart}} ({{duration}})", + "retakelabelshort": "{{retake}}: {{grade}} {{timestart}}", "review": "Αναθεώρηση", "reviewlesson": "Αναθεώρηση ενότητας", "reviewquestionback": "Ναι, θα ήθελα να δοκιμάσω πάλι", @@ -63,6 +69,7 @@ "timeremaining": "Υπολοιπόμενος χρόνος", "timetaken": "Χρόνος που χρειάστηκε", "unseenpageinbranch": "Ερώτηση μέσα σε διακλάδωση που δεν εμφανίσθηκε", + "warningretakefinished": "Η προσπάθεια ολοκληρώθηκε στον ιστότοπο.", "welldone": "Μπράβο!", "youhaveseen": "Έχετε δει περισσότερες από μία σελίδες αυτής της ενότητας.
Θέλετε να ξεκινήσετε από την τελευταία σελίδα που είδατε;", "youranswer": "Η απάντησή σας", diff --git a/www/addons/mod/lesson/lang/en.json b/www/addons/mod/lesson/lang/en.json index 92a9bb049b6..f9425621099 100644 --- a/www/addons/mod/lesson/lang/en.json +++ b/www/addons/mod/lesson/lang/en.json @@ -22,7 +22,7 @@ "emptypassword": "Password cannot be empty", "enterpassword": "Please enter the password:", "eolstudentoutoftimenoanswers": "You did not answer any questions. You have received a 0 for this lesson.", - "errorprefetchrandombranch": "This lesson contains a jump to a random content page, it cannot be attempted in the app until it has been started in web.", + "errorprefetchrandombranch": "This lesson contains a jump to a random content page. It can't be attempted in the app until it has been started in a web browser.", "errorreviewretakenotlast": "This attempt can no longer be reviewed because another attempt has been finished.", "finish": "Finish", "finishretakeoffline": "This attempt was finished offline.", diff --git a/www/addons/mod/lesson/lang/es-mx.json b/www/addons/mod/lesson/lang/es-mx.json index ead72ecbab5..b45c0a2544c 100644 --- a/www/addons/mod/lesson/lang/es-mx.json +++ b/www/addons/mod/lesson/lang/es-mx.json @@ -1,5 +1,6 @@ { "answer": "Respuesta", + "attempt": "Intento: {{$a}}", "attemptheader": "Intento", "attemptsremaining": "Tiene {{$a}} intento(s) restante(s)", "averagescore": "Puntuación promedio", @@ -21,9 +22,10 @@ "emptypassword": "La contraseña no puede estar vacía", "enterpassword": "Por favor, escriba la contraseña:", "eolstudentoutoftimenoanswers": "No ha contestado a ninguna pregunta. En esta lección ha obtenido 0 puntos.", - "errorreviewretakenotlast": "Este intento no puede ser revisado más porque se ha terminado otro intento.", + "errorprefetchrandombranch": "Esta lección contiene un salto hacia una página aleatoria de contenido; no puede ser intentada en la App hasta que haya sido comenzada en web.", + "errorreviewretakenotlast": "Este intento ya no puede ser revisado más porque se ha terminado otro intento.", "finish": "Terminar", - "finishretakeoffline": "Este intento se ha terminado en fuera-de-línea.", + "finishretakeoffline": "Este intento fue terminado fuera-de-línea.", "firstwrong": "Lo sentimos, usted ha contestado incorrectamente. ¡Le gustaría volver a intentar la pregunta de nuevo? (si Usted contesta ahora la pregunta correctamente, no contará hacia su puntaje final).", "gotoendoflesson": "Ir al final de lección", "grade": "Calificación", @@ -74,7 +76,7 @@ "timeremaining": "Tiempo restante", "timetaken": "Tiempo empleado", "unseenpageinbranch": "Pregunta no vista dentro de una página de conenidos", - "warningretakefinished": "Este intento fue terminado en el sitio.", + "warningretakefinished": "Este intento fue terminado en el sitio web.", "welldone": "¡Bien hecho!", "youhaveseen": "Usted ya ha visto más de una página de esta lección.
¿Desea comenzar desde la última página vista?", "youranswer": "Su respuesta", diff --git a/www/addons/mod/lesson/lang/es.json b/www/addons/mod/lesson/lang/es.json index 1b960b84214..9c084627631 100644 --- a/www/addons/mod/lesson/lang/es.json +++ b/www/addons/mod/lesson/lang/es.json @@ -1,5 +1,6 @@ { "answer": "Respuesta", + "attempt": "Intento: {{$a}}", "attemptheader": "Intento", "attemptsremaining": "Tiene {{$a}} intento(s) pendiente(s)", "averagescore": "Puntuación promedio", @@ -21,7 +22,9 @@ "emptypassword": "La contraseña no puede estar vacía", "enterpassword": "Por favor, escriba la contraseña:", "eolstudentoutoftimenoanswers": "No ha contestado a ninguna pregunta. En esta lección ha obtenido 0 puntos.", + "errorreviewretakenotlast": "Este intento no puede ser revisado ya que se ha terminado otro intento.", "finish": "Terminado", + "finishretakeoffline": "Este intento se ha terminado en fuera-de-línea.", "firstwrong": "Lo sentimos, usted no puede obtener este punto porque su respuesta no es correcta. ¿Desea seguir intentándolo? (únicamente para aprender, no para ganar el punto).", "gotoendoflesson": "Ir al final de la lección", "grade": "Calificación", @@ -55,6 +58,9 @@ "rawgrade": "Calificación en bruto", "reports": "Informes", "response": "Comentario", + "retakefinishedinsync": "Un intento fuera-de-línea fue sincronizado. ¿Quiere usted revisarlo?", + "retakelabelfull": "{{retake}}: {{grade}} {{timestart}} ({{duration}})", + "retakelabelshort": "{{retake}}: {{grade}} {{timestart}}", "review": "Revisión", "reviewlesson": "Revisar lección", "reviewquestionback": "Sí, me gustaría probar de nuevo", @@ -69,6 +75,7 @@ "timeremaining": "Tiempo restante", "timetaken": "Tiempo empleado", "unseenpageinbranch": "Pregunta no vista dentro de una página de conenidos", + "warningretakefinished": "Este intento se terminó en el sitio.", "welldone": "¡Bien hecho!", "youhaveseen": "Usted ya ha visto más de una página de esta lección.
¿Desea comenzar desde la última página vista?", "youranswer": "Su respuesta", diff --git a/www/addons/mod/lesson/lang/eu.json b/www/addons/mod/lesson/lang/eu.json index eb0cc12c6b0..fac71d304b6 100644 --- a/www/addons/mod/lesson/lang/eu.json +++ b/www/addons/mod/lesson/lang/eu.json @@ -1,5 +1,6 @@ { "answer": "Erantzuna", + "attempt": "Saiakera: {{$a}}", "attemptheader": "Saiakera", "attemptsremaining": "{{$a}} saiakera pendiente daukazu", "averagescore": "Batez besteko puntuazioa", @@ -24,7 +25,7 @@ "errorreviewretakenotlast": "Saiakera hau ezin da berrikusi dagoeneko beste saiakera bat amaitu duzulako.", "finish": "Amaitu", "finishretakeoffline": "Saiakera lineaz kanpo bukatu da.", - "firstwrong": "Sentitzen dugu. Ez duzu puntua lortu zure erantzuna zuzena izan ez delako. Berriz saiatu nahi al duzu? (ikasteko bakarrik, ez puntua lortzeko).", + "firstwrong": "Zure erantzuna ez da zuzena izan. Berriz saiatu nahi al duzu? (Oraingoan ondo erantzunez gero ez da zure azken emaitzan zenbatuko).", "gotoendoflesson": "Joan ikasgaiaren amaierara", "grade": "Kalifikazioa", "highscore": "Puntuazio altua", diff --git a/www/addons/mod/lesson/lang/fa.json b/www/addons/mod/lesson/lang/fa.json index 79774430714..36d3d14fd74 100644 --- a/www/addons/mod/lesson/lang/fa.json +++ b/www/addons/mod/lesson/lang/fa.json @@ -1,5 +1,6 @@ { "answer": "جواب", + "attempt": "تلاش: {{$a}}", "attemptsremaining": "می‌توانید {{$a}} بار دیگر تلاش کنید", "averagescore": "نمرهٔ میانگین", "averagetime": "زمان میانگین", diff --git a/www/addons/mod/lesson/lang/fr.json b/www/addons/mod/lesson/lang/fr.json index 2b8652437b9..538cdcf99bb 100644 --- a/www/addons/mod/lesson/lang/fr.json +++ b/www/addons/mod/lesson/lang/fr.json @@ -1,5 +1,6 @@ { "answer": "Réponse", + "attempt": "Tentative : {{$a}}", "attemptheader": "Tentative", "attemptsremaining": "Il vous reste {{$a}} tentative(s)", "averagescore": "Note moyenne", @@ -21,7 +22,10 @@ "emptypassword": "Le mot de passe ne peut pas être vide", "enterpassword": "Veuillez saisir le mot de passe :", "eolstudentoutoftimenoanswers": "vous n'avez répondu à aucune question. Votre note pour cette leçon est de 0.", + "errorprefetchrandombranch": "Cette leçon comporte un saut vers une page aléatoire. Elle ne peut être effectuée dans l'app avant d'avoir été commencée dans un navigateur.", + "errorreviewretakenotlast": "Cette tentative ne peut plus être relue, car une autre tentative a été terminée.", "finish": "Terminer", + "finishretakeoffline": "Cette tentative a été terminée hors ligne.", "firstwrong": "Vous n'avez pas répondu correctement. Voulez-vous essayer de deviner la bonne réponse ? Si vous répondez maintenant correctement, vous ne recevrez cependant pas de point.", "gotoendoflesson": "Aller à la fin de la leçon", "grade": "Note", @@ -55,13 +59,16 @@ "rawgrade": "Note brute", "reports": "Rapports", "response": "Feedback", + "retakefinishedinsync": "Une tentative hors ligne a été synchronisée. Voulez-vous la relire ?", + "retakelabelfull": "{{retake}}: {{grade}} {{timestart}} ({{duration}})", + "retakelabelshort": "{{retake}}: {{grade}} {{timestart}}", "review": "Relecture", "reviewlesson": "Revoir la leçon", "reviewquestionback": "Oui, j'aimerais essayer à nouveau", "reviewquestioncontinue": "Non, je veux passer à la question suivante", "secondpluswrong": "Pas tout à fait. Voulez-vous essayer à nouveau ?", "submit": "Envoyer", - "teacherjumpwarning": "Un lien {{$a.cluster}} ou un lien {{$a.unseen}} est utilisé dans cette leçon. Un lien « Page suivante » sera utilisé à sa place. Veuillez vous connecter en tant que participant pour tester ces liens.", + "teacherjumpwarning": "Un lien {{$a.cluster}} ou un lien {{$a.unseen}} est utilisé dans cette leçon. Un lien « Page suivante » sera utilisé à sa place. Veuillez vous connecter en tant qu'étudiant pour tester ces liens.", "teacherongoingwarning": "Le score actuel n'est affiché que pour les étudiants. Veuillez vous connecter en tant qu'étudiant pour tester le score actuel.", "teachertimerwarning": "Le chronomètre ne fonctionne que pour les étudiants. Veuillez vous connecter en tant qu'étudiant pour tester le chronomètre.", "thatsthecorrectanswer": "C'est une réponse correcte", @@ -69,6 +76,7 @@ "timeremaining": "Durée restante", "timetaken": "Durée utilisée", "unseenpageinbranch": "Question non vue au sein d'une page de contenu", + "warningretakefinished": "Cette tentative a été terminée dans un navigateur.", "welldone": "Bien joué !", "youhaveseen": "Vous avez déjà vu au moins une page de cette leçon.
Voulez-vous commencer à la dernière page que vous avez vue ?", "youranswer": "Votre réponse", diff --git a/www/addons/mod/lesson/lang/he.json b/www/addons/mod/lesson/lang/he.json index cc0a9600655..637604577d7 100644 --- a/www/addons/mod/lesson/lang/he.json +++ b/www/addons/mod/lesson/lang/he.json @@ -1,5 +1,6 @@ { "answer": "תשובה", + "attempt": "ניסיון: {{$a}}", "attemptheader": "ניסיון", "attemptsremaining": "נשארו לך עוד {{$a}} ניסיונות", "averagescore": "תוצאה ממוצעת", diff --git a/www/addons/mod/lesson/lang/hu.json b/www/addons/mod/lesson/lang/hu.json index d46a7ad2909..4c2bb5a14a2 100644 --- a/www/addons/mod/lesson/lang/hu.json +++ b/www/addons/mod/lesson/lang/hu.json @@ -1,5 +1,6 @@ { "answer": "Válasz", + "attempt": "Próbálkozás: {{$a}}", "attemptheader": "Próbálkozás", "attemptsremaining": "{{$a}} próbálkozása maradt", "averagescore": "Átlagpontszám", diff --git a/www/addons/mod/lesson/lang/it.json b/www/addons/mod/lesson/lang/it.json index de8299fe5af..3cd913414eb 100644 --- a/www/addons/mod/lesson/lang/it.json +++ b/www/addons/mod/lesson/lang/it.json @@ -1,5 +1,6 @@ { "answer": "Risposta", + "attempt": "Tentativo: {{$a}}", "attemptheader": "Tentativo", "attemptsremaining": "Ti rimangono {{$a}} tentativo/i", "averagescore": "Punteggio medio", diff --git a/www/addons/mod/lesson/lang/ja.json b/www/addons/mod/lesson/lang/ja.json index 18e3ade173c..786b3484757 100644 --- a/www/addons/mod/lesson/lang/ja.json +++ b/www/addons/mod/lesson/lang/ja.json @@ -1,5 +1,6 @@ { - "answer": "答え/選択肢", + "answer": "答え", + "attempt": "受験: {{$a}}", "attemptheader": "受験", "attemptsremaining": "あなたには {{$a}} 回の受験回数が残っています。", "averagescore": "平均評点", @@ -21,14 +22,16 @@ "emptypassword": "パスワードは空白にできません。", "enterpassword": "パスワードを入力してください:", "eolstudentoutoftimenoanswers": "あなたはどの問題にも解答していません。このレッスンのあなたの評点は0点です。", + "errorreviewretakenotlast": "この回答は、別の回答が完了しているため評価できません。", "finish": "終了", + "finishretakeoffline": "この回答はオフライン状態で完了しました。", "firstwrong": "あなたの解答は正しくありません。問題を再度受験しますか? (今から問題に正しく解答した場合、あなたの最終評点には加算されません)", "gotoendoflesson": "レッスンの最後に移動する", "grade": "評点", "highscore": "最高評点", "hightime": "最長時間", "leftduringtimed": "あなたは制限時間のあるレッスンを途中で終了しました。
レッスンを再スタートするには「続ける」をクリックしてください。", - "leftduringtimednoretake": "あなたは制限時間のあるレッスンを途中で終了しました。
レッスンを再受験または継続は許可されていません。", + "leftduringtimednoretake": "あなたは制限時間のあるレッスンを途中で終了しました。
レッスンの再受験または継続は許可されていません。", "lessonmenu": "レッスンメニュー", "lessonstats": "レッスン統計", "linkedmedia": "リンクメディア", @@ -36,10 +39,10 @@ "lowscore": "最低評点", "lowtime": "最短時間", "maximumnumberofattemptsreached": "最大受験回数に達しました - 次のページに移動しています。", - "modattemptsnoteacher": "学生レビューは学生のみに表示されます。", + "modattemptsnoteacher": "学生レビューは学生にのみ表示されます。", "noanswer": "1つまたはそれ以上の問題が解答されていません。戻って解答を送信してください。", "nolessonattempts": "このレッスンは受験されていません。", - "nolessonattemptsgroup": "このレッスンの {{$a}} グループメンバーによる受験はありません。", + "nolessonattemptsgroup": "このレッスンでは {{$a}} グループメンバーによる受験はありません。", "notcompleted": "未了", "numberofcorrectanswers": "正解数: {{$a}}", "numberofpagesviewed": "解答済み問題数: {{$a}}", @@ -55,6 +58,9 @@ "rawgrade": "素点", "reports": "レポート", "response": "返答", + "retakefinishedinsync": "オフラインの回答が同期されました。評価しますか?", + "retakelabelfull": "{{retake}}: {{grade}} {{timestart}} ({{duration}})", + "retakelabelshort": "{{retake}}: {{grade}} {{timestart}}", "review": "レビュー", "reviewlesson": "レッスンをレビューする", "reviewquestionback": "はい、もう一度受験します", @@ -62,13 +68,14 @@ "secondpluswrong": "もう一度受験しますか?", "submit": "送信", "teacherjumpwarning": "このレッスンでは {{$a.cluster}} ジャンプまたは {{$a.unseen}} ジャンプが使用されています。代わりに「次のページ」へのジャンプが使用されます。これらのジャンプを確認するには学生としてログインしてください。", - "teacherongoingwarning": "進行中の評点は学生にのみ表示されます。進行中のスコアをテストするには学生としてログインしてください。", + "teacherongoingwarning": "進行中の評点は学生にのみ表示されます。進行中の評点をテストするには学生としてログインしてください。", "teachertimerwarning": "タイマーは学生に対してのみ作動します。タイマーをテストするには学生としてログインしてください。", "thatsthecorrectanswer": "正解です。", "thatsthewronganswer": "不正解です。", "timeremaining": "残り時間", "timetaken": "経過時間", "unseenpageinbranch": "コンテンツページ内の未閲覧の問題", + "warningretakefinished": "回答はサイト内で完了しました。", "welldone": "よくできました!", "youhaveseen": "あなたはすでにこのレッスンを2ページ以上表示しました。
あなたが表示した最後のページから始めますか?", "youranswer": "あなたの答え", diff --git a/www/addons/mod/lesson/lang/lt.json b/www/addons/mod/lesson/lang/lt.json index e088a565222..d342ddcca33 100644 --- a/www/addons/mod/lesson/lang/lt.json +++ b/www/addons/mod/lesson/lang/lt.json @@ -1,5 +1,6 @@ { "answer": "Atsakyti", + "attempt": "Bandymas: {{$a}}", "attemptheader": "Bandymas", "attemptsremaining": "Turite likusių bandymų: {{$a}}", "averagescore": "Vidutinis balas", diff --git a/www/addons/mod/lesson/lang/nl.json b/www/addons/mod/lesson/lang/nl.json index e2620a8cabf..1dfe7b3bc47 100644 --- a/www/addons/mod/lesson/lang/nl.json +++ b/www/addons/mod/lesson/lang/nl.json @@ -1,5 +1,6 @@ { "answer": "Antwoord", + "attempt": "Poging: {{$a}}", "attemptheader": "Poging", "attemptsremaining": "Je kan nog {{$a}} poging(en) doen", "averagescore": "Gemiddelde score", @@ -21,9 +22,10 @@ "emptypassword": "Wachtwoord kan niet leeg zijn", "enterpassword": "Geef het wachtwoord:", "eolstudentoutoftimenoanswers": "Je hebt geen enkele vraag beantwoord. Je hebt een 0 voor deze les", + "errorprefetchrandombranch": "Deze les bevat een sprong naar een willekeurige inhoudspagina. De les kan niet gestart worden in de app zonder dat die gestart is op het web.", "errorreviewretakenotlast": "Deze poging kan niet meer nagekeken worden omdat er al een andere poging voltooid is.", "finish": "Einde", - "finishretakeoffline": "Deze poging is voltooid in offline modus", + "finishretakeoffline": "Deze poging is voltooid in offline modus.", "firstwrong": "Je antwoord is fout. Wil je de vraag opnieuw proberen te beantwoorden? Als je het antwoord weet, zul je er geen punten meer mee verdienen.", "gotoendoflesson": "Ga naar het einde van de les", "grade": "Cijfer", diff --git a/www/addons/mod/lesson/lang/pl.json b/www/addons/mod/lesson/lang/pl.json index c36b7ae91cf..410586113e2 100644 --- a/www/addons/mod/lesson/lang/pl.json +++ b/www/addons/mod/lesson/lang/pl.json @@ -1,5 +1,6 @@ { "answer": "Odpowiedź", + "attempt": "Podejście: {{$a}}", "attemptheader": "Próba", "attemptsremaining": "Pozostało Ci {{$a}} podejść", "averagescore": "Średnia liczba punktów", diff --git a/www/addons/mod/lesson/lang/pt-br.json b/www/addons/mod/lesson/lang/pt-br.json index a50382f3902..613d8d5c741 100644 --- a/www/addons/mod/lesson/lang/pt-br.json +++ b/www/addons/mod/lesson/lang/pt-br.json @@ -1,5 +1,6 @@ { "answer": "Resposta", + "attempt": "Tentativa: {{$a}}", "attemptheader": "Tentativa", "attemptsremaining": "Você tem ainda {{$a}} tentativas", "averagescore": "Pontuação média", diff --git a/www/addons/mod/lesson/lang/pt.json b/www/addons/mod/lesson/lang/pt.json index e236e65f35a..eab86d3e961 100644 --- a/www/addons/mod/lesson/lang/pt.json +++ b/www/addons/mod/lesson/lang/pt.json @@ -1,5 +1,6 @@ { "answer": "Resposta", + "attempt": "Tentativa: {{$a}}", "attemptheader": "Tentativa", "attemptsremaining": "Ainda pode realizar {{$a}} tentativa(s)", "averagescore": "Pontuação média", @@ -16,7 +17,7 @@ "detailedstats": "Estatísticas detalhadas", "didnotanswerquestion": "Não respondeu a esta pergunta", "displayofgrade": "Exibição da nota (apenas para alunos)", - "displayscorewithessays": "Obteve {{$a.score}} num máximo de {{$a.tempmaxgrade}}.
As suas respostas à(s) pergunta(s) de desenvolvimento {{$a.essayquestions resposta(s)}} serão avaliadas posteriormente,
sendo a pontuação correspondente adicionada à pontuação final.

A sua classificação atual, sem as perguntas que faltam avaliar, é de {{$a.score}} num máximo de {{$a.grade}}.", + "displayscorewithessays": "Obteve {{$a.score}} num máximo de {{$a.tempmaxgrade}}.
As suas respostas à(s) pergunta(s) de desenvolvimento {{$a.essayquestions}} resposta(s) serão avaliadas posteriormente,
sendo a pontuação correspondente adicionada à pontuação final.

A sua classificação atual, sem as perguntas que faltam avaliar, é de {{$a.score}} num máximo de {{$a.grade}}.", "displayscorewithoutessays": "Obteve uma pontuação de {{$a.score}} (em {{$a.grade}}). Clique em Ver notas para ver a sua nota final na pauta", "emptypassword": "A palava-chave não pode estar em branco", "enterpassword": "Introduza a senha:", @@ -66,11 +67,11 @@ "reviewquestioncontinue": "Não, quero avançar para a pergunta seguinte", "secondpluswrong": "Resposta incorreta. Quer voltar a tentar?", "submit": "Submeter", - "teacherjumpwarning": "Nesta lição, há páginas que seguem para {{$a.cluster}} ou {{$a.unseen}}. Esta sequência será ignorada e a lição seguirá para a página seguinte. Para testar a sequência das páginas entre como aluno.", + "teacherjumpwarning": "Nesta lição, há páginas que seguem para {{$a.cluster}} ou para {{$a.unseen}}. Esta sequência será ignorada e a lição seguirá para a página seguinte. Para testar a sequência das páginas entre como aluno.", "teacherongoingwarning": "A exibição da pontuação no decorrer da lição só é visível para os alunos. Para ver a pontuação no decorrer da lição entre como aluno.", "teachertimerwarning": "O cronómetro só é visível para os alunos. Para testar esta funcionalidade, entre como aluno.", "thatsthecorrectanswer": "A sua resposta está correta.", - "thatsthewronganswer": "A sua resposta não está correta.", + "thatsthewronganswer": "A sua resposta não está correta.", "timeremaining": "Tempo restante", "timetaken": "Tempo usado", "unseenpageinbranch": "Pergunta não vista da sequência", diff --git a/www/addons/mod/lesson/lang/ro.json b/www/addons/mod/lesson/lang/ro.json index e921358830b..b13962e5dd6 100644 --- a/www/addons/mod/lesson/lang/ro.json +++ b/www/addons/mod/lesson/lang/ro.json @@ -1,5 +1,6 @@ { "answer": "Răspuns", + "attempt": "Încercarea cu numărul: {{$a}}", "attemptheader": "Încercare", "attemptsremaining": "Mai aveţi {{$a}} încercări disponibile", "averagescore": "Punctaj mediu obţinut", diff --git a/www/addons/mod/lesson/lang/ru.json b/www/addons/mod/lesson/lang/ru.json index cdfe818e247..f8db842221a 100644 --- a/www/addons/mod/lesson/lang/ru.json +++ b/www/addons/mod/lesson/lang/ru.json @@ -1,5 +1,6 @@ { "answer": "Ответ", + "attempt": "Попытка: {{$a}}", "attemptheader": "Попытка", "attemptsremaining": "У вас осталось {{$a}} попыток", "averagescore": "Средний балл", diff --git a/www/addons/mod/lesson/lang/sr-cr.json b/www/addons/mod/lesson/lang/sr-cr.json new file mode 100644 index 00000000000..a09a8dc2437 --- /dev/null +++ b/www/addons/mod/lesson/lang/sr-cr.json @@ -0,0 +1,85 @@ +{ + "answer": "Одговор", + "attempt": "Покушај: {{$a}}", + "attemptheader": "Покушај", + "attemptsremaining": "Број покушаја који вам је преостао: {{$a}}", + "averagescore": "Просечан број бодова", + "averagetime": "Просечно време", + "branchtable": "Садржај са гранањем", + "cannotfindattempt": "Грешка: није пронађен покушај", + "cannotfinduser": "Грешка: нису пронађени слогови у табели lesson_timer", + "clusterjump": "Још неприказано питање из групе питања", + "completed": "Завршено", + "congratulations": "Честитамо - стигли сте до краја лекције", + "continue": "Настави", + "continuetonextpage": "Идите на следећу страницу", + "defaultessayresponse": "Предавач ће оценити ваш есеј.", + "detailedstats": "Детаљна статистика", + "didnotanswerquestion": "Нисте одговорили на ово питање.", + "displayofgrade": "Приказ оцена (само за полазнике)", + "displayscorewithessays": "

Освојили сте {{$a.score}} од максималних {{$a.tempmaxgrade}} бодова за питања која се аутоматски оцењују.

\n

Ваш {{$a.essayquestions}} одговор на питања у форми есеја биће ускоро прегледан и оцењен, а оцена ће касније бити додата
у ваш финални резултат.

\n

Ваша тренутна оцена без есеја је {{$a.score}} од {{$a.grade}}

", + "displayscorewithoutessays": "Ваш резултат је {{$a.score}} (од могућих {{$a.grade}}).", + "emptypassword": "Поље за лозинку не може бити празно", + "enterpassword": "Молимо унесите лозинку:", + "eolstudentoutoftimenoanswers": "Нисте одговорили ни на једно питање. Ваша оцена за ову лекцију је 0.", + "errorprefetchrandombranch": "Ова лекција садржи прелаз на наусимично одабрану страницу са садржајем, па је није могуће урадити у апликацији док се не покрене на веб сајту.", + "errorreviewretakenotlast": "Ова покушај не може више бити прегледан зато што је завршен други покушај.", + "finish": "Заврши", + "finishretakeoffline": "Овај покушај је завршен у офлајн режиму.", + "firstwrong": "Погрешно сте одговорили на питање. Да ли желите да покушате поново? (ако сада тачно одговорите на питање, то се неће рачунати у ваш коначан резултат.)", + "gotoendoflesson": "Иди на крај лекције", + "grade": "Оцена", + "highscore": "Најбољи резултат", + "hightime": "Најдуже време", + "leftduringtimed": "Напустили сте лекцију која је временски ограничена.
Притисните тастер за наставак да бисте погледали лекцију од почетка.", + "leftduringtimednoretake": "Напустили сте лекцију која је временски ограничена и није Вам
дозвољено да наставите или почнете лекцију из почетка.", + "lessonmenu": "Мени лекције", + "lessonstats": "Статистика лекције", + "linkedmedia": "Повезани медији", + "loginfail": "Погрешна пријава, молимо покушајте поново...", + "lowscore": "Наслабији резултат", + "lowtime": "Најкраће време", + "maximumnumberofattemptsreached": "Достигнут је максималан број покушаја - прелази се на следећу страницу", + "modattemptsnoteacher": "Полазнички преглед функционише само за полазнике.", + "noanswer": "На једно или више питања није дат одговор. Молимо вратите се назад и дајте свој одговор.", + "nolessonattempts": "Нико још није покушао да прође кроз ову лекцију.", + "nolessonattemptsgroup": "Није било покушаја за ову лекцију од стране чланова групе {{$a}}.", + "notcompleted": "Није завршено", + "numberofcorrectanswers": "Број тачних одговора: {{$a}}", + "numberofpagesviewed": "Број прегледаних страница: {{$a}}", + "numberofpagesviewednotice": "Број питања на које је дат одговор: {{$a.nquestions}} (Требало би их бити бар {{$a.minquestions}})", + "ongoingcustom": "До сада сте освојили {{$a.score}} од максимално {{$a.currenthigh}} бодова.", + "ongoingnormal": "Тачно сте одговорили на {{$a.correct}} од {{$a.viewed}} питања која сте видели.", + "or": "ИЛИ", + "overview": "Преглед", + "preview": "Преглед", + "progressbarteacherwarning2": "Нећете видети траку напредовања зато што можете да уређујете ову лекцију", + "progresscompleted": "Завршили сте {{$a}}% лекције", + "question": "Питање", + "rawgrade": "Необрађена оцена", + "reports": "Извештаји", + "response": "Повратне информације", + "retakefinishedinsync": "Офлајн покушај је синхронизован. Да ли желите да га прегледате?", + "retakelabelfull": "{{retake}}: {{grade}} {{timestart}} ({{duration}})", + "retakelabelshort": "{{retake}}: {{grade}} {{timestart}}", + "review": "Преглед", + "reviewlesson": "Преглед лекције", + "reviewquestionback": "Да, волео/ла бих да поново покушам", + "reviewquestioncontinue": "Не, желим да пређем на следеће питање", + "secondpluswrong": "Није баш. Да ли желите да покушате поново?", + "submit": "Пошаљи", + "teacherjumpwarning": "У овој лекцији се користе {{$a.cluster}} или {{$a.unseen}} прелаз између страница. Прелаз \"Следећа страница\" ће се користити уместо њих током овог приказа. За тестирање ових прелаза пријавите се на систем у улози полазника.", + "teacherongoingwarning": "Тренутни резултат током прегледа лекције се приказује само полазницима. Пријавите се на систем у улози полазника да бисте тестирали ову могућност.", + "teachertimerwarning": "Мерач времена могу да виде само полазници. Како бисте тестирали мерач времена пријавите се на систем у улози полазника.", + "thatsthecorrectanswer": "Тачан одговор", + "thatsthewronganswer": "Погрешан одговор", + "timeremaining": "Преостало време", + "timetaken": "Потрошено време", + "unseenpageinbranch": "Још неприказано питање унутар стране са садржајем и гранањем", + "warningretakefinished": "Покушај је завршен на веб сајту.", + "welldone": "Браво!", + "youhaveseen": "Већ сте видели више од једне странице ове лекције.
Желите ли почети од последње странице коју сте видели?", + "youranswer": "Ваш одговор", + "yourcurrentgradeisoutof": "Ваша тренутна оцена је {{$a.grade}} од могућих {{$a.total}}", + "youshouldview": "Требало би да одговорите на барем: {{$a}}" +} \ No newline at end of file diff --git a/www/addons/mod/lesson/lang/sr-lt.json b/www/addons/mod/lesson/lang/sr-lt.json new file mode 100644 index 00000000000..a98cc2242e1 --- /dev/null +++ b/www/addons/mod/lesson/lang/sr-lt.json @@ -0,0 +1,85 @@ +{ + "answer": "Odgovor", + "attempt": "Pokušaj: {{$a}}", + "attemptheader": "Pokušaj", + "attemptsremaining": "Broj pokušaja koji vam je preostao: {{$a}}", + "averagescore": "Prosečan broj bodova", + "averagetime": "Prosečno vreme", + "branchtable": "Sadržaj sa grananjem", + "cannotfindattempt": "Greška: nije pronađen pokušaj", + "cannotfinduser": "Greška: nisu pronađeni slogovi u tabeli lesson_timer", + "clusterjump": "Još neprikazano pitanje iz grupe pitanja", + "completed": "Završeno", + "congratulations": "Čestitamo - stigli ste do kraja lekcije", + "continue": "Nastavi", + "continuetonextpage": "Idite na sledeću stranicu", + "defaultessayresponse": "Predavač će oceniti vaš esej.", + "detailedstats": "Detaljna statistika", + "didnotanswerquestion": "Niste odgovorili na ovo pitanje.", + "displayofgrade": "Prikaz ocena (samo za polaznike)", + "displayscorewithessays": "

Osvojili ste {{$a.score}} od maksimalnih {{$a.tempmaxgrade}} bodova za pitanja koja se automatski ocenjuju.

\n

Vaš {{$a.essayquestions}} odgovor na pitanja u formi eseja biće uskoro pregledan i ocenjen, a ocena će kasnije biti dodata
u vaš finalni rezultat.

\n

Vaša trenutna ocena bez eseja je {{$a.score}} od {{$a.grade}}

", + "displayscorewithoutessays": "Vaš rezultat je {{$a.score}} (od mogućih {{$a.grade}}).", + "emptypassword": "Polje za lozinku ne može biti prazno", + "enterpassword": "Molimo unesite lozinku:", + "eolstudentoutoftimenoanswers": "Niste odgovorili ni na jedno pitanje. Vaša ocena za ovu lekciju je 0.", + "errorprefetchrandombranch": "Ova lekcija sadrži prelaz na nausimično odabranu stranicu sa sadržajem, pa je nije moguće uraditi u aplikaciji dok se ne pokrene na veb sajtu.", + "errorreviewretakenotlast": "Ova pokušaj ne može više biti pregledan zato što je završen drugi pokušaj.", + "finish": "Završi", + "finishretakeoffline": "Ovaj pokušaj je završen u oflajn režimu.", + "firstwrong": "Pogrešno ste odgovorili na pitanje. Da li želite da pokušate ponovo? (ako sada tačno odgovorite na pitanje, to se neće računati u vaš konačan rezultat.)", + "gotoendoflesson": "Idi na kraj lekcije", + "grade": "Ocena", + "highscore": "Najbolji rezultat", + "hightime": "Najduže vreme", + "leftduringtimed": "Napustili ste lekciju koja je vremenski ograničena.
Pritisnite taster za nastavak da biste pogledali lekciju od početka.", + "leftduringtimednoretake": "Napustili ste lekciju koja je vremenski ograničena i nije Vam
dozvoljeno da nastavite ili počnete lekciju iz početka.", + "lessonmenu": "Meni lekcije", + "lessonstats": "Statistika lekcije", + "linkedmedia": "Povezani mediji", + "loginfail": "Pogrešna prijava, molimo pokušajte ponovo...", + "lowscore": "Naslabiji rezultat", + "lowtime": "Najkraće vreme", + "maximumnumberofattemptsreached": "Dostignut je maksimalan broj pokušaja - prelazi se na sledeću stranicu", + "modattemptsnoteacher": "Polaznički pregled funkcioniše samo za polaznike", + "noanswer": "Na jedno ili više pitanja nije dat odgovor. Molimo vratite se nazad i dajte svoj odgovor.", + "nolessonattempts": "Niko još nije pokušao da prođe kroz ovu lekciju.", + "nolessonattemptsgroup": "Nije bilo pokušaja za ovu lekciju od strane članova grupe {{$a}}.", + "notcompleted": "Nije završeno", + "numberofcorrectanswers": "Broj tačnih odgovora: {{$a}}", + "numberofpagesviewed": "Broj pregledanih stranica: {{$a}}", + "numberofpagesviewednotice": "Broj pitanja na koje je dat odgovor: {{$a.nquestions}} (Trebalo bi ih biti bar {{$a.minquestions}})", + "ongoingcustom": "Do sada ste osvojili {{$a.score}} od maksimalno {{$a.currenthigh}} bodova.", + "ongoingnormal": "Tačno ste odgovorili na {{$a.correct}} od {{$a.viewed}} pitanja koja ste videli.", + "or": "ILI", + "overview": "Pregled", + "preview": "Pregled", + "progressbarteacherwarning2": "Nećete videti traku napredovanja zato što možete da uređujete ovu lekciju", + "progresscompleted": "Završili ste {{$a}}% lekcije", + "question": "Pitanje", + "rawgrade": "Neobrađena ocena", + "reports": "Izveštaji", + "response": "Povratne informacije", + "retakefinishedinsync": "Oflajn pokušaj je sinhronizovan. Da li želite da ga pregledate?", + "retakelabelfull": "{{retake}}: {{grade}} {{timestart}} ({{duration}})", + "retakelabelshort": "{{retake}}: {{grade}} {{timestart}}", + "review": "Pregled", + "reviewlesson": "Pregled lekcije", + "reviewquestionback": "Da, voleo/la bih da ponovo pokušam", + "reviewquestioncontinue": "Ne, želim da pređem na sledeće pitanje", + "secondpluswrong": "Nije baš. Da li želite da pokušate ponovo?", + "submit": "Pošalji", + "teacherjumpwarning": "U ovoj lekciji se koriste {{$a.cluster}} ili {{$a.unseen}} prelaz između stranica. Prelaz \"Sledeća stranica\" će se koristiti umesto njih tokom ovog prikaza. Za testiranje ovih prelaza prijavite se na sistem u ulozi polaznika.", + "teacherongoingwarning": "Trenutni rezultat tokom pregleda lekcije se prikazuje samo polaznicima. Prijavite se na sistem u ulozi polaznika da biste testirali ovu mogućnost.", + "teachertimerwarning": "Merač vremena mogu da vide samo polaznici. Kako biste testirali merač vremena prijavite se na sistem u ulozi polaznika.", + "thatsthecorrectanswer": "Tačan odgovor", + "thatsthewronganswer": "Pogrešan odgovor", + "timeremaining": "Preostalo vreme", + "timetaken": "Potrošeno vreme", + "unseenpageinbranch": "Još neprikazano pitanje unutar strane sa sadržajem i grananjem", + "warningretakefinished": "Pokušaj je završen na veb sajtu.", + "welldone": "Bravo!", + "youhaveseen": "Već ste videli više od jedne stranice ove lekcije.
Želite li početi od poslednje stranice koju ste videli?", + "youranswer": "Vaš odgovor", + "yourcurrentgradeisoutof": "Vaša trenutna ocena je {{$a.grade}} od mogućih {{$a.total}}", + "youshouldview": "Trebalo bi da odgovorite na barem: {{$a}}" +} \ No newline at end of file diff --git a/www/addons/mod/lesson/lang/sv.json b/www/addons/mod/lesson/lang/sv.json index fe0a53b2702..747a688c78b 100644 --- a/www/addons/mod/lesson/lang/sv.json +++ b/www/addons/mod/lesson/lang/sv.json @@ -1,5 +1,6 @@ { "answer": "Svar", + "attempt": "Försök: {{$a}}", "attemptsremaining": "Du har {{$a}} återstående försök", "averagescore": "Genomsnittsligt resultat", "averagetime": "Genomsnittslig tid", diff --git a/www/addons/mod/lesson/lang/tr.json b/www/addons/mod/lesson/lang/tr.json index 99d0bd338e2..7f50d81d9ea 100644 --- a/www/addons/mod/lesson/lang/tr.json +++ b/www/addons/mod/lesson/lang/tr.json @@ -1,5 +1,6 @@ { "answer": "Cevap", + "attempt": "Uygulama: {{$a}}", "attemptheader": "Deneme(Teşebbüs)", "attemptsremaining": "{{$a}} uygulama hakkınız kaldı", "averagescore": "Ortalama not", diff --git a/www/addons/mod/lesson/lang/uk.json b/www/addons/mod/lesson/lang/uk.json index e6a5762d90d..64f4e4e242a 100644 --- a/www/addons/mod/lesson/lang/uk.json +++ b/www/addons/mod/lesson/lang/uk.json @@ -1,5 +1,6 @@ { "answer": "Відповідь", + "attempt": "Спроба: {{$a}}", "attemptheader": "Спроба", "attemptsremaining": "У Вас залишилося {{$a}} спроб(и)", "averagescore": "Середній бал", @@ -21,7 +22,7 @@ "emptypassword": "Пароль не може бути порожнім", "enterpassword": "Будь ласка, введіть пароль:", "eolstudentoutoftimenoanswers": "Ви не дали відповіді на жодне запитання. Ви отримуєте нуль за цей урок.", - "errorreviewretakenotlast": "Ця спроба не може бути переглянута більше, тому що ще одна спроба була закінчена.", + "errorreviewretakenotlast": "Ця спроба не може бути переглянута, тому що ще одна спроба була закінчена.", "finish": "Завершити", "finishretakeoffline": "Ця спроба була закінчена в автономному режимі.", "firstwrong": "На жаль, за неправильної відповіді Ви не можете отримати бал. Ви хочете продовжити вгадування в цілях навчання (але не в цілях отримання балів)?", diff --git a/www/addons/mod/lesson/lang/zh-cn.json b/www/addons/mod/lesson/lang/zh-cn.json index 3c06c89a713..1cb9bce4497 100644 --- a/www/addons/mod/lesson/lang/zh-cn.json +++ b/www/addons/mod/lesson/lang/zh-cn.json @@ -1,5 +1,6 @@ { "answer": "答案", + "attempt": "尝试:{{$a}}", "attemptsremaining": "您还有{{$a}}次机会", "averagescore": "平均分", "averagetime": "平均耗时", diff --git a/www/addons/mod/lesson/lang/zh-tw.json b/www/addons/mod/lesson/lang/zh-tw.json index 42b9529905a..bcbb5ed10a1 100644 --- a/www/addons/mod/lesson/lang/zh-tw.json +++ b/www/addons/mod/lesson/lang/zh-tw.json @@ -1,5 +1,6 @@ { "answer": "答案", + "attempt": "作答:{{$a}}", "attemptheader": "作答", "attemptsremaining": "您還有{{$a}}次作答機會", "averagescore": "平均分數", @@ -35,7 +36,7 @@ "loginfail": "登入錯誤,請重試", "lowscore": "最低分數", "lowtime": "最短時間", - "maximumnumberofattemptsreached": "達到嘗試次數上限 - 請進入下一頁", + "maximumnumberofattemptsreached": "已達到作答次的上限 - 將進入下一頁", "modattemptsnoteacher": "學生回顧功能只開放給學生們。", "noanswer": "有一個或以上的問題沒有回答。請回頭並提交一個答案。", "nolessonattempts": "這個課程還沒有人嘗試。", @@ -47,7 +48,7 @@ "ongoingcustom": "目前的{{$a.currenthigh}}分中,您已獲得{{$a.score}}分。", "ongoingnormal": "到目前為止的{{$a.viewed}}問題中,您答對了{{$a.correct}}題。", "or": "或", - "overview": "概要", + "overview": "綜覽", "preview": "預覽", "progressbarteacherwarning2": "你不能看到這進度列,因為你可以編輯這一編序學習。", "progresscompleted": "在這一編序學習,你已經完成{{$a}}%", diff --git a/www/addons/mod/lesson/main.js b/www/addons/mod/lesson/main.js index e786c188432..fae4bc2fefd 100644 --- a/www/addons/mod/lesson/main.js +++ b/www/addons/mod/lesson/main.js @@ -83,6 +83,7 @@ angular.module('mm.addons.mod_lesson', ['mm.core']) $mmCoursePrefetchDelegateProvider.registerPrefetchHandler('mmaModLesson', 'lesson', '$mmaModLessonPrefetchHandler'); $mmContentLinksDelegateProvider.registerLinkHandler('mmaModLesson:view', '$mmaModLessonHandlers.viewLinksHandler'); $mmContentLinksDelegateProvider.registerLinkHandler('mmaModLesson:overview', '$mmaModLessonHandlers.overviewLinksHandler'); + $mmContentLinksDelegateProvider.registerLinkHandler('mmaModLesson:grade', '$mmaModLessonHandlers.gradeLinksHandler'); }) .run(function($mmCronDelegate) { diff --git a/www/addons/mod/lesson/services/handlers.js b/www/addons/mod/lesson/services/handlers.js index f1308aa0422..61fb53e1c37 100644 --- a/www/addons/mod/lesson/services/handlers.js +++ b/www/addons/mod/lesson/services/handlers.js @@ -98,9 +98,10 @@ angular.module('mm.addons.mod_lesson') $mmaModLessonPrefetchHandler.getDownloadSize(module, courseId).then(function(size) { $mmUtil.confirmDownloadSize(size).then(function() { - $mmaModLessonPrefetchHandler.prefetch(module, courseId).catch(function(error) { + return $mmaModLessonPrefetchHandler.prefetch(module, courseId).catch(function(error) { if (!$scope.$$destroyed) { $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true); + return $q.reject(); } }); }).catch(function() { @@ -363,5 +364,60 @@ angular.module('mm.addons.mod_lesson') }); } + /** + * Content links handler for lesson grade link. + * + * @module mm.addons.mod_lesson + * @ngdoc method + * @name $mmaModLessonHandlers#gradeLinksHandler + */ + self.gradeLinksHandler = $mmContentLinksHelper.createModuleGradeLinkHandler('mmaModLesson', 'lesson', $mmaModLesson, viewGrade); + + /** + * Treat a grade link to a user different than current one. + * + * @param {String} url URL to treat. + * @param {Object} params Params of the URL. + * @param {Number} [courseId] Course ID related to the URL. + * @param {String} siteId Site ID. + * @return {[type]} [description] + */ + function viewGrade(url, params, courseId, siteId) { + siteId = siteId || $mmSite.getId(); + + var moduleId = parseInt(params.id, 10), + modal = $mmUtil.showModalLoading(), + module; + + return $mmCourse.getModuleBasicInfo(moduleId, siteId).then(function(mod) { + module = mod; + courseId = module.course || courseId || params.courseid || params.cid; + + // Check if the user can see the user reports in the lesson. + return $mmaModLesson.getAccessInformation(module.instance); + }).then(function(info) { + if (info.canviewreports) { + // User can view reports, go to view the report. + return $state.go('redirect', { + siteid: siteId, + state: 'site.mod_lesson-userretake', + params: { + courseid: courseId, + lessonid: module.instance, + userid: parseInt(params.userid, 10) + } + }); + } else { + // User cannot view the report, go to lesson index. + return $mmCourseHelper.navigateToModule(moduleId, siteId, courseId, module.section); + } + }).catch(function(error) { + $mmUtil.showErrorModalDefault(error, 'mm.course.errorgetmodule', true); + return $q.reject(); + }).finally(function() { + modal.dismiss(); + }); + } + return self; }); diff --git a/www/addons/mod/lesson/services/helper.js b/www/addons/mod/lesson/services/helper.js index 7999d10a59e..4cbe8b8c462 100644 --- a/www/addons/mod/lesson/services/helper.js +++ b/www/addons/mod/lesson/services/helper.js @@ -93,8 +93,7 @@ angular.module('mm.addons.mod_lesson') var buttons = [], rootElement = document.createElement('div'), buttonsContainer, - forms, - isLegacy = false; + forms; // Get the container of the buttons if it exists. rootElement.innerHTML = html; @@ -106,14 +105,12 @@ angular.module('mm.addons.mod_lesson') // No buttons found. return buttons; } - isLegacy = true; buttonsContainer = rootElement; } forms = buttonsContainer.querySelectorAll('form'); angular.forEach(forms, function(form) { - var buttonSelector = isLegacy ? 'input[type="submit"]' : 'button[type="submit"]', - buttonEl = form.querySelector(buttonSelector), + var buttonEl = form.querySelector('input[type="submit"], button[type="submit"]'), inputs = form.querySelectorAll('input'), button; @@ -125,7 +122,7 @@ angular.module('mm.addons.mod_lesson') button = { id: buttonEl.id, title: buttonEl.title || buttonEl.value, - content: isLegacy ? buttonEl.value : buttonEl.innerHTML.trim(), + content: buttonEl.tagName == 'INPUT' ? buttonEl.value : buttonEl.innerHTML.trim(), data: {} }; @@ -141,6 +138,31 @@ angular.module('mm.addons.mod_lesson') return buttons; }; + /** + * Given a page data (result of getPageData), get the page contents. + * + * @module mm.addons.mod_lesson + * @ngdoc method + * @name $mmaModLessonHelper#getPageContentsFromPageData + * @param {Object} data Page data. + * @return {String} Page contents. + */ + self.getPageContentsFromPageData = function(data) { + var contents, + rootElement = document.createElement('div'); + + // Search the page contents inside the whole page HTML. Use data.pagecontent because it's filtered. + rootElement.innerHTML = data.pagecontent; + contents = rootElement.querySelector('.contents'); + + if (contents) { + return contents.innerHTML.trim(); + } + + // Cannot find contents element, return the page.contents (some elements like videos might not work). + return data.page.contents; + }; + /** * Given the HTML of an answer from a question page, extract the data to render the answer. * diff --git a/www/addons/mod/lti/lang/ja.json b/www/addons/mod/lti/lang/ja.json new file mode 100644 index 00000000000..b3e5bba2e60 --- /dev/null +++ b/www/addons/mod/lti/lang/ja.json @@ -0,0 +1,5 @@ +{ + "errorgetlti": "モジュールデータ取得中にエラーが発生しました。", + "errorinvalidlaunchurl": "起動するURLが不正です。", + "launchactivity": "アクティビティを起動" +} \ No newline at end of file diff --git a/www/addons/mod/lti/lang/sr-cr.json b/www/addons/mod/lti/lang/sr-cr.json new file mode 100644 index 00000000000..6f616981561 --- /dev/null +++ b/www/addons/mod/lti/lang/sr-cr.json @@ -0,0 +1,5 @@ +{ + "errorgetlti": "Грешка приликом преузимања података модула.", + "errorinvalidlaunchurl": "Иницијална URL адреса није исправна.", + "launchactivity": "Покрени активност" +} \ No newline at end of file diff --git a/www/addons/mod/lti/lang/sr-lt.json b/www/addons/mod/lti/lang/sr-lt.json new file mode 100644 index 00000000000..0feaaf89a14 --- /dev/null +++ b/www/addons/mod/lti/lang/sr-lt.json @@ -0,0 +1,5 @@ +{ + "errorgetlti": "Greška prilikom preuzimanja podataka modula.", + "errorinvalidlaunchurl": "Inicijalna URL adresa nije ispravna.", + "launchactivity": "Pokreni aktivnost" +} \ No newline at end of file diff --git a/www/addons/mod/lti/lang/uk.json b/www/addons/mod/lti/lang/uk.json index cc542981fd4..8569afbe6c1 100644 --- a/www/addons/mod/lti/lang/uk.json +++ b/www/addons/mod/lti/lang/uk.json @@ -1,5 +1,5 @@ { "errorgetlti": "Помилка при отриманні даних модуля.", - "errorinvalidlaunchurl": "Запуск URL не є дійсним.", + "errorinvalidlaunchurl": "Цей URL не є дійсним.", "launchactivity": "Запуск діяльності" } \ No newline at end of file diff --git a/www/addons/mod/page/lang/es_mx.json b/www/addons/mod/page/lang/es_mx.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/www/addons/mod/page/lang/es_mx.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/www/addons/mod/page/lang/ja.json b/www/addons/mod/page/lang/ja.json index 0637a088a01..4084af15212 100644 --- a/www/addons/mod/page/lang/ja.json +++ b/www/addons/mod/page/lang/ja.json @@ -1 +1,3 @@ -[] \ No newline at end of file +{ + "errorwhileloadingthepage": "ページ内容を読み込み中にエラーが発生しました。" +} \ No newline at end of file diff --git a/www/addons/mod/page/lang/pt_br.json b/www/addons/mod/page/lang/pt_br.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/www/addons/mod/page/lang/pt_br.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/www/addons/mod/page/lang/sr-cr.json b/www/addons/mod/page/lang/sr-cr.json new file mode 100644 index 00000000000..bb2b30f0d8b --- /dev/null +++ b/www/addons/mod/page/lang/sr-cr.json @@ -0,0 +1,3 @@ +{ + "errorwhileloadingthepage": "Грешка приликом учитавања садржаја странице." +} \ No newline at end of file diff --git a/www/addons/mod/page/lang/sr-lt.json b/www/addons/mod/page/lang/sr-lt.json new file mode 100644 index 00000000000..683b241e992 --- /dev/null +++ b/www/addons/mod/page/lang/sr-lt.json @@ -0,0 +1,3 @@ +{ + "errorwhileloadingthepage": "Greška prilikom učitavanja sadržaja stranice." +} \ No newline at end of file diff --git a/www/addons/mod/page/lang/zh_cn.json b/www/addons/mod/page/lang/zh_cn.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/www/addons/mod/page/lang/zh_cn.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/www/addons/mod/page/lang/zh_tw.json b/www/addons/mod/page/lang/zh_tw.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/www/addons/mod/page/lang/zh_tw.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/www/addons/mod/quiz/lang/ja.json b/www/addons/mod/quiz/lang/ja.json index f7b4d3d133f..62382e648d4 100644 --- a/www/addons/mod/quiz/lang/ja.json +++ b/www/addons/mod/quiz/lang/ja.json @@ -4,32 +4,49 @@ "attemptnumber": "受験", "attemptquiznow": "問題を受験する", "attemptstate": "状態", + "cannotsubmitquizdueto": "このクイズの回答は、以下の理由で提出できませんでした:", "comment": "コメント", "completedon": "完了日時", - "confirmclose": "送信した場合、この受験に関して、これ以上あなたの答えを変更することはできません。", + "confirmclose": "送信した場合、あなたはこれ以上受験の答えを変更できないようになります。", + "confirmcontinueoffline": "この回答は、理由「 {{$a}} 」により、同期できませんでした。もしあなたが別のデバイスで回答を続けていた場合、データが失われている可能性があります。", + "confirmleavequizonerror": "回答の保存中にエラーが発生しました。クイズを終了してもよいですか?", "confirmstart": "この小テストには {{$a}} の時間制限があります。あなたが受験を開始した時点から時間が計測されます。あなたは有効期限前に送信する必要があります。今から開始してもよろしいですか?", "confirmstartheader": "時間制限小テスト", - "connectionerror": "ネットワークコネクションが切断されました (オートセーブ失敗)。\n\nこのページで入力した最後の数分間の解答をメモした後、再接続を試みてください。\n\n接続が再確立された場合、あなたの解答は保存され、このメッセージは表示されなくなります。", + "connectionerror": "ネットワークコネクションが切断されました (オートセーブ失敗)。\n\nこのページで入力した最後の数分間の解答をメモした後、再接続を試みてください。\n\n再度接続が確立された場合、あなたの解答は保存されこのメッセージは表示されなくなります。", "continueattemptquiz": "前回の受験を続ける", - "continuepreview": "前回受験のプレビューを続ける", + "continuepreview": "前回のプレビューを続ける", + "errorbehaviournotsupported": "このクイズは、アプリでサポートされていない動作が含まれているため回答することができません。", + "errordownloading": "必要なデータのダウンロード中にエラーが発生しました。", + "errorgetattempt": "回答データの取得中にエラーが発生しました。", + "errorgetquestions": "質問の取得中にエラーが発生しました。", + "errorgetquiz": "クイズデータの取得中にエラーが発生しました。", + "errorparsequestions": "質問の読み込み中にエラーが発生しました。Webブラウザからこのクイズに回答してください。", + "errorquestionsnotsupported": "このクイズは、アプリでサポートされていない質問を含む可能性があるため回答することができません。", + "errorrulesnotsupported": "このクイズは、アプリでサポートされていないアクセスルールがあるため回答することができません。", + "errorsaveattempt": "回答データの保存中にエラーが発生しました。", + "errorsyncquiz": "同期中にエラーが発生しました。再度同期してください。", + "errorsyncquizblocked": "このクイズは、進行中のプロセスがあるためすぐには同期できません。後で再び同期してください。この問題が連続する場合、アプリを再起動してみてください。", "feedback": "フィードバック", "finishattemptdots": "受験を終了する ...", + "finishnotsynced": "完了しましたが同期されていません。", "grade": "評点", "gradeaverage": "平均評点", "gradehighest": "最高評点", "grademethod": "評定方法", "gradesofar": "{{$a.method}}: {{$a.mygrade}} / {{$a.quizgrade}}", + "hasdatatosync": "このクイズには同期が必要なオフラインデータがあります。", "marks": "得点", "mustbesubmittedby": "この受験は {{$a}} までに送信される必要があります。", "noquestions": "まだ問題が追加されていません。", "noreviewattempt": "あなたはこの受験のレビューを許可されていません。", "notyetgraded": "未評定", + "opentoc": "ナビゲーションポップオーバーを開いてください。", "outof": "{{$a.grade}} / {{$a.maxgrade}}", "outofpercent": "{{$a.grade}} / {{$a.maxgrade}} ({{$a.percent}}%)", "outofshort": "{{$a.grade}} / {{$a.maxgrade}}", "overallfeedback": "全体のフィードバック", "overdue": "期限切れ", - "overduemustbesubmittedby": "この受験は制限時間を過ぎています。そして、すでに送信されている必要があります。あなたがこの小テストの評定を希望する場合、{{$a}} までに送信してください。それまでに送信しない場合、この受験の評点はカウントされません。", + "overduemustbesubmittedby": "この受験は制限時間を過ぎています。この受験はすでに送信されている必要があります。あなたがこの小テストの評定を希望する場合、{{$a}} までに送信してください。それまでに送信しない場合、この受験の評点はカウントされません。", "preview": "プレビュー", "previewquiznow": "小テストをプレビューする", "question": "問題", @@ -56,5 +73,8 @@ "summaryofattempts": "あなたの前回の受験概要", "timeleft": "残り時間", "timetaken": "所要時間", + "warningattemptfinished": "オフラインの回答は、サイト上で完了していた、もしくは見当たらなかったため廃棄されました。", + "warningdatadiscarded": "質問文がオンラインで変更されたため、一部のオフライン回答が廃棄されました。", + "warningdatadiscardedfromfinished": "オフライン回答が廃棄されたため、回答が完了していません。回答内容を確認し、回答を再度提出してください。", "yourfinalgradeis": "あなたの小テスト最終評点は {{$a}} です。" } \ No newline at end of file diff --git a/www/addons/mod/quiz/lang/lt.json b/www/addons/mod/quiz/lang/lt.json index 3d18000f600..0e24a274c6e 100644 --- a/www/addons/mod/quiz/lang/lt.json +++ b/www/addons/mod/quiz/lang/lt.json @@ -46,6 +46,7 @@ "outofshort": "{{$a.grade}}/{{$a.maxgrade}}", "overallfeedback": "Bendras atsiliepimas", "overdue": "Uždelstas", + "overduemustbesubmittedby": "Šis bandymas jau pavėluotas. Jis jau turėjo būti pateiktas. Jei norite, kad šis testas būtų įvertintas, turite jį patvirtinti {{$a}}. Jei nepateiksite, tada balas šiam bandymui nebus skaičiuojamas.", "preview": "Peržiūra", "previewquiznow": "Peržiūrėti testą dabar", "question": "Klausimas", diff --git a/www/addons/mod/quiz/lang/sr-cr.json b/www/addons/mod/quiz/lang/sr-cr.json new file mode 100644 index 00000000000..41be728b1ad --- /dev/null +++ b/www/addons/mod/quiz/lang/sr-cr.json @@ -0,0 +1,80 @@ +{ + "attemptfirst": "Први покушај", + "attemptlast": "Последњи покушај", + "attemptnumber": "Покушај", + "attemptquiznow": "Започни тест", + "attemptstate": "Стање", + "cannotsubmitquizdueto": "Овај покушај решавања теста не може да буде предат због следећих разлога:", + "comment": "Коментар", + "completedon": "Завршено дана", + "confirmclose": "Када предате тест нећете више бити у могућности да мењате своје одговоре.", + "confirmcontinueoffline": "Овај покушај није синхронизован од {{$a}}. Ако сте у међувремену овај покушај наставили на неком другом уређају, постоји могућност да сте изгубили податке.", + "confirmleavequizonerror": "Дошло је до грешке приликом покушаја да се сачувају одговори. Да ли сте сигурни да желите да напустите тест?", + "confirmstart": "Тест има временско ограничење ({{$a}}). Време ће се одбројавати од момента почетка покушаја и морате предати своје одговоре пре него што истекне. Да ли сте сигурни да сада желите да започнете решавање теста?", + "confirmstartheader": "Временски ограничен тест", + "connectionerror": "Мрежна веза је изгубљена. (Аутоматско чување није успело).\n\nЗапишите све одговора унетих на овој страници у последњих неколико минута, а затим покушајте поново да се повежете.\n\nКада се веза поново успостави ваши одговори би требало да буду сачувани а ова порука ће нестати.", + "continueattemptquiz": "Наставите последњи покушај", + "continuepreview": "Настави последњи преглед", + "errorbehaviournotsupported": "Овај тест не можете решавати у апликацији зато што она не подржава понашање питања:", + "errordownloading": "Грешка приликом преузимања неопходних података.", + "errorgetattempt": "Грешка приликом преузимања података о покушају решавања теста.", + "errorgetquestions": "Грешка приликом преузимања питања.", + "errorgetquiz": "Грешка приликом преузимања података о тесту.", + "errorparsequestions": "Дошло је до грешке приликом учитавања питања. Молимо, покушајте да решите овај тест у веб читачу.", + "errorquestionsnotsupported": "Овај тест се не може решавати у апликацији зато што садржи питања које апликација не подржава:", + "errorrulesnotsupported": "Овај тест се не може решавати у апликацији зато што садржи правила за приступ које апликација не подржава:", + "errorsaveattempt": "Дошло је до грешке приликом снимања података о покушају решавања теста.", + "errorsyncquiz": "Дошло је до грешке приликом синхронизације. Молимо, покушајте поново.", + "errorsyncquizblocked": "Овај тест сада не може бити синхронизован због другог процеса који је тренутно у току. Молимо, покушајте поново касније. Ако и даље будете имали проблема, покушајте да покренете апликацију испочетка.", + "feedback": "Повратне информације", + "finishattemptdots": "Заврши покушај...", + "finishnotsynced": "Тест је завршен, али није синхронизован", + "grade": "Оцена", + "gradeaverage": "Просечна оцена", + "gradehighest": "Највиша оцена", + "grademethod": "Метод оцењивања", + "gradesofar": "{{$a.method}}: {{$a.mygrade}} / {{$a.quizgrade}}.", + "hasdatatosync": "Овај тест има офлајн податке које треба синхронизовати.", + "marks": "Оцене", + "mustbesubmittedby": "Овај покушај мора бити предат до {{$a}}.", + "noquestions": "Ниједно питање још није додато", + "noreviewattempt": "Није Вам дозвољено да прегледате овај покушај", + "notyetgraded": "Још није оцењено", + "opentoc": "Отвори навигациони мени.", + "outof": "{{$a.grade}} од {{$a.maxgrade}}", + "outofpercent": "{{$a.grade}} од {{$a.maxgrade}}", + "outofshort": "{{$a.grade}}/{{$a.maxgrade}}", + "overallfeedback": "Свеобухватне повратне информације", + "overdue": "Закаснели", + "overduemustbesubmittedby": "Време за овај покушај решавање теста је истекло. Покушај је већ требало предати. Ако желите да овај тест буде оцењен морате га предати до {{$a}}. Ако то не урадите до наведеног рока, оцене за овај покушај се неће рачунати.", + "preview": "Преглед", + "previewquiznow": "Прегледај тест сада", + "question": "Питање", + "quizpassword": "Лозинка теста", + "reattemptquiz": "Поновни покушај решавања теста", + "requirepasswordmessage": "Да бисте приступили решавању овог теста морате знати лозинку теста", + "returnattempt": "Повратак на покушај", + "review": "Преглед", + "reviewofattempt": "Преглед покушаја {{$a}}", + "reviewofpreview": "Преглед приказа", + "showall": "Прикажи сва питања на једној страници", + "showeachpage": "Прикажи једну по једну страницу", + "startattempt": "Започни покушај решавања", + "startedon": "Започето", + "stateabandoned": "Никад предато", + "statefinished": "Завршено", + "statefinisheddetails": "Предато {{$a}}", + "stateinprogress": "У току", + "stateoverdue": "Закаснела предаја", + "stateoverduedetails": "Мора се предати до {{$a}}", + "status": "Статус", + "submitallandfinish": "Предај све одговоре и заврши тест", + "summaryofattempt": "Резиме покушаја", + "summaryofattempts": "Резиме ваших претходних покушаја", + "timeleft": "Преостало време", + "timetaken": "Утрошено време", + "warningattemptfinished": "Офлајн покушај је одбачен зато што је или завршен на сајту или није пронађен.", + "warningdatadiscarded": "Неки офлајн одговори су одбачени зато што су питања измењена онлајн.", + "warningdatadiscardedfromfinished": "Покушај решавања теста је није завршен зато што су неки офлајн одговори одбачени. Прегледајте своје одговоре, а затим поново пошаљите свој покушај.", + "yourfinalgradeis": "Ваша коначна оцена на овом тесту је {{$a}}." +} \ No newline at end of file diff --git a/www/addons/mod/quiz/lang/sr-lt.json b/www/addons/mod/quiz/lang/sr-lt.json new file mode 100644 index 00000000000..0bff65e68b6 --- /dev/null +++ b/www/addons/mod/quiz/lang/sr-lt.json @@ -0,0 +1,80 @@ +{ + "attemptfirst": "Prvi pokušaj", + "attemptlast": "Poslednji pokušaj", + "attemptnumber": "Pokušaj", + "attemptquiznow": "Započni test", + "attemptstate": "Stanje", + "cannotsubmitquizdueto": "Ovaj pokušaj rešavanja testa ne može da bude predat zbog sledećih razloga:", + "comment": "Komentar", + "completedon": "Završeno dana", + "confirmclose": "Kada predate test nećete više biti u mogućnosti da menjate svoje odgovore.", + "confirmcontinueoffline": "Ovaj pokušaj nije sinhronizovan od {{$a}}. Ako ste u međuvremenu ovaj pokušaj nastavili na nekom drugom uređaju, postoji mogućnost da ste izgubili podatke.", + "confirmleavequizonerror": "Došlo je do greške prilikom pokušaja da se sačuvaju odgovori. Da li ste sigurni da želite da napustite test?", + "confirmstart": "Test ima vremensko ograničenje ({{$a}}). Vreme će se odbrojavati od momenta početka pokušaja i morate predati svoje odgovore pre nego što istekne. Da li ste sigurni da sada želite da započnete rešavanje testa?", + "confirmstartheader": "Vremenski ograničen test", + "connectionerror": "Mrežna veza je izgubljena. (Automatsko čuvanje nije uspelo).\n\nZapišite sve odgovora unetih na ovoj stranici u poslednjih nekoliko minuta, a zatim pokušajte ponovo da se povežete.\n\nKada se veza ponovo uspostavi vaši odgovori bi trebalo da budu sačuvani a ova poruka će nestati.", + "continueattemptquiz": "Nastavite poslednji pokušaj", + "continuepreview": "Nastavi poslednji pregled", + "errorbehaviournotsupported": "Ovaj test ne možete rešavati u aplikaciji zato što ona ne podržava ponašanje pitanja:", + "errordownloading": "Greška prilikom preuzimanja neophodnih podataka.", + "errorgetattempt": "Greška prilikom preuzimanja podataka o pokušaju rešavanja testa.", + "errorgetquestions": "Greška prilikom preuzimanja pitanja.", + "errorgetquiz": "Greška prilikom preuzimanja podataka o testu.", + "errorparsequestions": "Došlo je do greške prilikom učitavanja pitanja. Molimo, pokušajte da rešite ovaj test u veb čitaču.", + "errorquestionsnotsupported": "Ovaj test se ne može rešavati u aplikaciji zato što sadrži pitanja koje aplikacija ne podržava:", + "errorrulesnotsupported": "Ovaj test se ne može rešavati u aplikaciji zato što sadrži pravila za pristup koje aplikacija ne podržava:", + "errorsaveattempt": "Došlo je do greške prilikom snimanja podataka o pokušaju rešavanja testa.", + "errorsyncquiz": "Došlo je do greške prilikom sinhronizacije. Molimo, pokušajte ponovo.", + "errorsyncquizblocked": "Ovaj test sada ne može biti sinhronizovan zbog drugog procesa koji je trenutno u toku. Molimo, pokušajte ponovo kasnije. Ako i dalje budete imali problema, pokušajte da pokrenete aplikaciju ispočetka.", + "feedback": "Povratne informacije", + "finishattemptdots": "Završi pokušaj...", + "finishnotsynced": "Test je završen, ali nije sinhronizovan", + "grade": "Ocena", + "gradeaverage": "Prosečna ocena", + "gradehighest": "Najviša ocena", + "grademethod": "Metod ocenjivanja", + "gradesofar": "{{$a.method}}: {{$a.mygrade}} / {{$a.quizgrade}}.", + "hasdatatosync": "Ovaj test ima oflajn podatke koje treba sinhronizovati.", + "marks": "Ocene", + "mustbesubmittedby": "Ovaj pokušaj mora biti predat do {{$a}}.", + "noquestions": "Nijedno pitanje još nije dodato", + "noreviewattempt": "Nije Vam dozvoljeno da pregledate ovaj pokušaj", + "notyetgraded": "Još nije ocenjeno", + "opentoc": "Otvori navigacioni meni.", + "outof": "{{$a.grade}} od {{$a.maxgrade}}", + "outofpercent": "{{$a.grade}} od {{$a.maxgrade}}", + "outofshort": "{{$a.grade}}/{{$a.maxgrade}}", + "overallfeedback": "Sveobuhvatne povratne informacije", + "overdue": "Zakasneli", + "overduemustbesubmittedby": "Vreme za ovaj pokušaj rešavanje testa je isteklo. Pokušaj je već trebalo predati. Ako želite da ovaj test bude ocenjen morate ga predati do {{$a}}. Ako to ne uradite do navedenog roka, ocene za ovaj pokušaj se neće računati.", + "preview": "Pregled", + "previewquiznow": "Pregledaj test sada", + "question": "Pitanje", + "quizpassword": "Lozinka testa", + "reattemptquiz": "Ponovni pokušaj rešavanja testa", + "requirepasswordmessage": "Da biste pristupili rešavanju ovog testa morate znati lozinku testa", + "returnattempt": "Povratak na pokušaj", + "review": "Pregled", + "reviewofattempt": "Pregled pokušaja {{$a}}", + "reviewofpreview": "Pregled prikaza", + "showall": "Prikaži sva pitanja na jednoj stranici", + "showeachpage": "Prikaži jednu po jednu stranicu", + "startattempt": "Započni pokušaj rešavanja", + "startedon": "Započeto", + "stateabandoned": "Nikad predato", + "statefinished": "Završeno", + "statefinisheddetails": "Predato {{$a}}", + "stateinprogress": "U toku", + "stateoverdue": "Zakasnela predaja", + "stateoverduedetails": "Mora se predati do {{$a}}", + "status": "Status", + "submitallandfinish": "Predaj sve odgovore i završi test", + "summaryofattempt": "Rezime pokušaja", + "summaryofattempts": "Rezime vaših prethodnih pokušaja", + "timeleft": "Preostalo vreme", + "timetaken": "Utrošeno vreme", + "warningattemptfinished": "Oflajn pokušaj je odbačen zato što je ili završen na sajtu ili nije pronađen.", + "warningdatadiscarded": "Neki oflajn odgovori su odbačeni zato što su pitanja izmenjena onlajn.", + "warningdatadiscardedfromfinished": "Pokušaj rešavanja testa je nije završen zato što su neki oflajn odgovori odbačeni. Pregledajte svoje odgovore, a zatim ponovo pošaljite svoj pokušaj.", + "yourfinalgradeis": "Vaša konačna ocena na ovom testu je {{$a}}." +} \ No newline at end of file diff --git a/www/addons/mod/quiz/lang/sv.json b/www/addons/mod/quiz/lang/sv.json index cb771aab8be..f330a8a5999 100644 --- a/www/addons/mod/quiz/lang/sv.json +++ b/www/addons/mod/quiz/lang/sv.json @@ -6,7 +6,7 @@ "attemptstate": "Tillstånd", "comment": "Kommentar", "completedon": "Fullgjord den", - "confirmclose": "Du håller på att avsluta det här försöket. När Du väl har avslutat försöket kommer Du inte längre att kunna ändra Dina svar.", + "confirmclose": "dDu håller på att avsluta det här försöket. När du väl har avslutat försöket kommer du inte längre att kunna ändra dina svar.", "connectionerror": "Nätverksanslutning förlorade (autospara misslyckades).\n\nAnteckna alla svar som angavs på webbplatsen de sista minuterna på papper, försöka sedan att återansluta.\n\nNär anslutningen har återupprättats, bör dina svar sparas och detta meddelande kommer att försvinna.", "continueattemptquiz": "Fortsätt med det senaste försöket", "continuepreview": "Fortsätt med den senaste förhandsgranskningen", diff --git a/www/addons/mod/quiz/lang/uk.json b/www/addons/mod/quiz/lang/uk.json index 3c6c7b28f67..33bfc0688f7 100644 --- a/www/addons/mod/quiz/lang/uk.json +++ b/www/addons/mod/quiz/lang/uk.json @@ -8,24 +8,24 @@ "comment": "Коментар", "completedon": "Завершено", "confirmclose": "Ви вибрали закінчення тесту (даної спроби). Якщо ви це підтверджуєте, Ви більше не зможете змінювати ваші відповіді.", - "confirmcontinueoffline": "Ця спроба не була синхронізована, {{$a}}. Якщо ви продовжили цю спробу в іншому пристрої з тих пір, ви можете втратити дані.", + "confirmcontinueoffline": "Ця спроба не була синхронізована, {{$a}}. Якщо ви продовжили цю спробу на іншому пристрої, ви можете втратити дані.", "confirmleavequizonerror": "При збереженні відповідей сталася помилка. Ви впевнені, що хочете залишити тест?", "confirmstart": "Цей тест має обмеження в часі {{$a}}. Час почне відраховуватися з моменту, коли ви починаєте вашу спробу, і ви повинні будете закінчити вашу спробу допоки не спливе термін. Ви впевнені, що хочете почати зараз?", "confirmstartheader": "Тест з обмеженням в часі", "connectionerror": "Мережеве підключення втрачено. (Автозбереження не вдалося).\n\nЗапишіть відповіді введені на цій сторінці за останні кілька хвилин, потім спробуйте знову підключити.\n\nПісля того, як з'єднання буде відновлено, ваші відповіді мають бути збережені і це повідомлення зникне.", "continueattemptquiz": "Продовжити останню спробу", "continuepreview": "Продовжити останній перегляд", - "errorbehaviournotsupported": "Цей тест не може бути зроблений в додатку, тому що поведінка не підтримуються додатком:", + "errorbehaviournotsupported": "Цей тест не може бути зроблений в додатку, тому що не підтримується додатком:", "errordownloading": "Помилка при завантаженні потрібних даних.", "errorgetattempt": "Помилка при отриманні даних спроби.", "errorgetquestions": "Помилка отримання питань.", "errorgetquiz": "Помилка при отриманні даних тесту.", - "errorparsequestions": "Сталася помилка під час читання питання. Будь ласка, спроба цей тест в веб-браузері.", + "errorparsequestions": "Сталася помилка під час читання питання. Будь ласка, спробуйте цей тест в веб-браузері.", "errorquestionsnotsupported": "Цей тест не може бути вирішених в додатку, оскільки він може містити питання, які не підтримуються додатком:", - "errorrulesnotsupported": "Цей тест не може бути зроблений в додатку, оскільки він має правило доступу, що не підтримується додатком:", + "errorrulesnotsupported": "Цей тест не може бути зроблений в додатку, оскільки він має правила доступу, що не підтримується додатком:", "errorsaveattempt": "При збереженні даних спроби сталася помилка.", "errorsyncquiz": "Під час синхронізації сталася помилка. Будь ласка спробуйте ще раз.", - "errorsyncquizblocked": "Цей тест не може бути синхронізований прямо зараз через триваючий процес. Будь-ласка спробуйте пізніше. Якщо питання залишається невирішеним, спробуйте перезапустити програму.", + "errorsyncquizblocked": "Цей тест не може бути синхронізований прямо зараз через навантаження на сервер. Будь-ласка спробуйте пізніше. Якщо питання залишається невирішеним, спробуйте перезапустити програму.", "feedback": "Відгук", "finishattemptdots": "Завершити спробу...", "finishnotsynced": "Готово, але не синхронізовано", diff --git a/www/addons/mod/resource/lang/es_mx.json b/www/addons/mod/resource/lang/es_mx.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/www/addons/mod/resource/lang/es_mx.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/www/addons/mod/resource/lang/ja.json b/www/addons/mod/resource/lang/ja.json index 0637a088a01..8a0d7d9a02d 100644 --- a/www/addons/mod/resource/lang/ja.json +++ b/www/addons/mod/resource/lang/ja.json @@ -1 +1,4 @@ -[] \ No newline at end of file +{ + "errorwhileloadingthecontent": "内容を読み込み中にエラーが発生しました。", + "openthefile": "ファイルを開く" +} \ No newline at end of file diff --git a/www/addons/mod/resource/lang/pt_br.json b/www/addons/mod/resource/lang/pt_br.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/www/addons/mod/resource/lang/pt_br.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/www/addons/mod/resource/lang/sr-cr.json b/www/addons/mod/resource/lang/sr-cr.json new file mode 100644 index 00000000000..260ac7e4935 --- /dev/null +++ b/www/addons/mod/resource/lang/sr-cr.json @@ -0,0 +1,4 @@ +{ + "errorwhileloadingthecontent": "Грешка приликом учитавања садржаја.", + "openthefile": "Отвори датотеку" +} \ No newline at end of file diff --git a/www/addons/mod/resource/lang/sr-lt.json b/www/addons/mod/resource/lang/sr-lt.json new file mode 100644 index 00000000000..8120d454e8a --- /dev/null +++ b/www/addons/mod/resource/lang/sr-lt.json @@ -0,0 +1,4 @@ +{ + "errorwhileloadingthecontent": "Greška prilikom učitavanja sadržaja.", + "openthefile": "Otvori datoteku" +} \ No newline at end of file diff --git a/www/addons/mod/resource/lang/zh_cn.json b/www/addons/mod/resource/lang/zh_cn.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/www/addons/mod/resource/lang/zh_cn.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/www/addons/mod/resource/lang/zh_tw.json b/www/addons/mod/resource/lang/zh_tw.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/www/addons/mod/resource/lang/zh_tw.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/www/addons/mod/scorm/controllers/index.js b/www/addons/mod/scorm/controllers/index.js index f73a74bf913..e4073952ac5 100644 --- a/www/addons/mod/scorm/controllers/index.js +++ b/www/addons/mod/scorm/controllers/index.js @@ -323,6 +323,7 @@ angular.module('mm.addons.mod_scorm') } } else if (progress.message) { // Show a message. $scope.progressMessage = progress.message; + $scope.percentage = undefined; } else if (progress.loaded && progress.total) { // Unzipping package. $scope.percentage = (parseFloat(progress.loaded / progress.total) * 100).toFixed(1); } else { @@ -418,9 +419,9 @@ angular.module('mm.addons.mod_scorm') if (!$scope.$$destroyed) { openScorm(scoId); } - }).catch(function() { + }).catch(function(error) { if (!$scope.$$destroyed) { - $mmaModScormHelper.showDownloadError(scorm); + $mmaModScormHelper.showDownloadError(scorm, error); } }); }); diff --git a/www/addons/mod/scorm/lang/el.json b/www/addons/mod/scorm/lang/el.json index a819301fbee..e5fbfbe4a46 100644 --- a/www/addons/mod/scorm/lang/el.json +++ b/www/addons/mod/scorm/lang/el.json @@ -46,5 +46,6 @@ "scormstatusnotdownloaded": "Αυτό το SCORM δεν έχει κατέβει. Θα κατέβει αυτόματα όταν το ανοίξετε.", "scormstatusoutdated": "Αυτό το SCORM έχει τροποποιηθεί από την τελευταία λήψη. Θα κατέβει αυτόματα όταν το ανοίξετε.", "suspended": "Αναστέλλεται", + "warningofflinedatadeleted": "Ορισμένα δεδομένα εκτός σύνδεσης της προσπάθειας {{number}} διαγράφηκαν επειδή δεν ήταν δυνατή η δημιουργία νέας προσπάθειας.", "warningsynconlineincomplete": "Κάποιες προσπάθειες δεν μπόρεσαν να συγχρονιστούν με το site διότι η τελευταία online προσπάθεια δεν έχει ολοκληρωθεί. Παρακαλώ τελειώστε την online προσπάθεια πρώτα." } \ No newline at end of file diff --git a/www/addons/mod/scorm/lang/eu.json b/www/addons/mod/scorm/lang/eu.json index d6315ef6681..cb26ace868a 100644 --- a/www/addons/mod/scorm/lang/eu.json +++ b/www/addons/mod/scorm/lang/eu.json @@ -20,7 +20,7 @@ "errorpackagefile": "Barkatu, aplikazioak ZIP paketeak besterik ez du onartzen.", "errorsyncscorm": "Errorea gertatu da sinkronizatzean. Mesedez, saiatu berriz.", "exceededmaxattempts": "Gehienezko saiakera-kopurua egin duzu.", - "failed": "Errorea", + "failed": "Gainditu gabea", "firstattempt": "Lehenengo saiakera", "gradeaverage": "Batez besteko kalifikazioa", "gradeforattempt": "Saikerarako kalifikazioa", diff --git a/www/addons/mod/scorm/lang/ja.json b/www/addons/mod/scorm/lang/ja.json index df57f44b198..031b2f60a58 100644 --- a/www/addons/mod/scorm/lang/ja.json +++ b/www/addons/mod/scorm/lang/ja.json @@ -6,9 +6,19 @@ "browse": "プレビュー", "browsed": "閲覧済み", "browsemode": "プレビューモード", + "cannotcalculategrade": "評定が計算できませんでした。", "completed": "完了", "contents": "コンテンツ", + "dataattemptshown": "このデータは回答番号 {{number}} に該当します。", "enter": "問題に入る", + "errorcreateofflineattempt": "新たなオフライン回答の作成中にエラーが発生しました。再度実行してください。", + "errordownloadscorm": "SCORM \"{{name}}\" のダウンロード中にエラーが発生しました。", + "errorgetscorm": "SCORMデータの取得中にエラーが発生しました。", + "errorinvalidversion": "申し訳ありません。アプリケーションはSCORM 1.2のみをサポートしています。", + "errornotdownloadable": "あなたのMoodleサイトではSCORMパッケージのダウンロードができません。Moodleサイト管理者に連絡してください。", + "errornovalidsco": "このSCORMはロードに必要な表示できるSCOがありません。", + "errorpackagefile": "申し訳ありません。アプリケーションはZIPパッケージのみをサポートしています。", + "errorsyncscorm": "同期中にエラーが発生しました。再度実行してください。", "exceededmaxattempts": "あなたは最大受験回数に達しました。", "failed": "不合格", "firstattempt": "最初の受験", @@ -28,8 +38,14 @@ "noattemptsmade": "あなたの受験回数", "normal": "ノーマル", "notattempted": "未受験", + "offlineattemptnote": "この回答には動悸されなかったデータがあります。", + "offlineattemptovermax": "受験可能回数を超えたため、この回答を送信できません。", "organizations": "組織", "passed": "合格", "reviewmode": "レビューモード", - "suspended": "一時停止" + "scormstatusnotdownloaded": "このSCORMはダウンロードされていません。これを開くときに、自動的にダウンロードされます。", + "scormstatusoutdated": "このSCORMは最後にダウンロードされた後に更新されています。開くときに、自動的に新しいものがダウンロードされます。", + "suspended": "一時停止", + "warningofflinedatadeleted": "回答番号 {{number}} を新しい回答として作成することができなかったため、オフラインデータの一部が消去されました。", + "warningsynconlineincomplete": "最終のオンライン回答が完了していないため、一部の回答が同期できませんでした。先にオンライン回答を完了してください。" } \ No newline at end of file diff --git a/www/addons/mod/scorm/lang/sr-cr.json b/www/addons/mod/scorm/lang/sr-cr.json new file mode 100644 index 00000000000..e35b5f6a6b6 --- /dev/null +++ b/www/addons/mod/scorm/lang/sr-cr.json @@ -0,0 +1,51 @@ +{ + "asset": "Елемент", + "assetlaunched": "Елемент - Прегледано", + "attempts": "Покушаји", + "averageattempt": "Просечни број покушаја", + "browse": "Преглед", + "browsed": "Претражено", + "browsemode": "Режим прегледа", + "cannotcalculategrade": "Оцена не може да се израчуна.", + "completed": "Завршено", + "contents": "Садржај", + "dataattemptshown": "Ови подаци припадају покушају број {{number}}.", + "enter": "Уђи", + "errorcreateofflineattempt": "Дошло је до грешке приликом покушаја креирања новог офлајн покушаја. Молимо, покушајте поново.", + "errordownloadscorm": "Грешка приликом преузимања SCORM пакета: \"{{name}}\".", + "errorgetscorm": "Грешка приликом преузимања података SCORM пакета.", + "errorinvalidversion": "Извините, апликација подржава само SCORM 1.2.", + "errornotdownloadable": "Преузимање SCORM пакета је онемогућено на вашем сајту. Молимо, обратите се администратору вашег Moodle сајта.", + "errornovalidsco": "Овај SCORM пакет нема видљив SCO који би био учитан.", + "errorpackagefile": "Извините, апликација подржава само ZIP архиве.", + "errorsyncscorm": "Дошло је до грешке приликом синхронизације. Молимо, покушајте поново.", + "exceededmaxattempts": "Достигли сте максималан број покушаја", + "failed": "Није успело", + "firstattempt": "Први покушај", + "gradeaverage": "Просечна оцена", + "gradeforattempt": "Оцена за покушај", + "gradehighest": "Највиша оцена", + "grademethod": "Метод оцењивања", + "gradereported": "Извештај о оценама", + "gradescoes": "Објекти за учење", + "gradesum": "Коначна оцена", + "highestattempt": "Најбољи покушај", + "incomplete": "Непотпуно", + "lastattempt": "Последњи завршени покушај", + "mode": "Режим рада", + "newattempt": "Почни нови покушај", + "noattemptsallowed": "Број дозвољених покушаја", + "noattemptsmade": "Број покушаја који сте имали", + "normal": "Нормално", + "notattempted": "Није покушавано", + "offlineattemptnote": "Овај покушај има податке који нису синхронизован.", + "offlineattemptovermax": "Овај покушај не може бити послат зато што сте премашили максималан број дозвољених покушаја.", + "organizations": "Организације", + "passed": "Положено", + "reviewmode": "Режим прегледа", + "scormstatusnotdownloaded": "Овај SCORM пакет није преузет. Биће аутоматски преузет када га отворите.", + "scormstatusoutdated": "Овај SCORM пакет је мењан од последњег преузимања. Биће аутоматски преузет када га отворите.", + "suspended": "Суспендовано", + "warningofflinedatadeleted": "Неки офлајн подаци о покушају {{number}} су обрисани зато што их није могуће креирати у новом покушају.", + "warningsynconlineincomplete": "Неки покушаји нису могли бити синхронизовани са сајтом зато што последњи онлине покушај није завршен. Молимо вас да прво завршите онлајн покушај." +} \ No newline at end of file diff --git a/www/addons/mod/scorm/lang/sr-lt.json b/www/addons/mod/scorm/lang/sr-lt.json new file mode 100644 index 00000000000..7f75f400c9b --- /dev/null +++ b/www/addons/mod/scorm/lang/sr-lt.json @@ -0,0 +1,51 @@ +{ + "asset": "Element", + "assetlaunched": "Element - Pregledano", + "attempts": "Pokušaji", + "averageattempt": "Prosečni broj pokušaja", + "browse": "Pregled", + "browsed": "Pretraženo", + "browsemode": "Režim pregleda", + "cannotcalculategrade": "Ocena ne može da se izračuna.", + "completed": "Završeno", + "contents": "Sadržaj", + "dataattemptshown": "Ovi podaci pripadaju pokušaju broj {{number}}.", + "enter": "Uđi", + "errorcreateofflineattempt": "Došlo je do greške prilikom pokušaja kreiranja novog oflajn pokušaja. Molimo, pokušajte ponovo.", + "errordownloadscorm": "Greška prilikom preuzimanja SCORM paketa: \"{{name}}\".", + "errorgetscorm": "Greška prilikom preuzimanja podataka SCORM paketa.", + "errorinvalidversion": "Izvinite, aplikacija podržava samo SCORM 1.2.", + "errornotdownloadable": "Preuzimanje SCORM paketa je onemogućeno na vašem sajtu. Molimo, obratite se administratoru vašeg Moodle sajta.", + "errornovalidsco": "Ovaj SCORM paket nema vidljiv SCO koji bi bio učitan.", + "errorpackagefile": "Izvinite, aplikacija podržava samo ZIP arhive.", + "errorsyncscorm": "Došlo je do greške prilikom sinhronizacije. Molimo, pokušajte ponovo.", + "exceededmaxattempts": "Dostigli ste maksimalan broj pokušaja", + "failed": "Nije uspelo", + "firstattempt": "Prvi pokušaj", + "gradeaverage": "Prosečna ocena", + "gradeforattempt": "Ocena za pokušaj", + "gradehighest": "Najviša ocena", + "grademethod": "Metod ocenjivanja", + "gradereported": "Izveštaj o ocenama", + "gradescoes": "Objekti za učenje", + "gradesum": "Konačna ocena", + "highestattempt": "Najbolji pokušaj", + "incomplete": "Nepotpuno", + "lastattempt": "Poslednji završeni pokušaj", + "mode": "Režim rada", + "newattempt": "Počni novi pokušaj", + "noattemptsallowed": "Broj dozvoljenih pokušaja", + "noattemptsmade": "Broj pokušaja koji ste imali", + "normal": "Normalno", + "notattempted": "Nije pokušavano", + "offlineattemptnote": "Ovaj pokušaj ima podatke koji nisu sinhronizovan.", + "offlineattemptovermax": "Ovaj pokušaj ne može biti poslat zato što ste premašili maksimalan broj dozvoljenih pokušaja.", + "organizations": "Organizacije", + "passed": "Položeno", + "reviewmode": "Režim prikaza", + "scormstatusnotdownloaded": "Ovaj SCORM paket nije preuzet. Biće automatski preuzet kada ga otvorite.", + "scormstatusoutdated": "Ovaj SCORM paket je menjan od poslednjeg preuzimanja. Biće automatski preuzet kada ga otvorite.", + "suspended": "Suspendovano", + "warningofflinedatadeleted": "Neki oflajn podaci o pokušaju {{number}} su obrisani zato što ih nije moguće kreirati u novom pokušaju.", + "warningsynconlineincomplete": "Neki pokušaji nisu mogli biti sinhronizovani sa sajtom zato što poslednji online pokušaj nije završen. Molimo vas da prvo završite onlajn pokušaj." +} \ No newline at end of file diff --git a/www/addons/mod/scorm/lang/uk.json b/www/addons/mod/scorm/lang/uk.json index 47edde51210..dc0f5cb8a29 100644 --- a/www/addons/mod/scorm/lang/uk.json +++ b/www/addons/mod/scorm/lang/uk.json @@ -12,7 +12,7 @@ "dataattemptshown": "Ці дані належать до спроби № {{number}}.", "enter": "Ввести", "errorcreateofflineattempt": "При створенні нового форуму сталася помилка. Будь ласка спробуйте ще раз.", - "errordownloadscorm": "Помилка завантаження SCORM: \"{{name}}\".", + "errordownloadscorm": "Помилка завантаження SCORM: \"{{name}}\".", "errorgetscorm": "Помилка отримання SCORM-даних.", "errorinvalidversion": "На жаль, додаток підтримує тільки SCORM 1.2.", "errornotdownloadable": "Завантаження SCORM пакетів відключене у вашому сайті Moodle. Будь ласка, зверніться до адміністратора сайту Moodle.", @@ -39,13 +39,13 @@ "normal": "Нормальний", "notattempted": "Не було спроб", "offlineattemptnote": "Ця спроба має дані, що не були синхронізовані.", - "offlineattemptovermax": "Ця спроба не може бути відправлена, так як ви перевершили максимальну кількість спроб.", + "offlineattemptovermax": "Ця спроба не може бути відправлена, так як ви перевищили максимальну кількість спроб.", "organizations": "Організації", "passed": "Пропущено", "reviewmode": "Режим перегляду", - "scormstatusnotdownloaded": "Це SCORM не завантажується. Він буде автоматично завантажуватися при її відкритті.", + "scormstatusnotdownloaded": "Цей SCORM не завантажений. Він буде автоматично завантажуватися при його відкритті.", "scormstatusoutdated": "Цей SCORM був змінений з моменту останнього завантаження. Він буде автоматично завантажуватися при її відкритті.", "suspended": "Заблокований", - "warningofflinedatadeleted": "Деякі автономні дані про спробу № {{number}} були видалений, тому що він не може бути створений в новій спробі.", + "warningofflinedatadeleted": "Деякі автономні дані про спробу № {{number}} були видалені, тому що вони не можуть бути створені в новій спробі.", "warningsynconlineincomplete": "Деякі спроби не можуть бути синхронізовані з сайтом, тому що онлайн спроба не закінчена. Будь ласка закінчіть спробу онлайн спершу." } \ No newline at end of file diff --git a/www/addons/mod/scorm/lang/zh-tw.json b/www/addons/mod/scorm/lang/zh-tw.json index ec476e126b9..c46213ad3fa 100644 --- a/www/addons/mod/scorm/lang/zh-tw.json +++ b/www/addons/mod/scorm/lang/zh-tw.json @@ -21,23 +21,23 @@ "errorsyncscorm": "同步時發生錯誤. 請再試一次.", "exceededmaxattempts": "你已經達到最大的作答次數", "failed": "失敗", - "firstattempt": "第一次使用", + "firstattempt": "第一次作答", "gradeaverage": "平均成績", "gradeforattempt": "作答次的分數", "gradehighest": "最高成績", - "grademethod": "評分方式", + "grademethod": "成績採計方式", "gradereported": "成績報告", "gradescoes": "學習目標", "gradesum": "加總", - "highestattempt": "最高使用次數", + "highestattempt": "最高作答次數", "incomplete": "不完整", "lastattempt": "最後完成的作答次", "mode": "模式", - "newattempt": "開始新的使用", + "newattempt": "開始一個新的作答次", "noattemptsallowed": "允許作答的次數", "noattemptsmade": "你已經作答的次數", "normal": "一般", - "notattempted": "未嘗試", + "notattempted": "尚未作答", "offlineattemptnote": "此嘗試包含尚未同步的資料.", "offlineattemptovermax": "無法發送此嘗試, 因為您超過了最大嘗試次數.", "organizations": "組織", @@ -45,7 +45,7 @@ "reviewmode": "複習模式", "scormstatusnotdownloaded": "此SCORM未下載. 它會在您打開時自動下載.", "scormstatusoutdated": "此SCORM自上次下載以來已被修改. 它會在您打開時自動下載.", - "suspended": "中止", + "suspended": "已休學", "warningofflinedatadeleted": "嘗試{{number}}的某些離線資料已被刪除, 因為無法建立新的嘗試.", "warningsynconlineincomplete": "某些嘗試無法與網站同步, 因為上次上線嘗試未完成, 請先完成上線嘗試." } \ No newline at end of file diff --git a/www/addons/mod/scorm/services/handlers.js b/www/addons/mod/scorm/services/handlers.js index b9048febd28..8e9bf9b482c 100644 --- a/www/addons/mod/scorm/services/handlers.js +++ b/www/addons/mod/scorm/services/handlers.js @@ -23,7 +23,7 @@ angular.module('mm.addons.mod_scorm') */ .factory('$mmaModScormHandlers', function($mmCourse, $mmaModScorm, $mmEvents, $state, $mmSite, $mmaModScormHelper, $mmCoursePrefetchDelegate, mmCoreDownloading, mmCoreNotDownloaded, mmCoreOutdated, mmCoreEventPackageStatusChanged, - mmaModScormComponent, $q, $mmContentLinksHelper, $mmUtil, $mmaModScormSync, $mmaModScormPrefetchHandler) { + mmaModScormComponent, $q, $mmContentLinksHelper, $mmaModScormSync, $mmaModScormPrefetchHandler) { var self = {}; /** @@ -95,9 +95,10 @@ angular.module('mm.addons.mod_scorm') $scope.spinner = true; // Show spinner since this operation might take a while. $mmaModScorm.getScorm(courseid, module.id, module.url).then(function(scorm) { $mmaModScormHelper.confirmDownload(scorm, isOutdated).then(function() { - $mmaModScormPrefetchHandler.prefetch(module, courseid).catch(function() { + return $mmaModScormPrefetchHandler.prefetch(module, courseid).catch(function(error) { if (!$scope.$$destroyed) { - $mmaModScormHelper.showDownloadError(scorm); + $mmaModScormHelper.showDownloadError(scorm, error); + return $q.reject(); } }); }).catch(function() { @@ -106,11 +107,7 @@ angular.module('mm.addons.mod_scorm') }); }).catch(function(error) { $scope.spinner = false; - if (error) { - $mmUtil.showErrorModal(error); - } else { - $mmaModScormHelper.showDownloadError(scorm); - } + $mmaModScormHelper.showDownloadError(scorm, error); }); } @@ -156,6 +153,9 @@ angular.module('mm.addons.mod_scorm') $scope.$on('$destroy', function() { statusObserver && statusObserver.off && statusObserver.off(); }); + }).catch(function() { + // Error getting SCORM, hide the spinner. + $scope.spinner = false; }); }; }; diff --git a/www/addons/mod/scorm/services/helper.js b/www/addons/mod/scorm/services/helper.js index 056636d7a38..052b2654c29 100644 --- a/www/addons/mod/scorm/services/helper.js +++ b/www/addons/mod/scorm/services/helper.js @@ -352,13 +352,12 @@ angular.module('mm.addons.mod_scorm') * @module mm.addons.mod_scorm * @ngdoc method * @name $mmaModScormHelper#showDownloadError - * @param {Object} scorm SCORM downloaded. + * @param {Object} scorm SCORM downloaded. + * @param {String} [error] Error returned by the download. * @return {Void} */ - self.showDownloadError = function(scorm) { - $translate('mma.mod_scorm.errordownloadscorm', {name: scorm.name}).then(function(message) { - $mmUtil.showErrorModal(message); - }); + self.showDownloadError = function(scorm, error) { + $mmUtil.showErrorModalDefault(error, $translate.instant('mma.mod_scorm.errordownloadscorm', {name: scorm.name})); }; return self; diff --git a/www/addons/mod/survey/controllers/index.js b/www/addons/mod/survey/controllers/index.js index 469f5cc7b63..5d4f0dab873 100644 --- a/www/addons/mod/survey/controllers/index.js +++ b/www/addons/mod/survey/controllers/index.js @@ -110,6 +110,13 @@ angular.module('mm.addons.mod_survey') var isTextArea = q.multi && q.multi.length === 0 && q.type === 0; $scope.answers[q.name] = q.required ? -1 : (isTextArea ? '' : '0'); } + + if (q.multi && !q.multi.length && q.parent === 0 && q.type > 0) { + // Options shown in a select. Remove all HTML. + q.options = q.options.map(function(option) { + return $mmText.cleanTags(option); + }); + } }); }); }); diff --git a/www/addons/mod/survey/lang/ar.json b/www/addons/mod/survey/lang/ar.json index 30dd1d2fed3..dd271b759c7 100644 --- a/www/addons/mod/survey/lang/ar.json +++ b/www/addons/mod/survey/lang/ar.json @@ -2,5 +2,5 @@ "ifoundthat": "وجدت أن", "ipreferthat": "أفضل أن", "responses": "إجابات", - "results": "نتائج" + "results": "النتائج" } \ No newline at end of file diff --git a/www/addons/mod/survey/lang/ja.json b/www/addons/mod/survey/lang/ja.json index 9880b35045a..35fbcedcc0d 100644 --- a/www/addons/mod/survey/lang/ja.json +++ b/www/addons/mod/survey/lang/ja.json @@ -1,4 +1,6 @@ { + "cannotsubmitsurvey": "申し訳ありません。あなたの調査提出で問題が発生しました。再度提出を実行してください。", + "errorgetsurvey": "調査データの取得中にエラーが発生しました。", "ifoundthat": "私は次のことを発見しました:", "ipreferthat": "私は次のことが好きです:", "responses": "回答", diff --git a/www/addons/mod/survey/lang/pl.json b/www/addons/mod/survey/lang/pl.json index 3b9a9921b72..cc6f6480b61 100644 --- a/www/addons/mod/survey/lang/pl.json +++ b/www/addons/mod/survey/lang/pl.json @@ -2,6 +2,6 @@ "ifoundthat": "Stwierdziłem, że", "ipreferthat": "Wolę to", "responses": "Odpowiedzi", - "results": "Wynik", + "results": "Wyniki", "surveycompletednograph": "Już wypełniłeś tą ankietę." } \ No newline at end of file diff --git a/www/addons/mod/survey/lang/sr-cr.json b/www/addons/mod/survey/lang/sr-cr.json new file mode 100644 index 00000000000..b09d2613a67 --- /dev/null +++ b/www/addons/mod/survey/lang/sr-cr.json @@ -0,0 +1,9 @@ +{ + "cannotsubmitsurvey": "Нажалост, било је проблема са предајом вашег упитника. Молим вас, покушајте поново.", + "errorgetsurvey": "Грешка приликом преузимања података за 'Упитник' (Survey)", + "ifoundthat": "Открио/ла сам да", + "ipreferthat": "Преферирам", + "responses": "Одговори", + "results": "Резултати", + "surveycompletednograph": "Испунили сте анкету." +} \ No newline at end of file diff --git a/www/addons/mod/survey/lang/sr-lt.json b/www/addons/mod/survey/lang/sr-lt.json new file mode 100644 index 00000000000..7e1fed7f8d7 --- /dev/null +++ b/www/addons/mod/survey/lang/sr-lt.json @@ -0,0 +1,9 @@ +{ + "cannotsubmitsurvey": "Nažalost, bilo je problema sa predajom vašeg upitnika. Molim vas, pokušajte ponovo.", + "errorgetsurvey": "Greška prilikom preuzimanja podataka za 'Upitnik' (Survey)", + "ifoundthat": "Otkrio/la sam da", + "ipreferthat": "Preferiram", + "responses": "Odgovori", + "results": "Rezultati", + "surveycompletednograph": "Ispunili ste anketu." +} \ No newline at end of file diff --git a/www/addons/mod/survey/lang/tr.json b/www/addons/mod/survey/lang/tr.json index f42edcb4d3f..471798df02c 100644 --- a/www/addons/mod/survey/lang/tr.json +++ b/www/addons/mod/survey/lang/tr.json @@ -2,6 +2,6 @@ "ifoundthat": "Gerçekte olan", "ipreferthat": "İstediğim", "responses": "Yanıtlar", - "results": "Sonuç", + "results": "Sonuçlar", "surveycompletednograph": "Bu anketi tamamladınız." } \ No newline at end of file diff --git a/www/addons/mod/survey/lang/uk.json b/www/addons/mod/survey/lang/uk.json index 74dd0374658..c0e91783cb7 100644 --- a/www/addons/mod/survey/lang/uk.json +++ b/www/addons/mod/survey/lang/uk.json @@ -1,6 +1,6 @@ { - "cannotsubmitsurvey": "На жаль, існує проблема представлення вашого обстеження. Будь ласка спробуйте ще раз.", - "errorgetsurvey": "Помилка при отриманні даних обстеження.", + "cannotsubmitsurvey": "На жаль, існує проблема вашого представлення. Будь ласка спробуйте ще раз.", + "errorgetsurvey": "Помилка при отриманні даних.", "ifoundthat": "Я довідався, що", "ipreferthat": "Я волію, щоб", "responses": "Відповіді", diff --git a/www/addons/mod/survey/lang/zh-cn.json b/www/addons/mod/survey/lang/zh-cn.json index 912d8caa96b..7ef142e9e7a 100644 --- a/www/addons/mod/survey/lang/zh-cn.json +++ b/www/addons/mod/survey/lang/zh-cn.json @@ -2,5 +2,5 @@ "ifoundthat": "我发现", "ipreferthat": "我希望的是", "responses": "回复", - "results": "投票结果" + "results": "结果" } \ No newline at end of file diff --git a/www/addons/mod/survey/services/handlers.js b/www/addons/mod/survey/services/handlers.js index 4bbccfbe032..22a6cb83fbf 100644 --- a/www/addons/mod/survey/services/handlers.js +++ b/www/addons/mod/survey/services/handlers.js @@ -22,7 +22,7 @@ angular.module('mm.addons.mod_survey') * @name $mmaModSurveyHandlers */ .factory('$mmaModSurveyHandlers', function($mmCourse, $mmaModSurvey, $state, $mmContentLinksHelper, $mmUtil, $mmEvents, $mmSite, - $mmaModSurveyPrefetchHandler, $mmCoursePrefetchDelegate, mmCoreDownloading, mmCoreNotDownloaded, mmCoreOutdated, + $mmaModSurveyPrefetchHandler, $mmCoursePrefetchDelegate, mmCoreDownloading, mmCoreNotDownloaded, mmCoreOutdated, $q, mmaModSurveyComponent, mmCoreEventPackageStatusChanged, $mmaModSurveySync) { var self = {}; @@ -103,9 +103,10 @@ angular.module('mm.addons.mod_survey') // Get download size to ask for confirm if it's high. $mmaModSurveyPrefetchHandler.getDownloadSize(module, courseId).then(function(size) { $mmUtil.confirmDownloadSize(size).then(function() { - $mmaModSurveyPrefetchHandler.prefetch(module, courseId).catch(function() { + return $mmaModSurveyPrefetchHandler.prefetch(module, courseId).catch(function(error) { if (!$scope.$$destroyed) { - $mmUtil.showErrorModal('mm.core.errordownloading', true); + $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true); + return $q.reject(); } }); }).catch(function() { diff --git a/www/addons/mod/survey/templates/index.html b/www/addons/mod/survey/templates/index.html index e3f4ac67837..f9ef701c354 100644 --- a/www/addons/mod/survey/templates/index.html +++ b/www/addons/mod/survey/templates/index.html @@ -70,7 +70,7 @@

{{ question.text }}

-
diff --git a/www/addons/mod/url/lang/es_mx.json b/www/addons/mod/url/lang/es_mx.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/www/addons/mod/url/lang/es_mx.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/www/addons/mod/url/lang/ja.json b/www/addons/mod/url/lang/ja.json index 0637a088a01..350006f4a7f 100644 --- a/www/addons/mod/url/lang/ja.json +++ b/www/addons/mod/url/lang/ja.json @@ -1 +1,4 @@ -[] \ No newline at end of file +{ + "accessurl": "URLへのアクセス", + "pointingtourl": "このリソースを示すURL" +} \ No newline at end of file diff --git a/www/addons/mod/url/lang/pt_br.json b/www/addons/mod/url/lang/pt_br.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/www/addons/mod/url/lang/pt_br.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/www/addons/mod/url/lang/sr-cr.json b/www/addons/mod/url/lang/sr-cr.json new file mode 100644 index 00000000000..8559de48806 --- /dev/null +++ b/www/addons/mod/url/lang/sr-cr.json @@ -0,0 +1,4 @@ +{ + "accessurl": "Приступи URL адреси", + "pointingtourl": "URL адреса са којом је овај ресурс повезан" +} \ No newline at end of file diff --git a/www/addons/mod/url/lang/sr-lt.json b/www/addons/mod/url/lang/sr-lt.json new file mode 100644 index 00000000000..a266fc49df5 --- /dev/null +++ b/www/addons/mod/url/lang/sr-lt.json @@ -0,0 +1,4 @@ +{ + "accessurl": "Pristupi URL adresi", + "pointingtourl": "URL adresa sa kojom je ovaj resurs povezan" +} \ No newline at end of file diff --git a/www/addons/mod/url/lang/zh_cn.json b/www/addons/mod/url/lang/zh_cn.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/www/addons/mod/url/lang/zh_cn.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/www/addons/mod/url/lang/zh_tw.json b/www/addons/mod/url/lang/zh_tw.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/www/addons/mod/url/lang/zh_tw.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/www/addons/mod/wiki/lang/ar.json b/www/addons/mod/wiki/lang/ar.json index 1bff5b0f91c..794020d3f62 100644 --- a/www/addons/mod/wiki/lang/ar.json +++ b/www/addons/mod/wiki/lang/ar.json @@ -6,7 +6,7 @@ "newpagetitle": "عنواو صفحة جديد", "nocontent": "لا يوجد محتوى في هذه الصفحة", "notingroup": "لا ينتمي إلى مجموعة", - "page": "صفحة", + "page": "صفحة: {{$a}}", "pagename": "اسم الصفحة", "wrongversionlock": "قام مستخدم آخر بتحديث هذه الصفحة بينما كنت أنت تحررها، أصبحت تعديلاتك قديمة." } \ No newline at end of file diff --git a/www/addons/mod/wiki/lang/bg.json b/www/addons/mod/wiki/lang/bg.json index dbe95df13e3..cfe93c0370e 100644 --- a/www/addons/mod/wiki/lang/bg.json +++ b/www/addons/mod/wiki/lang/bg.json @@ -4,8 +4,8 @@ "editingpage": "Редактиране на страница \"{{$a}}\"", "map": "Карта", "newpagetitle": "Заглавие на новата страница", - "notingroup": "Извинете, но трябва да сте част от групата за да видите тази дейност.", - "page": "Страница", + "notingroup": "За съжаление Вие трябва да се част от група за да виждате този форум.", + "page": "Страница: {{$a}}", "pagename": "Име на страница", "wrongversionlock": "Друг потребител редактира тази страница докато Вие редактирахте и Вашата редакция вече е остаряла." } \ No newline at end of file diff --git a/www/addons/mod/wiki/lang/el.json b/www/addons/mod/wiki/lang/el.json index 801399e1135..7a3a3058446 100644 --- a/www/addons/mod/wiki/lang/el.json +++ b/www/addons/mod/wiki/lang/el.json @@ -2,7 +2,7 @@ "errorloadingpage": "Παρουσιάστηκε σφάλμα κατά τη φόρτωση της σελίδας.", "errornowikiavailable": "Αυτό το wiki δεν έχει ακόμα περιεχόμενο.", "gowikihome": "Go Wiki home", - "notingroup": "Συγνώμη, αλλά θα πρέπει να είστε μέλος μιας ομάδας για να δείτε αυτήν τη δραστηριότητα", + "notingroup": "Συγγνώμη, αλλά πρέπει να είστε μέλος ομάδας για να δείτε αυτό την ομάδα συζητήσεων.", "page": "Σελίδα", "subwiki": "Subwiki", "titleshouldnotbeempty": "Ο τίτλος δεν πρέπει να είναι κενός", diff --git a/www/addons/mod/wiki/lang/fa.json b/www/addons/mod/wiki/lang/fa.json index 3ea0f81b588..645adbdab85 100644 --- a/www/addons/mod/wiki/lang/fa.json +++ b/www/addons/mod/wiki/lang/fa.json @@ -5,7 +5,7 @@ "newpagetitle": "عنوان صفحهٔ جدید", "nocontent": "محتوایی برای این صفحه وجود ندارد", "notingroup": "بدون گروه", - "page": "صفحه", + "page": "صفحهٔ {{$a}}", "pageexists": "این صفحه در حال حاضر وجود دارد. در حال تغییر مسیر به صفحهٔ موجود.", "viewpage": "مشاهدهٔ صفحه", "wrongversionlock": "هنگامی که شما در حال ویرایش این صفحه بودید، کاربر دیگری آن را ویرایش کرد و محتوایش را تغییر داد." diff --git a/www/addons/mod/wiki/lang/he.json b/www/addons/mod/wiki/lang/he.json index 46bd85d687c..6d94870a86a 100644 --- a/www/addons/mod/wiki/lang/he.json +++ b/www/addons/mod/wiki/lang/he.json @@ -7,7 +7,7 @@ "newpagetitle": "כותרת דף חדש", "nocontent": "אין תוכן לדף זה", "notingroup": "לא בקבוצה", - "page": "עמוד", + "page": "עמוד: {{$a}}", "pageexists": "הדף כבר קיים. הפנה אליו מחדש.", "pagename": "שם העמוד", "wrongversionlock": "משתמש אחר ערך את הדף הזה בזמן שאת/ה ערכת/ה. התוכן שלך לא ישמר." diff --git a/www/addons/mod/wiki/lang/hu.json b/www/addons/mod/wiki/lang/hu.json index 19b98951ec9..52eb1a43078 100644 --- a/www/addons/mod/wiki/lang/hu.json +++ b/www/addons/mod/wiki/lang/hu.json @@ -7,7 +7,7 @@ "newpagetitle": "Új oldalcím", "nocontent": "Az oldalhoz nincs tartalom", "notingroup": "Nem része a csoportnak", - "page": "Oldal", + "page": "Oldal: {{$a}}", "pageexists": "Az oldal már létezik. Átirányítás az oldalra.", "pagename": "Oldal neve", "wrongversionlock": "A szerkesztés közben egy másik felhasználó szerkesztette ezt az oldalt, így az Ön tartalma elavult." diff --git a/www/addons/mod/wiki/lang/it.json b/www/addons/mod/wiki/lang/it.json index 5acbfeed47e..188539ca68d 100644 --- a/www/addons/mod/wiki/lang/it.json +++ b/www/addons/mod/wiki/lang/it.json @@ -10,7 +10,7 @@ "newpagetitle": "Titolo nuova pagina", "nocontent": "Questa pagina non ha contenuti", "notingroup": "Non è in un gruppo", - "page": "Pagina", + "page": "Pagina: {{$a}}", "pageexists": "La pagina esiste già.", "pagename": "Nome pagina", "subwiki": "Subwiki", diff --git a/www/addons/mod/wiki/lang/ja.json b/www/addons/mod/wiki/lang/ja.json index fbfaad517e5..602d4646668 100644 --- a/www/addons/mod/wiki/lang/ja.json +++ b/www/addons/mod/wiki/lang/ja.json @@ -2,6 +2,9 @@ "cannoteditpage": "あなたはこのページを編集できません。", "createpage": "ページを作成する", "editingpage": "このページ「 {{$a}} 」の編集", + "errorloadingpage": "ページの読み込み中にエラーが発生しました。", + "errornowikiavailable": "このwikiにはまだ内容がありません。", + "gowikihome": "Wikiのホームへ移動", "map": "マップ", "newpagehdr": "新しいページ", "newpagetitle": "新しいページタイトル", @@ -10,5 +13,9 @@ "page": "ページ", "pageexists": "このページはすでに存在します。", "pagename": "ページ名", + "subwiki": "サブwiki", + "titleshouldnotbeempty": "空のタイトルは受け付けられません", + "viewpage": "ページを表示", + "wikipage": "Wikiページ", "wrongversionlock": "あなたが編集している間、別のユーザがこのページを編集しました。そのため、あなたのコンテンツは古くなりました。" } \ No newline at end of file diff --git a/www/addons/mod/wiki/lang/pl.json b/www/addons/mod/wiki/lang/pl.json index 8515710e26a..391b0fbc350 100644 --- a/www/addons/mod/wiki/lang/pl.json +++ b/www/addons/mod/wiki/lang/pl.json @@ -7,7 +7,7 @@ "newpagetitle": "Tytuł nowej strony", "nocontent": "Brak zawartości dla tej strony", "notingroup": "Nie w grupie", - "page": "Strona", + "page": "Strona: {{$a}}", "pageexists": "Ta strona już istnieje. Przekierowuje do niej.", "pagename": "Nazwa strony", "wrongversionlock": "Inny użytkownik edytował tę stronę w czasie, kiedy ty ją edytowałeś i twoja zawartość jest przestarzała." diff --git a/www/addons/mod/wiki/lang/ro.json b/www/addons/mod/wiki/lang/ro.json index 79fdc396e4f..2b0c326bec6 100644 --- a/www/addons/mod/wiki/lang/ro.json +++ b/www/addons/mod/wiki/lang/ro.json @@ -5,7 +5,7 @@ "newpagehdr": "Pagină nouă", "newpagetitle": "Un nou titlu de pagină", "nocontent": "Nu există conținut pentru această pagină", - "notingroup": "Ne pare rău, dar trebuie să faceţi parte dintr-un grup pentru a putea vizualiza această activitate.", - "page": "Pagină", + "notingroup": "Ne pare rău, pentru a putea vizualiza acest forum trebuie să fiţi membru al unui grup.", + "page": "Pagina {{$a}}", "pagename": "Nume pagină" } \ No newline at end of file diff --git a/www/addons/mod/wiki/lang/sr-cr.json b/www/addons/mod/wiki/lang/sr-cr.json new file mode 100644 index 00000000000..9620e198c9d --- /dev/null +++ b/www/addons/mod/wiki/lang/sr-cr.json @@ -0,0 +1,21 @@ +{ + "cannoteditpage": "Не можете да уређујете ову страницу.", + "createpage": "Креирај страницу", + "editingpage": "Уређивање ове странице '{{$a}}'", + "errorloadingpage": "Дошло је до грешке приликом учитавања странице.", + "errornowikiavailable": "Овај вики још увек нема садржај.", + "gowikihome": "Иди на почетну страницу викија", + "map": "Мапа", + "newpagehdr": "Нова страница", + "newpagetitle": "Наслов нове странице", + "nocontent": "На овој страници нема садржаја", + "notingroup": "Није у групи", + "page": "Страница", + "pageexists": "Ова страница већ постоји.", + "pagename": "Назив странице", + "subwiki": "Подвики", + "titleshouldnotbeempty": "Наслов не би требало да буде празан", + "viewpage": "Погледај страницу", + "wikipage": "Вики страница", + "wrongversionlock": "Други корисник је уређивао ову страницу у исто време када и ви. Ваш садржај је застарео." +} \ No newline at end of file diff --git a/www/addons/mod/wiki/lang/sr-lt.json b/www/addons/mod/wiki/lang/sr-lt.json new file mode 100644 index 00000000000..11efcb2e226 --- /dev/null +++ b/www/addons/mod/wiki/lang/sr-lt.json @@ -0,0 +1,21 @@ +{ + "cannoteditpage": "Ne možete da uređujete ovu stranicu.", + "createpage": "Kreiraj stranicu", + "editingpage": "Uređivanje ove stranice '{{$a}}'", + "errorloadingpage": "Došlo je do greške prilikom učitavanja stranice.", + "errornowikiavailable": "Ovaj viki još uvek nema sadržaj.", + "gowikihome": "Idi na početnu stranicu vikija", + "map": "Mapa", + "newpagehdr": "Nova stranica", + "newpagetitle": "Naslov nove stranice", + "nocontent": "Na ovoj stranici nema sadržaja", + "notingroup": "Nije u grupi", + "page": "Stranica", + "pageexists": "Ova stranica već postoji.", + "pagename": "Naziv stranice", + "subwiki": "Podviki", + "titleshouldnotbeempty": "Naslov ne bi trebalo da bude prazan", + "viewpage": "Pogledaj stranicu", + "wikipage": "Viki stranica", + "wrongversionlock": "Drugi korisnik je uređivao ovu stranicu u isto vreme kada i vi. Vaš sadržaj je zastareo." +} \ No newline at end of file diff --git a/www/addons/mod/wiki/lang/sv.json b/www/addons/mod/wiki/lang/sv.json index f9ebf16c762..43bd89b4601 100644 --- a/www/addons/mod/wiki/lang/sv.json +++ b/www/addons/mod/wiki/lang/sv.json @@ -10,7 +10,7 @@ "newpagetitle": "Ny titel på sida", "nocontent": "Det finns inget innehåll för den här sidan", "notingroup": "Inte i grupp", - "page": "Sida", + "page": "Sida: {{$a}}", "pageexists": "Den här sidan finns redan, länkning dit pågår", "pagename": "Namn på sida", "subwiki": "Subwiki", diff --git a/www/addons/mod/wiki/lang/uk.json b/www/addons/mod/wiki/lang/uk.json index c19abe51cb9..cd89e56c9cc 100644 --- a/www/addons/mod/wiki/lang/uk.json +++ b/www/addons/mod/wiki/lang/uk.json @@ -13,7 +13,7 @@ "page": "Сторінка", "pageexists": "Ця сторінка вже існує. Перенаправити до неї.", "pagename": "Назва сторінки", - "subwiki": "Сабвікі", + "subwiki": "Субвікі", "titleshouldnotbeempty": "Заголовок не може бути порожнім", "viewpage": "Переглянути сторінку", "wikipage": "Вікі-сторінка", diff --git a/www/addons/mod/wiki/lang/zh-cn.json b/www/addons/mod/wiki/lang/zh-cn.json index 1eb2563a117..28e5c1b23ad 100644 --- a/www/addons/mod/wiki/lang/zh-cn.json +++ b/www/addons/mod/wiki/lang/zh-cn.json @@ -7,7 +7,7 @@ "newpagetitle": "新页面标题", "nocontent": "此页面无内容", "notingroup": "不在小组内", - "page": "页", + "page": "页面", "pageexists": "页面已存在。重定向到它", "pagename": "页码", "wrongversionlock": "在您正编辑此页面时,另一个人已经做了编辑,所以您的修改已过时。" diff --git a/www/addons/mod/wiki/services/handlers.js b/www/addons/mod/wiki/services/handlers.js index 04ecf9ea010..eacdbf6c62f 100644 --- a/www/addons/mod/wiki/services/handlers.js +++ b/www/addons/mod/wiki/services/handlers.js @@ -102,9 +102,10 @@ angular.module('mm.addons.mod_wiki') // We need to call getDownloadSize, the package might have been updated. $mmaModWikiPrefetchHandler.getDownloadSize(module, courseId).then(function(size) { $mmUtil.confirmDownloadSize(size).then(function() { - $mmaModWikiPrefetchHandler.prefetch(module, courseId).catch(function() { + return $mmaModWikiPrefetchHandler.prefetch(module, courseId).catch(function(error) { if (!$scope.$$destroyed) { - $mmUtil.showErrorModal('mm.core.errordownloading', true); + $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true); + return $q.reject(); } }); }).catch(function() { diff --git a/www/addons/myoverview/lang/ca.json b/www/addons/myoverview/lang/ca.json index 6f57cd536b3..7d74942e12e 100644 --- a/www/addons/myoverview/lang/ca.json +++ b/www/addons/myoverview/lang/ca.json @@ -1,5 +1,18 @@ { - "inprogress": "En curs", - "nocourses": "No hi ha informació de cursos per mostrar.", - "pluginname": "Nom del connector de repositori" + "future": "Futurs", + "inprogress": "En progrés", + "morecourses": "Més cursos", + "next30days": "Propers 30 dies", + "next7days": "Propers 7 dies", + "nocourses": "Cap curs", + "nocoursesfuture": "Cap curs futur", + "nocoursesinprogress": "Cap curs en progrés", + "nocoursespast": "Cap curs passat", + "noevents": "Cap activitat venç properament", + "past": "Passats", + "pluginname": "Resum del curs", + "recentlyoverdue": "Vençuda recentment", + "sortbycourses": "Ordena per cursos", + "sortbydates": "Ordena per dates", + "timeline": "Línia de temps" } \ No newline at end of file diff --git a/www/addons/myoverview/lang/da.json b/www/addons/myoverview/lang/da.json index 6b0e076a3e8..93f96452658 100644 --- a/www/addons/myoverview/lang/da.json +++ b/www/addons/myoverview/lang/da.json @@ -1,5 +1,17 @@ { - "inprogress": "Igangværende", - "nocourses": "Du er ikke tilmeldt nogen kurser.", - "pluginname": "Navn på filarkiv-plugin" + "future": "Fremtidige", + "inprogress": "I gang", + "morecourses": "Flere kurser", + "next30days": "Næste 30 dage", + "next7days": "Næste 7 dage", + "nocourses": "Ingen kurser", + "nocoursesfuture": "Ingen fremtidige kurser", + "nocoursesinprogress": "Ingen igangværende kurser", + "nocoursespast": "Ingen tidligere kurser", + "noevents": "Ingen forestående aktiviteter", + "past": "Tidligere", + "pluginname": "Kursusoversigt", + "sortbycourses": "Sorter efter kurser", + "sortbydates": "Sorter efter dato", + "timeline": "Tidslinje" } \ No newline at end of file diff --git a/www/addons/myoverview/lang/de.json b/www/addons/myoverview/lang/de.json index 5eeb1d65140..48617009585 100644 --- a/www/addons/myoverview/lang/de.json +++ b/www/addons/myoverview/lang/de.json @@ -14,5 +14,5 @@ "recentlyoverdue": "Kürzlich überfällig", "sortbycourses": "Nach Kurs sortieren", "sortbydates": "Nach Datum sortieren", - "timeline": "Timeline" + "timeline": "Zeitleiste" } \ No newline at end of file diff --git a/www/addons/myoverview/lang/es.json b/www/addons/myoverview/lang/es.json index b796e0b88b4..44a7a41e6f1 100644 --- a/www/addons/myoverview/lang/es.json +++ b/www/addons/myoverview/lang/es.json @@ -1,5 +1,5 @@ { - "future": "Futuro", + "future": "Futuros", "inprogress": "En progreso", "morecourses": "Más cursos", "next30days": "Próximos 30 días", @@ -9,7 +9,7 @@ "nocoursesinprogress": "Sin cursos en progreso", "nocoursespast": "Sin cursos pasados", "noevents": "No hay actividades próximas pendientes", - "past": "Pasado", + "past": "Pasados", "pluginname": "Vista general de curso", "recentlyoverdue": "Recientemente vencidas", "sortbycourses": "Ordenar por curso", diff --git a/www/addons/myoverview/lang/eu.json b/www/addons/myoverview/lang/eu.json index 63ad1570d13..75bf1d67080 100644 --- a/www/addons/myoverview/lang/eu.json +++ b/www/addons/myoverview/lang/eu.json @@ -6,13 +6,13 @@ "next7days": "Datozen 7 egunetan", "nocourses": "Ez dago ikastarorik", "nocoursesfuture": "Ez dago ikastarorik etorkizunean", - "nocoursesinprogress": "", + "nocoursesinprogress": "Ez dago martxan dagoen ikastarorik", "nocoursespast": "Ez dago ikastarorik iraganean", - "noevents": "", + "noevents": "Ez dago jardueren muga-egunik laster", "past": "Iragana", - "pluginname": "", - "recentlyoverdue": "", + "pluginname": "Ikuspegi orokorra", + "recentlyoverdue": "Orain dela gutxi iragotako muga-egunak", "sortbycourses": "Ordenatu ikastaroen arabera", "sortbydates": "Ordenatu dataren arabera", - "timeline": "" + "timeline": "Kronologia" } \ No newline at end of file diff --git a/www/addons/myoverview/lang/fr.json b/www/addons/myoverview/lang/fr.json index 266d636a4b5..2a74ad739d4 100644 --- a/www/addons/myoverview/lang/fr.json +++ b/www/addons/myoverview/lang/fr.json @@ -10,7 +10,7 @@ "nocoursespast": "Pas de cours dans le passé", "noevents": "Aucune activité", "past": "Passé", - "pluginname": "Vue d'ensemble du cours", + "pluginname": "Vue d'ensemble des cours", "recentlyoverdue": "Récemment en retard", "sortbycourses": "Tri par cours", "sortbydates": "Tri par date", diff --git a/www/addons/myoverview/lang/he.json b/www/addons/myoverview/lang/he.json index 2c8bcae7be2..d0b13672129 100644 --- a/www/addons/myoverview/lang/he.json +++ b/www/addons/myoverview/lang/he.json @@ -1,7 +1,7 @@ { "future": "עתידי", "inprogress": "בלמידה", - "morecourses": "", + "morecourses": "קורסים נוספים", "next30days": "ב 30 הימים הבאים", "next7days": "ב 7 הימים הבאים", "nocourses": "טרם נרשמתם לקורס כלשהו", @@ -10,7 +10,7 @@ "nocoursespast": "אינכם רשומים לקורס אשר הסתיימו", "noevents": "לא קיימות פעילויות עתידיות להן מועד הגשה", "past": "עבר", - "pluginname": "עדכונים בקורסים שלי", + "pluginname": "סקירה כללית", "recentlyoverdue": "מועד־ההגשה עבר, לאחרונה", "sortbycourses": "מיון לפי שמות קורסים", "sortbydates": "מיון לפי תאריכים", diff --git a/www/addons/myoverview/lang/it.json b/www/addons/myoverview/lang/it.json index 3e157ff6e5c..cca29fb3c13 100644 --- a/www/addons/myoverview/lang/it.json +++ b/www/addons/myoverview/lang/it.json @@ -1,17 +1,17 @@ { - "future": "", - "inprogress": "", - "morecourses": "", - "next30days": "", - "next7days": "", + "future": "Prossimi", + "inprogress": "In svolgimento", + "morecourses": "Altri corsi", + "next30days": "Prossimi 30 giorni", + "next7days": "Prossimi 7 giorni", "nocourses": "Non ci sono corsi", - "nocoursesfuture": "", + "nocoursesfuture": "Non ci sono corsi di prossima attivazione", "nocoursesinprogress": "Non ci sono corsi in svolgimento", - "nocoursespast": "", + "nocoursespast": "Non ci sono corsi conclusi", "noevents": "Non ci sono attività da svolgere", - "past": "", + "past": "Conclusi", "pluginname": "Panoramica corsi", - "recentlyoverdue": "", + "recentlyoverdue": "Scadute di recente", "sortbycourses": "Ordina per corso", "sortbydates": "Ordina per data", "timeline": "Cronologia" diff --git a/www/addons/myoverview/lang/ja.json b/www/addons/myoverview/lang/ja.json index 3671d43e7ee..af5dc09b17a 100644 --- a/www/addons/myoverview/lang/ja.json +++ b/www/addons/myoverview/lang/ja.json @@ -1,11 +1,11 @@ { - "future": "今後", + "future": "未来", "inprogress": "進行中", "morecourses": "コースをさらに", "next30days": "次の30日", "next7days": "次の7日", "nocourses": "コースなし", - "nocoursesfuture": "今後のコースはありません。", + "nocoursesfuture": "未来のコースはありません。", "nocoursesinprogress": "進行中のコースはありません。", "nocoursespast": "過去のコースはありません。", "noevents": "到来する活動期限はありません。", diff --git a/www/addons/myoverview/lang/lt.json b/www/addons/myoverview/lang/lt.json index cba79f81ce3..c7d17b3aea6 100644 --- a/www/addons/myoverview/lang/lt.json +++ b/www/addons/myoverview/lang/lt.json @@ -1,5 +1,18 @@ { - "inprogress": "Nebaigta", - "nocourses": "Nėra rodytinos kursų informacijos", - "pluginname": "Saugyklos priedo pavadinimas" + "future": "Būsimi", + "inprogress": "Vykstantys", + "morecourses": "Daugiau kursų", + "next30days": "Kitas 30 dienų", + "next7days": "Kitas 7 dienas", + "nocourses": "Nėra kursų", + "nocoursesfuture": "Nėra būsimų kursų", + "nocoursesinprogress": "Nėra vykstančių kursų", + "nocoursespast": "Nėra pasibaigusių kursų", + "noevents": "Nėra numatytų artėjančių veiklų", + "past": "Pasibaigę", + "pluginname": "Kursų apžvalga", + "recentlyoverdue": "Neseniai pavėluotas", + "sortbycourses": "Rūšiuoti pagal kursus", + "sortbydates": "Rūšiuoti pagal datą", + "timeline": "Laiko skalė" } \ No newline at end of file diff --git a/www/addons/myoverview/lang/pl.json b/www/addons/myoverview/lang/pl.json index 08052becbb2..26323a8f098 100644 --- a/www/addons/myoverview/lang/pl.json +++ b/www/addons/myoverview/lang/pl.json @@ -1,5 +1,18 @@ { - "inprogress": "W toku", - "nocourses": "Nie ma informacji do pokazania", - "pluginname": "Nazwa wtyczki repozytorium" + "future": "Nadchodzące", + "inprogress": "Aktualne", + "morecourses": "Więcej kursów", + "next30days": "Następne 30 dni", + "next7days": "Następne 7 dni", + "nocourses": "Brak kursów", + "nocoursesfuture": "Brak nadchodzących kursów", + "nocoursesinprogress": "Brak aktualnych kursów", + "nocoursespast": "Brak zakończonych kursów", + "noevents": "Brak nadchodzących terminów zadań", + "past": "Zakończone", + "pluginname": "Przegląd kursu", + "recentlyoverdue": "Obecnie opóźnione", + "sortbycourses": "Sortuj wg kursów", + "sortbydates": "Sortuj wg dat", + "timeline": "Porządek chronologiczny" } \ No newline at end of file diff --git a/www/addons/myoverview/lang/pt-br.json b/www/addons/myoverview/lang/pt-br.json index c02df1adb37..f768881904f 100644 --- a/www/addons/myoverview/lang/pt-br.json +++ b/www/addons/myoverview/lang/pt-br.json @@ -1,5 +1,18 @@ { + "future": "Não iniciados", "inprogress": "Em andamento", - "nocourses": "Nenhuma informação disponível sobre o curso.", - "pluginname": "Nome do plugin de repositório" + "morecourses": "Mais cursos", + "next30days": "Próximos 30 dias", + "next7days": "Próximos 7 dias", + "nocourses": "Não há cursos", + "nocoursesfuture": "Não há cursos não iniciados", + "nocoursesinprogress": "Não há cursos em andamento", + "nocoursespast": "Não há cursos encerrados", + "noevents": "Não há atividades pendentes", + "past": "Encerrados", + "pluginname": "Resumo dos cursos", + "recentlyoverdue": "Atividades atrasadas", + "sortbycourses": "Ordenar por cursos", + "sortbydates": "Ordenar por data", + "timeline": "Linha do tempo" } \ No newline at end of file diff --git a/www/addons/myoverview/lang/pt.json b/www/addons/myoverview/lang/pt.json index b019a3830aa..1c084d2e2f3 100644 --- a/www/addons/myoverview/lang/pt.json +++ b/www/addons/myoverview/lang/pt.json @@ -1,5 +1,18 @@ { + "future": "Futuro", "inprogress": "Em progresso", - "nocourses": "Sem informação das suas disciplinas para mostrar.", - "pluginname": "Nome do módulo de repositório" + "morecourses": "Mais disciplinas", + "next30days": "Próximos 30 dias", + "next7days": "Próximos 7 dias", + "nocourses": "Sem disciplinas", + "nocoursesfuture": "Nenhuma disciplina a começar", + "nocoursesinprogress": "Nenhuma disciplina a decorrer", + "nocoursespast": "Nenhuma disciplina terminada", + "noevents": "Nenhuma atividade programada", + "past": "Passado", + "pluginname": "Vista geral", + "recentlyoverdue": "Terminadas recentemente", + "sortbycourses": "Ordenar por disciplinas", + "sortbydates": "Ordenar por datas", + "timeline": "Cronograma" } \ No newline at end of file diff --git a/www/addons/myoverview/lang/ru.json b/www/addons/myoverview/lang/ru.json index fbfa8f8a870..1a29c7d620b 100644 --- a/www/addons/myoverview/lang/ru.json +++ b/www/addons/myoverview/lang/ru.json @@ -1,5 +1,18 @@ { + "future": "Будущие", "inprogress": "В процессе", - "nocourses": "Нет информации для отображения.", - "pluginname": "Имя плагина хранилища" + "morecourses": "Больше курсов", + "next30days": "Следующие 30 дней", + "next7days": "Следующие 7 дней", + "nocourses": "Нет курсов", + "nocoursesfuture": "Нет будущих курсов", + "nocoursesinprogress": "Нет курсов в процессе", + "nocoursespast": "Нет прошлых курсов", + "noevents": "Нет предстоящих заданий", + "past": "Прошлые", + "pluginname": "Обзор курсов", + "recentlyoverdue": "Недавно пропущенное", + "sortbycourses": "Сортировать по курсам", + "sortbydates": "Сортировать по датам", + "timeline": "Обзор" } \ No newline at end of file diff --git a/www/addons/myoverview/lang/sr-cr.json b/www/addons/myoverview/lang/sr-cr.json new file mode 100644 index 00000000000..218f9ebde77 --- /dev/null +++ b/www/addons/myoverview/lang/sr-cr.json @@ -0,0 +1,18 @@ +{ + "future": "Будући", + "inprogress": "У току", + "morecourses": "Више курсева", + "next30days": "Следећих 30 дана", + "next7days": "Следећих 7 дана", + "nocourses": "Нема курсева", + "nocoursesfuture": "Нема будућих курсева", + "nocoursesinprogress": "Нема курсева који су току", + "nocoursespast": "Нема прошлих курсева", + "noevents": "Нема активности које се ускоро завршавају", + "past": "Прошли", + "pluginname": "Преглед курсева", + "recentlyoverdue": "Недавно завршене активности", + "sortbycourses": "Сортирај по курсевима", + "sortbydates": "Сортирају по датумима", + "timeline": "Временски распоред" +} \ No newline at end of file diff --git a/www/addons/myoverview/lang/sr-lt.json b/www/addons/myoverview/lang/sr-lt.json new file mode 100644 index 00000000000..953d764faa8 --- /dev/null +++ b/www/addons/myoverview/lang/sr-lt.json @@ -0,0 +1,18 @@ +{ + "future": "Budući", + "inprogress": "U toku", + "morecourses": "Više kurseva", + "next30days": "Sledećih 30 dana", + "next7days": "Sledećih 7 dana", + "nocourses": "Nema kurseva", + "nocoursesfuture": "Nema budućih kurseva", + "nocoursesinprogress": "Nema kurseva koji su toku", + "nocoursespast": "Nema prošlih kurseva", + "noevents": "Nema aktivnosti koje se uskoro završavaju", + "past": "Prošli", + "pluginname": "Pregled kurseva", + "recentlyoverdue": "Nedavno završene aktivnosti", + "sortbycourses": "Sortiraj po kursevima", + "sortbydates": "Sortiraju po datumima", + "timeline": "Vremenski raspored" +} \ No newline at end of file diff --git a/www/addons/myoverview/lang/sv.json b/www/addons/myoverview/lang/sv.json index 977e7631d0d..004122c5c20 100644 --- a/www/addons/myoverview/lang/sv.json +++ b/www/addons/myoverview/lang/sv.json @@ -1,5 +1,16 @@ { - "inprogress": "Pågår", - "nocourses": "Det finns ingen kursinformation att visa.", - "pluginname": "Namn på plugin-program för arkiv" + "future": "Kommande", + "inprogress": "Pågående", + "morecourses": "Fler kurser", + "next30days": "30 dagar framåt", + "next7days": "7 dagar framåt", + "nocourses": "Inga kurser", + "nocoursesfuture": "Inga kommande kurser", + "nocoursesinprogress": "Inga pågående kurser", + "nocoursespast": "Inga tidigare kurser", + "past": "Tidigare", + "pluginname": "Kursöversikt", + "sortbycourses": "Sortera efter kurser", + "sortbydates": "Sortera efter datum", + "timeline": "Tidslinje" } \ No newline at end of file diff --git a/www/addons/myoverview/lang/uk.json b/www/addons/myoverview/lang/uk.json new file mode 100644 index 00000000000..1b4fb0f4e46 --- /dev/null +++ b/www/addons/myoverview/lang/uk.json @@ -0,0 +1,18 @@ +{ + "future": "Заплановані", + "inprogress": "В процесі", + "morecourses": "Більше курсів", + "next30days": "Наступні 30 днів", + "next7days": "Наступні 7 днів", + "nocourses": "Курси відсутні", + "nocoursesfuture": "Немає запланових курсів", + "nocoursesinprogress": "Курси в прогресі відсутні", + "nocoursespast": "Пройдені курси відсутні", + "noevents": "Наразі, заплановані активності відсутні", + "past": "Минулі", + "pluginname": "Огляд курсу", + "recentlyoverdue": "Нещодавно прострочені", + "sortbycourses": "Сортувати за назвою курсів", + "sortbydates": "Сортувати за датою", + "timeline": "Часова пряма" +} \ No newline at end of file diff --git a/www/addons/myoverview/lang/zh-cn.json b/www/addons/myoverview/lang/zh-cn.json index ce98820d486..0694737081f 100644 --- a/www/addons/myoverview/lang/zh-cn.json +++ b/www/addons/myoverview/lang/zh-cn.json @@ -1,5 +1,18 @@ { - "inprogress": "处理中", - "nocourses": "没有可显示的课程信息。", - "pluginname": "容器插件名" + "future": "未来", + "inprogress": "进行中", + "morecourses": "更多课程", + "next30days": "下一月", + "next7days": "下一周", + "nocourses": "没有课程", + "nocoursesfuture": "没有未来的课程", + "nocoursesinprogress": "没有进行中的课程", + "nocoursespast": "没有过去的课程", + "noevents": "没有即将到期的活动", + "past": "过去", + "pluginname": "课程概览", + "recentlyoverdue": "最近逾期的", + "sortbycourses": "按课程排序", + "sortbydates": "按日期排序", + "timeline": "时间进度" } \ No newline at end of file diff --git a/www/addons/myoverview/lang/zh-tw.json b/www/addons/myoverview/lang/zh-tw.json index 18cfa0860fc..16d60ff4766 100644 --- a/www/addons/myoverview/lang/zh-tw.json +++ b/www/addons/myoverview/lang/zh-tw.json @@ -11,7 +11,7 @@ "noevents": "沒有即將到期的活動", "past": "過去", "pluginname": "課程概觀", - "recentlyoverdue": "", + "recentlyoverdue": "最近逾期的", "sortbycourses": "依課程排序", "sortbydates": "依日期排序", "timeline": "時間軸" diff --git a/www/addons/notes/lang/ar.json b/www/addons/notes/lang/ar.json index df8de0cf069..30b58e0c705 100644 --- a/www/addons/notes/lang/ar.json +++ b/www/addons/notes/lang/ar.json @@ -2,7 +2,7 @@ "addnewnote": "إضافة ملاحظة جديدة", "coursenotes": "ملاحظات المقرر الدراسي", "note": "ملحوظة", - "notes": "تحليلك وملاحظاتك الخاصة", + "notes": "ملاحظات", "personalnotes": "ملاحظات شخصية", "publishstate": "السياق", "sitenotes": "ملاحظات الموقع" diff --git a/www/addons/notes/lang/bg.json b/www/addons/notes/lang/bg.json index 606e3b6a09d..89cc6664d9d 100644 --- a/www/addons/notes/lang/bg.json +++ b/www/addons/notes/lang/bg.json @@ -4,7 +4,7 @@ "eventnotecreated": "Бележката създадена", "nonotes": "Все още няма бележки от този тип.", "note": "Бележка", - "notes": "Бележки", + "notes": "Вашият личен анализ и бележки", "personalnotes": "Лични бележки", "publishstate": "Контекст", "sitenotes": "Бележки за сайта" diff --git a/www/addons/notes/lang/da.json b/www/addons/notes/lang/da.json index cf35362b164..3dadb18f0eb 100644 --- a/www/addons/notes/lang/da.json +++ b/www/addons/notes/lang/da.json @@ -4,7 +4,7 @@ "eventnotecreated": "Note oprettet", "nonotes": "Der er endnu ingen noter af denne type", "note": "Note", - "notes": "Dine private kommentarer og noter", + "notes": "Noter", "personalnotes": "Personlige noter", "publishstate": "Sammenhæng", "sitenotes": "Webstedsnoter", diff --git a/www/addons/notes/lang/es_mx.json b/www/addons/notes/lang/es_mx.json deleted file mode 100644 index 0eb20a78105..00000000000 --- a/www/addons/notes/lang/es_mx.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "addnewnote": "Añadir una nota nueva", - "coursenotes": "Notas del curso", - "eventnotecreated": "Nota creada", - "note": "Nota", - "personalnotes": "Notas personales", - "publishstate": "Contexto", - "sitenotes": "Notas del sitio" -} \ No newline at end of file diff --git a/www/addons/notes/lang/he.json b/www/addons/notes/lang/he.json index 2e3c5dd9644..416427b2dec 100644 --- a/www/addons/notes/lang/he.json +++ b/www/addons/notes/lang/he.json @@ -4,7 +4,7 @@ "eventnotecreated": "הערה נוצרה", "nonotes": "עדיין לא קיימות הערות מסוג זה", "note": "הערה", - "notes": "ההערות והניתוח הפרטיים שלך.", + "notes": "הערות", "personalnotes": "הערות אישיות", "publishstate": "תוכן", "sitenotes": "הערות אתר", diff --git a/www/addons/notes/lang/ja.json b/www/addons/notes/lang/ja.json index 31c68f19f28..6b3304c8067 100644 --- a/www/addons/notes/lang/ja.json +++ b/www/addons/notes/lang/ja.json @@ -1,10 +1,13 @@ { - "addnewnote": "新しいノートを追加する", + "addnewnote": "新しいノートを追加", "coursenotes": "コースノート", - "eventnotecreated": "ノートが作成されました。", + "eventnotecreated": "作成したノート", + "nonotes": "このタイプのノートはまだ存在しません", "note": "ノート", - "notes": "あなたの個人分析およびノート", + "notes": "ノート", "personalnotes": "パーソナルノート", - "publishstate": "コンテクスト", - "sitenotes": "サイトノート" + "publishstate": "コンテキスト", + "sitenotes": "サイトノート", + "userwithid": "ID {{id}} のユーザ", + "warningnotenotsent": "コース {{course}} にノートを追加することができません。 {{error}}" } \ No newline at end of file diff --git a/www/addons/notes/lang/pt_br.json b/www/addons/notes/lang/pt_br.json deleted file mode 100644 index 3d49facd550..00000000000 --- a/www/addons/notes/lang/pt_br.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "addnewnote": "Escrever uma nova anotação", - "coursenotes": "Anotações do Curso", - "eventnotecreated": "Anotação criada", - "note": "Anotação", - "personalnotes": "Anotações individuais", - "publishstate": "Estado", - "sitenotes": "Anotações do site" -} \ No newline at end of file diff --git a/www/addons/notes/lang/ro.json b/www/addons/notes/lang/ro.json index 605a02f2299..1115becc8d5 100644 --- a/www/addons/notes/lang/ro.json +++ b/www/addons/notes/lang/ro.json @@ -4,7 +4,7 @@ "eventnotecreated": "A fost creată o notă", "nonotes": "Momentan nu există note de acest tip", "note": "Notă", - "notes": "Note", + "notes": "Analiza şi notele tale particulare", "personalnotes": "Note personale", "publishstate": "Context", "sitenotes": "Note de site", diff --git a/www/addons/notes/lang/sr-cr.json b/www/addons/notes/lang/sr-cr.json new file mode 100644 index 00000000000..0690900c3c5 --- /dev/null +++ b/www/addons/notes/lang/sr-cr.json @@ -0,0 +1,13 @@ +{ + "addnewnote": "Додај нову белешку", + "coursenotes": "Белешке курса", + "eventnotecreated": "Белешка креирана", + "nonotes": "Још не постоје белешке овог типа", + "note": "Белешка", + "notes": "Белешке", + "personalnotes": "Личне белешке", + "publishstate": "Контекст", + "sitenotes": "Белешке сајта", + "userwithid": "Корисник са ID ознаком {{id}}", + "warningnotenotsent": "Није могуће додати белешку/е курсу {{course}}. {{error}}" +} \ No newline at end of file diff --git a/www/addons/notes/lang/sr-lt.json b/www/addons/notes/lang/sr-lt.json new file mode 100644 index 00000000000..d4a1ef87e7f --- /dev/null +++ b/www/addons/notes/lang/sr-lt.json @@ -0,0 +1,13 @@ +{ + "addnewnote": "Dodaj novu belešku", + "coursenotes": "Beleške kursa", + "eventnotecreated": "Beleška kreirana", + "nonotes": "Još ne postoje beleške ovog tipa", + "note": "Beleška", + "notes": "Beleške", + "personalnotes": "Lične beleške", + "publishstate": "Kontekst", + "sitenotes": "Beleške sajta", + "userwithid": "Korisnik sa ID oznakom {{id}}", + "warningnotenotsent": "Nije moguće dodati belešku/e kursu {{course}}. {{error}}" +} \ No newline at end of file diff --git a/www/addons/notes/lang/uk.json b/www/addons/notes/lang/uk.json index 8f58e17054e..8c815080c16 100644 --- a/www/addons/notes/lang/uk.json +++ b/www/addons/notes/lang/uk.json @@ -9,5 +9,5 @@ "publishstate": "Контекст", "sitenotes": "Записки сайту", "userwithid": "Користувач з Id {{id}}", - "warningnotenotsent": "Неможливо додати записку до курсу{{course}}. {{error}}" + "warningnotenotsent": "Неможливо додати записку до курсу {{course}}. {{error}}" } \ No newline at end of file diff --git a/www/addons/notes/lang/zh_cn.json b/www/addons/notes/lang/zh_cn.json deleted file mode 100644 index 786909fa20c..00000000000 --- a/www/addons/notes/lang/zh_cn.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "addnewnote": "添加新备注", - "coursenotes": "课程备注", - "eventnotecreated": "创建了笔记", - "note": "备注", - "personalnotes": "私人备注", - "publishstate": "上下文", - "sitenotes": "全站备注" -} \ No newline at end of file diff --git a/www/addons/notes/lang/zh_tw.json b/www/addons/notes/lang/zh_tw.json deleted file mode 100644 index 2b90c1325c7..00000000000 --- a/www/addons/notes/lang/zh_tw.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "addnewnote": "添加一筆新註記", - "coursenotes": "課程註記", - "eventnotecreated": "已建立註記", - "note": "註記", - "personalnotes": "個人的註記", - "publishstate": "使用的情境", - "sitenotes": "網站註記" -} \ No newline at end of file diff --git a/www/addons/notifications/controllers/preferences.js b/www/addons/notifications/controllers/preferences.js index 226a12fcaab..efe6168083f 100644 --- a/www/addons/notifications/controllers/preferences.js +++ b/www/addons/notifications/controllers/preferences.js @@ -23,23 +23,26 @@ angular.module('mm.addons.notifications') */ .controller('mmaNotificationsPreferencesCtrl', function($scope, $mmaNotifications, $mmUtil, $ionicPlatform, $mmUser, $mmConfig, $mmaMessageOutputDelegate, $q, $timeout, $mmSettingsHelper, mmCoreSettingsNotificationSound, $mmLocalNotifications, - $mmEvents, mmCoreEventNotificationSoundChanged) { + $mmEvents, mmCoreEventNotificationSoundChanged, $mmApp) { var updateTimeout; $scope.isTablet = $ionicPlatform.isTablet(); $scope.notifPrefsEnabled = $mmaNotifications.isNotificationPreferencesEnabled(); + $scope.canChangeSound = $mmLocalNotifications.isAvailable() && !$mmApp.isDesktop(); - // Notification sound setting. - $mmConfig.get(mmCoreSettingsNotificationSound, true).then(function(enabled) { - $scope.notificationSound = enabled; - }); + if ($scope.canChangeSound) { + // Notification sound setting. + $mmConfig.get(mmCoreSettingsNotificationSound, true).then(function(enabled) { + $scope.notificationSound = enabled; + }); - $scope.notificationSoundChanged = function(enabled) { - $mmConfig.set(mmCoreSettingsNotificationSound, enabled); - $mmEvents.trigger(mmCoreEventNotificationSoundChanged, enabled); - $mmLocalNotifications.rescheduleAll(); - }; + $scope.notificationSoundChanged = function(enabled) { + $mmConfig.set(mmCoreSettingsNotificationSound, enabled); + $mmEvents.trigger(mmCoreEventNotificationSoundChanged, enabled); + $mmLocalNotifications.rescheduleAll(); + }; + } if (!$scope.notifPrefsEnabled) { // Notification preferences aren't enabled, stop. diff --git a/www/addons/notifications/lang/ar.json b/www/addons/notifications/lang/ar.json index cab5daac101..edbc8f11446 100644 --- a/www/addons/notifications/lang/ar.json +++ b/www/addons/notifications/lang/ar.json @@ -1,5 +1,5 @@ { "errorgetnotifications": "خطأ في الحصول على الإشعارات", - "notifications": "إشعارات", + "notifications": "الإشعارات", "therearentnotificationsyet": "لا توجد إشعارات" } \ No newline at end of file diff --git a/www/addons/notifications/lang/da.json b/www/addons/notifications/lang/da.json index 2e190040f35..56219f0789c 100644 --- a/www/addons/notifications/lang/da.json +++ b/www/addons/notifications/lang/da.json @@ -1,6 +1,6 @@ { "errorgetnotifications": "Fejl ved hentning af underretninger", "notificationpreferences": "Indstillinger for underretninger", - "notifications": "Beskeder", + "notifications": "Underretninger", "therearentnotificationsyet": "Der er ingen underretninger" } \ No newline at end of file diff --git a/www/addons/notifications/lang/de.json b/www/addons/notifications/lang/de.json index 6dc2a08c68c..4175d5121e3 100644 --- a/www/addons/notifications/lang/de.json +++ b/www/addons/notifications/lang/de.json @@ -2,6 +2,6 @@ "errorgetnotifications": "Fehler beim Laden der Mitteilungen", "notificationpreferences": "Systemmitteilungen", "notifications": "Systemmitteilungen", - "playsound": "Audio abspielen", + "playsound": "Signalton abspielen", "therearentnotificationsyet": "Keine Mitteilungen" } \ No newline at end of file diff --git a/www/addons/notifications/lang/el.json b/www/addons/notifications/lang/el.json index 287c60968cc..d5d645008b8 100644 --- a/www/addons/notifications/lang/el.json +++ b/www/addons/notifications/lang/el.json @@ -2,5 +2,6 @@ "errorgetnotifications": "Σφάλμα κατά τη λήψη ειδοποιήσεων", "notificationpreferences": "Προτιμήσεις ειδοποιήσεων", "notifications": "Ειδοποιήσεις", + "playsound": "Αναπαραγωγή ήχου", "therearentnotificationsyet": "Δεν υπάρχουν ειδοποιήσεις" } \ No newline at end of file diff --git a/www/addons/notifications/lang/es.json b/www/addons/notifications/lang/es.json index e73e272de69..db11ade05af 100644 --- a/www/addons/notifications/lang/es.json +++ b/www/addons/notifications/lang/es.json @@ -2,5 +2,6 @@ "errorgetnotifications": "Error al obtener notificaciones", "notificationpreferences": "Preferencias de notificaciones", "notifications": "Notificaciones", + "playsound": "Reproducir sonido", "therearentnotificationsyet": "No hay notificaciones" } \ No newline at end of file diff --git a/www/addons/notifications/lang/es_mx.json b/www/addons/notifications/lang/es_mx.json deleted file mode 100644 index 80b4b5e0dbc..00000000000 --- a/www/addons/notifications/lang/es_mx.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "notifications": "Notificaciones", - "therearentnotificationsyet": "No hay notificaciones" -} \ No newline at end of file diff --git a/www/addons/notifications/lang/fa.json b/www/addons/notifications/lang/fa.json index dcfecb86fba..f641bf74805 100644 --- a/www/addons/notifications/lang/fa.json +++ b/www/addons/notifications/lang/fa.json @@ -1,5 +1,5 @@ { "notificationpreferences": "ترجیحات اطلاعیه‌ها", - "notifications": "هشدارها", + "notifications": "تذکرات", "therearentnotificationsyet": "هیچ هشداری وجود ندارد" } \ No newline at end of file diff --git a/www/addons/notifications/lang/fr.json b/www/addons/notifications/lang/fr.json index edb4a631896..f5c2621dbba 100644 --- a/www/addons/notifications/lang/fr.json +++ b/www/addons/notifications/lang/fr.json @@ -2,5 +2,6 @@ "errorgetnotifications": "Erreur lors de la récupération des notifications.", "notificationpreferences": "Préférences de notification", "notifications": "Notifications", + "playsound": "Jouer le son", "therearentnotificationsyet": "Aucune notification" } \ No newline at end of file diff --git a/www/addons/notifications/lang/he.json b/www/addons/notifications/lang/he.json index 39e5a6ed7a5..1c1591b94ed 100644 --- a/www/addons/notifications/lang/he.json +++ b/www/addons/notifications/lang/he.json @@ -1,6 +1,6 @@ { "errorgetnotifications": "שגיאה בטעינת התראות", "notificationpreferences": "העדפות הודעות", - "notifications": "עדכונים והודעות", + "notifications": "התראות", "therearentnotificationsyet": "אין התראות" } \ No newline at end of file diff --git a/www/addons/notifications/lang/ja.json b/www/addons/notifications/lang/ja.json index a253cfba0ae..22daa00358e 100644 --- a/www/addons/notifications/lang/ja.json +++ b/www/addons/notifications/lang/ja.json @@ -1,5 +1,7 @@ { - "notificationpreferences": "通知プリファレンス", + "errorgetnotifications": "通知の取得中にエラーが発生しました。", + "notificationpreferences": "通知の設定", "notifications": "通知", + "playsound": "音を出力", "therearentnotificationsyet": "通知はありません" } \ No newline at end of file diff --git a/www/addons/notifications/lang/pt_br.json b/www/addons/notifications/lang/pt_br.json deleted file mode 100644 index 3913f917f41..00000000000 --- a/www/addons/notifications/lang/pt_br.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "notifications": "Notificação", - "therearentnotificationsyet": "Não há notificações" -} \ No newline at end of file diff --git a/www/addons/notifications/lang/ru.json b/www/addons/notifications/lang/ru.json index 46e6247828f..3bb79943f46 100644 --- a/www/addons/notifications/lang/ru.json +++ b/www/addons/notifications/lang/ru.json @@ -2,5 +2,6 @@ "errorgetnotifications": "Ошибка получения уведомления", "notificationpreferences": "Настройка уведомлений", "notifications": "Уведомления", + "playsound": "Проигрывать звук", "therearentnotificationsyet": "Уведомлений нет" } \ No newline at end of file diff --git a/www/addons/notifications/lang/sr-cr.json b/www/addons/notifications/lang/sr-cr.json new file mode 100644 index 00000000000..f45f0611020 --- /dev/null +++ b/www/addons/notifications/lang/sr-cr.json @@ -0,0 +1,7 @@ +{ + "errorgetnotifications": "Грешка приликом преузимања обавештења", + "notificationpreferences": "Параметри обавештења", + "notifications": "Обавештења", + "playsound": "Репродукуј звук", + "therearentnotificationsyet": "Нема обавештења" +} \ No newline at end of file diff --git a/www/addons/notifications/lang/sr-lt.json b/www/addons/notifications/lang/sr-lt.json new file mode 100644 index 00000000000..74bfd3d17cb --- /dev/null +++ b/www/addons/notifications/lang/sr-lt.json @@ -0,0 +1,7 @@ +{ + "errorgetnotifications": "Greška prilikom preuzimanja obaveštenja", + "notificationpreferences": "Parametri obaveštenja", + "notifications": "Obaveštenja", + "playsound": "Reprodukuj zvuk", + "therearentnotificationsyet": "Nema obaveštenja" +} \ No newline at end of file diff --git a/www/addons/notifications/lang/sv.json b/www/addons/notifications/lang/sv.json index 2aa4e69322a..8029962c563 100644 --- a/www/addons/notifications/lang/sv.json +++ b/www/addons/notifications/lang/sv.json @@ -1,5 +1,6 @@ { "errorgetnotifications": "Fel att få meddelanden", + "notificationpreferences": "Välj inställningar för notiser", "notifications": "Meddelanden", "therearentnotificationsyet": "Det finns inga meddelanden" } \ No newline at end of file diff --git a/www/addons/notifications/lang/zh_cn.json b/www/addons/notifications/lang/zh_cn.json deleted file mode 100644 index 7d236d7f15d..00000000000 --- a/www/addons/notifications/lang/zh_cn.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "notifications": "通知", - "therearentnotificationsyet": "没有通知" -} \ No newline at end of file diff --git a/www/addons/notifications/lang/zh_tw.json b/www/addons/notifications/lang/zh_tw.json deleted file mode 100644 index 957a61b5db7..00000000000 --- a/www/addons/notifications/lang/zh_tw.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "notifications": "通知", - "therearentnotificationsyet": "沒有通知訊息" -} \ No newline at end of file diff --git a/www/addons/notifications/main.js b/www/addons/notifications/main.js index 715ca9acb8d..d178e938f10 100644 --- a/www/addons/notifications/main.js +++ b/www/addons/notifications/main.js @@ -19,6 +19,7 @@ angular.module('mm.addons.notifications', []) .constant('mmaNotificationsPreferencesPriority', 500) .constant('mmaNotificationsReadChangedEvent', 'mma-notifications_read_changed') .constant('mmaNotificationsReadCronEvent', 'mma-notifications_read_cron') +.constant('mmaNotificationsPushSimulationComponent', 'mmaNotificationsPushSimulation') .config(function($stateProvider, $mmSideMenuDelegateProvider, mmaNotificationsPriority, $mmSettingsDelegateProvider, mmaNotificationsPreferencesPriority) { @@ -53,7 +54,8 @@ angular.module('mm.addons.notifications', []) '$mmaNotificationsHandlers.preferences', mmaNotificationsPreferencesPriority); }) -.run(function($log, $mmaNotifications, $mmUtil, $state, $mmAddonManager, $mmCronDelegate, $mmSitesManager) { +.run(function($log, $mmaNotifications, $mmUtil, $state, $mmAddonManager, $mmCronDelegate, $mmSitesManager, $mmLocalNotifications, + $mmApp, mmaNotificationsPushSimulationComponent) { $log = $log.getInstance('mmaNotifications'); // Register push notification clicks. @@ -61,19 +63,7 @@ angular.module('mm.addons.notifications', []) if ($mmPushNotificationsDelegate) { $mmPushNotificationsDelegate.registerHandler('mmaNotifications', function(notification) { if ($mmUtil.isTrueOrOne(notification.notif)) { - $mmaNotifications.isPluginEnabledForSite(notification.site).then(function() { - $mmSitesManager.isFeatureDisabled('$mmSideMenuDelegate_mmaNotifications', notification.site) - .then(function(disabled) { - if (disabled) { - // Notifications are disabled, stop. - return; - } - - $mmaNotifications.invalidateNotificationsList().finally(function() { - $state.go('redirect', {siteid: notification.site, state: 'site.notifications'}); - }); - }); - }); + notificationClicked(notification); return true; } }); @@ -81,4 +71,26 @@ angular.module('mm.addons.notifications', []) // Register sync process. $mmCronDelegate.register('mmaNotificationsMenu', '$mmaNotificationsHandlers.sideMenuNav'); + + if ($mmApp.isDesktop()) { + // Listen for clicks in simulated push notifications. + $mmLocalNotifications.registerClick(mmaNotificationsPushSimulationComponent, notificationClicked); + } + + // A push notification belonging to notifications was clicked. + function notificationClicked(notification) { + return $mmaNotifications.isPluginEnabledForSite(notification.site).then(function() { + $mmSitesManager.isFeatureDisabled('$mmSideMenuDelegate_mmaNotifications', notification.site) + .then(function(disabled) { + if (disabled) { + // Notifications are disabled, stop. + return; + } + + $mmaNotifications.invalidateNotificationsList().finally(function() { + $state.go('redirect', {siteid: notification.site, state: 'site.notifications'}); + }); + }); + }); + } }); diff --git a/www/addons/notifications/services/handlers.js b/www/addons/notifications/services/handlers.js index f832baa8c98..9dd39235d82 100644 --- a/www/addons/notifications/services/handlers.js +++ b/www/addons/notifications/services/handlers.js @@ -24,11 +24,38 @@ angular.module('mm.addons.notifications') * @name $mmaNotificationsHandlers */ .factory('$mmaNotificationsHandlers', function($log, $mmaNotifications, $mmEvents, $mmSitesManager, $mmUtil, $mmSite, - mmaNotificationsReadChangedEvent, mmaNotificationsReadCronEvent, $mmAddonManager) { + mmaNotificationsReadChangedEvent, mmaNotificationsReadCronEvent, $mmAddonManager, $mmApp, $mmLocalNotifications, + $mmEmulatorHelper, $mmText, mmaNotificationsPushSimulationComponent) { $log = $log.getInstance('$mmaNotificationsHandlers'); var self = {}; + /** + * Get the latest unread notifications from a site. + * + * @param {String} siteId Site ID. + * @return {Promise} Promise resolved with the notifications. + */ + function fetchNotifications(siteId) { + return $mmaNotifications.getUnreadNotifications(0, undefined, true, false, true, siteId); + } + + /** + * Given a notification, return the title and the text for the notification. + * + * @param {Object} notification Notification. + * @return {Object} Object with title and text. + */ + function getTitleAndText(notification) { + var data = { + title: notification.userfromfullname, + text: notification.mobiletext.replace(/-{4,}/ig, '') + }; + data.text = $mmText.replaceNewLines(data.text, '
'); + + return data; + } + /** * Side menu nav handler. * @@ -142,6 +169,11 @@ angular.module('mm.addons.notifications') siteid: siteId }); } + + if ($mmApp.isDesktop() && $mmLocalNotifications.isAvailable()) { + $mmEmulatorHelper.checkNewNotifications( + mmaNotificationsPushSimulationComponent, fetchNotifications, getTitleAndText, siteId); + } }; /** @@ -150,7 +182,7 @@ angular.module('mm.addons.notifications') * @return {Number} Time between consecutive executions (in ms). */ self.getInterval = function() { - return 600000; // 10 minutes. + return $mmApp.isDesktop() ? 60000 : 600000; // 1 or 10 minutes. }; /** @@ -159,8 +191,9 @@ angular.module('mm.addons.notifications') * @return {Boolean} True if is a sync process, false otherwise. */ self.isSync = function() { - // This is done to use only wifi if using the fallback function - return !$mmaNotifications.isNotificationCountEnabled(); + // This is done to use only wifi if using the fallback function. + // In desktop it is always sync, since it fetches notification to see if there's a new one. + return !$mmaNotifications.isNotificationCountEnabled() || $mmApp.isDesktop(); }; /** diff --git a/www/addons/notifications/services/notifications.js b/www/addons/notifications/services/notifications.js index 44e7179dca3..58a3470f1ba 100644 --- a/www/addons/notifications/services/notifications.js +++ b/www/addons/notifications/services/notifications.js @@ -21,13 +21,19 @@ angular.module('mm.addons.notifications') * @ngdoc service * @name $mmaNotifications */ -.factory('$mmaNotifications', function($q, $log, $mmSite, $mmSitesManager, $mmUser, $mmUtil, mmaNotificationsListLimit) { +.factory('$mmaNotifications', function($q, $log, $mmSite, $mmSitesManager, $mmUser, $mmUtil, $mmApp, mmaNotificationsListLimit, + mmaNotificationsPushSimulationComponent, $mmEmulatorHelper) { $log = $log.getInstance('$mmaNotifications'); var self = {}; - // Function to format notification data. + /** + * Function to format notification data. + * + * @param {Object[]} notifications List of notifications. + * @return {Void} + */ function formatNotificationsData(notifications) { angular.forEach(notifications, function(notification) { // Set message to show. @@ -97,39 +103,60 @@ angular.module('mm.addons.notifications') * @module mm.addons.notifications * @ngdoc method * @name $mmaNotifications#getNotifications - * @param {Boolean} read True if should get read notifications, false otherwise. - * @param {Number} limitFrom Position of the first notification to get. - * @param {Number} limitNumber Number of notifications to get. - * @return {Promise} Promise resolved with notifications. + * @param {Boolean} read True if should get read notifications, false otherwise. + * @param {Number} limitFrom Position of the first notification to get. + * @param {Number} limitNumber Number of notifications to get. + * @param {Boolean} [toDisplay=true] True if notifications will be displayed to the user, either in view or in a notification. + * @param {Boolean} [forceCache] True if it should return cached data. Has priority over ignoreCache. + * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} [siteId] Site ID. If not defined, use current site. + * @return {Promise} Promise resolved with notifications. */ - self.getNotifications = function(read, limitFrom, limitNumber) { + self.getNotifications = function(read, limitFrom, limitNumber, toDisplay, forceCache, ignoreCache, siteId) { + toDisplay = typeof toDisplay == 'undefined' ? true : toDisplay; limitFrom = limitFrom || 0; limitNumber = limitNumber || mmaNotificationsListLimit; + siteId = siteId || $mmSite.getId(); $log.debug('Get ' + (read ? 'read' : 'unread') + ' notifications from ' + limitFrom + '. Limit: ' + limitNumber); - var data = { - useridto: $mmSite.getUserId(), - useridfrom: 0, - type: 'notifications', - read: read ? 1 : 0, - newestfirst: 1, - limitfrom: limitFrom, - limitnum: limitNumber - }; - var preSets = { - cacheKey: getNotificationsCacheKey() - }; - - // Get unread notifications. - return $mmSite.read('core_message_get_messages', data, preSets).then(function(response) { - if (response.messages) { - var notifications = response.messages; - formatNotificationsData(notifications); - return notifications; - } else { - return $q.reject(); + return $mmSitesManager.getSite(siteId).then(function(site) { + var data = { + useridto: site.getUserId(), + useridfrom: 0, + type: 'notifications', + read: read ? 1 : 0, + newestfirst: 1, + limitfrom: limitFrom, + limitnum: limitNumber + }, preSets = { + cacheKey: getNotificationsCacheKey() + }; + + if (forceCache) { + preSets.omitExpires = true; + } else if (ignoreCache) { + preSets.getFromCache = 0; + preSets.emergencyCache = 0; } + + // Get unread notifications. + return site.read('core_message_get_messages', data, preSets).then(function(response) { + if (response.messages) { + var notifications = response.messages; + formatNotificationsData(notifications); + + if ($mmApp.isDesktop() && toDisplay && !read && limitFrom === 0) { + // Store the last received notification. Don't block the user for this. + $mmEmulatorHelper.storeLastReceivedNotification( + mmaNotificationsPushSimulationComponent, notifications[0], siteId); + } + + return notifications; + } else { + return $q.reject(); + } + }); }); }; @@ -139,12 +166,16 @@ angular.module('mm.addons.notifications') * @module mm.addons.notifications * @ngdoc method * @name $mmaNotifications#getReadNotifications - * @param {Number} limitFrom Position of the first notification to get. - * @param {Number} limitNumber Number of notifications to get. - * @return {Promise} Promise resolved with notifications. + * @param {Number} limitFrom Position of the first notification to get. + * @param {Number} limitNumber Number of notifications to get. + * @param {Boolean} [toDisplay=true] True if notifications will be displayed to the user, either in view or in a notification. + * @param {Boolean} [forceCache] True if it should return cached data. Has priority over ignoreCache. + * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} [siteId] Site ID. If not defined, use current site. + * @return {Promise} Promise resolved with notifications. */ - self.getReadNotifications = function(limitFrom, limitNumber) { - return self.getNotifications(true, limitFrom, limitNumber); + self.getReadNotifications = function(limitFrom, limitNumber, toDisplay, forceCache, ignoreCache, siteId) { + return self.getNotifications(true, limitFrom, limitNumber, toDisplay, forceCache, ignoreCache, siteId); }; /** @@ -153,12 +184,16 @@ angular.module('mm.addons.notifications') * @module mm.addons.notifications * @ngdoc method * @name $mmaNotifications#getUnreadNotifications - * @param {Number} limitFrom Position of the first notification to get. - * @param {Number} limitNumber Number of notifications to get. - * @return {Promise} Promise resolved with notifications. + * @param {Number} limitFrom Position of the first notification to get. + * @param {Number} limitNumber Number of notifications to get. + * @param {Boolean} [toDisplay=true] True if notifications will be displayed to the user, either in view or in a notification. + * @param {Boolean} [forceCache] True if it should return cached data. Has priority over ignoreCache. + * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} [siteId] Site ID. If not defined, use current site. + * @return {Promise} Promise resolved with notifications. */ - self.getUnreadNotifications = function(limitFrom, limitNumber) { - return self.getNotifications(false, limitFrom, limitNumber); + self.getUnreadNotifications = function(limitFrom, limitNumber, toDisplay, forceCache, ignoreCache, siteId) { + return self.getNotifications(false, limitFrom, limitNumber, toDisplay, forceCache, ignoreCache, siteId); }; /** @@ -193,7 +228,8 @@ angular.module('mm.addons.notifications') } // Fallback call. - return self.getNotifications(false, 0, mmaNotificationsListLimit + 1).then(function(unread) { + var limit = mmaNotificationsListLimit + 1; + return self.getUnreadNotifications(0, limit, false, false, false, siteId).then(function(unread) { // Add + sign if there are more than the limit reachable. return (unread.length > mmaNotificationsListLimit) ? unread.length + "+" : unread.length; }).catch(function() { diff --git a/www/addons/notifications/templates/preferences.html b/www/addons/notifications/templates/preferences.html index 94ec50727c0..1b35e02a80b 100644 --- a/www/addons/notifications/templates/preferences.html +++ b/www/addons/notifications/templates/preferences.html @@ -10,7 +10,7 @@ - +

{{ 'mma.notifications.playsound' | translate }}

@@ -19,7 +19,7 @@ {{ 'mm.settings.disableall' | translate }} - +

{{ 'mma.notifications.playsound' | translate }}

diff --git a/www/addons/participants/lang/ar.json b/www/addons/participants/lang/ar.json index 91db007489d..8c013f870e2 100644 --- a/www/addons/participants/lang/ar.json +++ b/www/addons/participants/lang/ar.json @@ -1,4 +1,4 @@ { "noparticipants": "لم يتم العثور على مشاركين في هذا المقرر الدراسي", - "participants": "المشتركون" + "participants": "المشاركين" } \ No newline at end of file diff --git a/www/addons/participants/lang/es_mx.json b/www/addons/participants/lang/es_mx.json deleted file mode 100644 index 9ec3327c06d..00000000000 --- a/www/addons/participants/lang/es_mx.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "participants": "Participantes" -} \ No newline at end of file diff --git a/www/addons/participants/lang/fa.json b/www/addons/participants/lang/fa.json index 34112f687d7..90d51eaa038 100644 --- a/www/addons/participants/lang/fa.json +++ b/www/addons/participants/lang/fa.json @@ -1,4 +1,4 @@ { - "noparticipants": "این درس شرکت‌کننده‌ای ندارد", + "noparticipants": "هیچ شرکت‌کننده‌ای پیدا نشد.", "participants": "شرکت کنندگان" } \ No newline at end of file diff --git a/www/addons/participants/lang/he.json b/www/addons/participants/lang/he.json index 669a9a80dfd..5c487a42ed3 100644 --- a/www/addons/participants/lang/he.json +++ b/www/addons/participants/lang/he.json @@ -1,4 +1,4 @@ { - "noparticipants": "לא נמצאו משתתפים עבור קורס זה", + "noparticipants": "טרם צורפו משתתפים.", "participants": "משתתפים" } \ No newline at end of file diff --git a/www/addons/participants/lang/hu.json b/www/addons/participants/lang/hu.json index 929c510a598..f1cb5cf7cf6 100644 --- a/www/addons/participants/lang/hu.json +++ b/www/addons/participants/lang/hu.json @@ -1,4 +1,4 @@ { - "noparticipants": "A kurzushoz nincsenek résztvevők!", + "noparticipants": "Nincs résztvevő.", "participants": "Résztvevők" } \ No newline at end of file diff --git a/www/addons/participants/lang/ja.json b/www/addons/participants/lang/ja.json index 8fbbcbb3976..3656df9f659 100644 --- a/www/addons/participants/lang/ja.json +++ b/www/addons/participants/lang/ja.json @@ -1,4 +1,4 @@ { - "noparticipants": "このコースには参加者が登録されていません。", + "noparticipants": "このコースには参加者がいません。", "participants": "参加者" } \ No newline at end of file diff --git a/www/addons/participants/lang/pl.json b/www/addons/participants/lang/pl.json index 5025bf740ec..adceacdf5a7 100644 --- a/www/addons/participants/lang/pl.json +++ b/www/addons/participants/lang/pl.json @@ -1,4 +1,4 @@ { - "noparticipants": "Nie znaleziono uczestników w tym kursie", + "noparticipants": "Nie znaleziono uczestników.", "participants": "Uczestnicy" } \ No newline at end of file diff --git a/www/addons/participants/lang/pt_br.json b/www/addons/participants/lang/pt_br.json deleted file mode 100644 index 9ec3327c06d..00000000000 --- a/www/addons/participants/lang/pt_br.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "participants": "Participantes" -} \ No newline at end of file diff --git a/www/addons/participants/lang/ro.json b/www/addons/participants/lang/ro.json index 57abb945354..0c2fa9e2bad 100644 --- a/www/addons/participants/lang/ro.json +++ b/www/addons/participants/lang/ro.json @@ -1,4 +1,4 @@ { - "noparticipants": "Nu au fost găsiți participanți la acest curs.", - "participants": "Participanți" + "noparticipants": "Nu există participanți la acest curs", + "participants": "Participanţi" } \ No newline at end of file diff --git a/www/addons/participants/lang/ru.json b/www/addons/participants/lang/ru.json index 590333bcb2f..bcfa292346e 100644 --- a/www/addons/participants/lang/ru.json +++ b/www/addons/participants/lang/ru.json @@ -1,4 +1,4 @@ { - "noparticipants": "Не найдены участники для этого курса.", + "noparticipants": "Участники не найдены.", "participants": "Участники" } \ No newline at end of file diff --git a/www/addons/participants/lang/sr-cr.json b/www/addons/participants/lang/sr-cr.json new file mode 100644 index 00000000000..5c5170c3c41 --- /dev/null +++ b/www/addons/participants/lang/sr-cr.json @@ -0,0 +1,4 @@ +{ + "noparticipants": "Ниједан учесник није пронађен на овом курсу.", + "participants": "Учесници" +} \ No newline at end of file diff --git a/www/addons/participants/lang/sr-lt.json b/www/addons/participants/lang/sr-lt.json new file mode 100644 index 00000000000..090378abb39 --- /dev/null +++ b/www/addons/participants/lang/sr-lt.json @@ -0,0 +1,4 @@ +{ + "noparticipants": "Nijedan učesnik nije pronađen na ovom kursu.", + "participants": "Učesnici" +} \ No newline at end of file diff --git a/www/addons/participants/lang/zh_cn.json b/www/addons/participants/lang/zh_cn.json deleted file mode 100644 index 36c81dc05e0..00000000000 --- a/www/addons/participants/lang/zh_cn.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "participants": "课程参与者" -} \ No newline at end of file diff --git a/www/addons/participants/lang/zh_tw.json b/www/addons/participants/lang/zh_tw.json deleted file mode 100644 index 64c7fde824b..00000000000 --- a/www/addons/participants/lang/zh_tw.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "participants": "參與者" -} \ No newline at end of file diff --git a/www/config.json b/www/config.json index 8567b881866..9a558ca27cb 100644 --- a/www/config.json +++ b/www/config.json @@ -1,11 +1,12 @@ { "app_id" : "com.moodle.moodlemobile", "appname": "Moodle Mobile", - "versioncode" : "2018", - "versionname" : "3.3.0", + "desktopappname": "Moodle Desktop", + "versioncode" : "2019", + "versionname" : "3.3.1", "cache_expiration_time" : 300000, "default_lang" : "en", - "languages": {"ar": "عربي", "bg": "Български", "ca": "Català", "cs": "Čeština", "da": "Dansk", "de": "Deutsch", "el": "Ελληνικά", "en": "English", "es": "Español", "es-mx": "Español - México", "eu": "Euskara", "fa": "فارسی", "fr" : "Français", "he" : "עברית", "hu": "magyar", "it": "Italiano", "ja": "日本語","nl": "Nederlands", "pl": "Polski", "pt-br": "Português - Brasil", "pt": "Português - Portugal", "ro": "Română", "ru": "Русский", "sv": "Svenska", "tr" : "Türkçe", "uk" : "Українська", "zh-cn" : "简体中文", "zh-tw" : "正體中文"}, + "languages": {"ar": "عربي", "bg": "Български", "ca": "Català", "cs": "Čeština", "da": "Dansk", "de": "Deutsch", "el": "Ελληνικά", "en": "English", "es": "Español", "es-mx": "Español - México", "eu": "Euskara", "fa": "فارسی", "fr" : "Français", "he" : "עברית", "hu": "magyar", "it": "Italiano", "lt" : "Lietuvių", "ja": "日本語","nl": "Nederlands", "pl": "Polski", "pt-br": "Português - Brasil", "pt": "Português - Portugal", "ro": "Română", "ru": "Русский", "sr-cr": "Српски", "sr-lt": "Srpski", "sv": "Svenska", "tr" : "Türkçe", "uk" : "Українська", "zh-cn" : "简体中文", "zh-tw" : "正體中文"}, "wsservice" : "moodle_mobile_app", "wsextservice" : "local_mobile", "demo_sites": {"student": {"url": "http://school.demo.moodle.net", "username": "student", "password": "moodle"}, "teacher": {"url": "http://school.demo.moodle.net", "username": "teacher", "password": "moodle"}, "cva": {"url": "http://mm.cvaconsulting.com/moodle", "username": "student", "password": "student"}}, diff --git a/www/core/components/comments/services/comments.js b/www/core/components/comments/services/comments.js index 274e3556028..c5c0f945b0a 100644 --- a/www/core/components/comments/services/comments.js +++ b/www/core/components/comments/services/comments.js @@ -72,14 +72,12 @@ angular.module('mm.core.comments') * @return {Promise} Promise resolved with the comments. */ self.getComments = function(contextLevel, instanceId, component, itemId, area, page, siteId) { - siteId = siteId || $mmSite.getId(); - return $mmSitesManager.getSite(siteId).then(function(site) { var params = { "contextlevel": contextLevel, - "instanceid": instanceId, + "instanceid": parseInt(instanceId, 10), "component": component, - "itemid": itemId + "itemid": parseInt(itemId, 10) }, preSets = {}; @@ -118,7 +116,6 @@ angular.module('mm.core.comments') * @return {Promise} Promise resolved when the data is invalidated. */ self.invalidateCommentsData = function(contextLevel, instanceId, component, itemId, area, page, siteId) { - siteId = siteId || $mmSite.getId(); return $mmSitesManager.getSite(siteId).then(function(site) { return site.invalidateWsCacheForKey(getCommentsCacheKey(contextLevel, instanceId, component, itemId, area, page)); }); @@ -135,7 +132,6 @@ angular.module('mm.core.comments') * @return {Promise} Promise resolved when the data is invalidated. */ self.invalidateCommentsByInstance = function(contextLevel, instanceId, siteId) { - siteId = siteId || $mmSite.getId(); return $mmSitesManager.getSite(siteId).then(function(site) { return site.invalidateWsCacheForKeyStartingWith(getCommentsPrefixCacheKey(contextLevel, instanceId)); }); @@ -151,8 +147,6 @@ angular.module('mm.core.comments') * @return {Promise} Promise resolved with true if plugin is enabled, rejected or resolved with false otherwise. */ self.isPluginEnabled = function(siteId) { - siteId = siteId || $mmSite.getId(); - return $mmSitesManager.getSite(siteId).then(function(site) { return site.wsAvailable('core_comment_get_comments'); }); diff --git a/www/core/components/contentlinks/lang/ja.json b/www/core/components/contentlinks/lang/ja.json new file mode 100644 index 00000000000..625c4385040 --- /dev/null +++ b/www/core/components/contentlinks/lang/ja.json @@ -0,0 +1,7 @@ +{ + "chooseaccount": "アカウントの選択", + "chooseaccounttoopenlink": "リンクを開くアカウントを選択してください。", + "confirmurlothersite": "このリンクは別のサイトに属しています。本当に開きますか?", + "errornoactions": "このリンクを実行するためのアクションが見つかりませんでした。", + "errornosites": "このリンクをもつサイトが見つかりませんでした。" +} \ No newline at end of file diff --git a/www/core/components/contentlinks/lang/sr-cr.json b/www/core/components/contentlinks/lang/sr-cr.json new file mode 100644 index 00000000000..9091dad7d56 --- /dev/null +++ b/www/core/components/contentlinks/lang/sr-cr.json @@ -0,0 +1,7 @@ +{ + "chooseaccount": "Изабери налог", + "chooseaccounttoopenlink": "Изаберите налог са којим треба отворити линк.", + "confirmurlothersite": "Овај линк припада другом сајту. Да ли желите да га отворите?", + "errornoactions": "Није могуће пронаћи акцију коју треба извести са овим линком.", + "errornosites": "Није могуће пронаћи било који сајт који може изаћи на крај са овим линком." +} \ No newline at end of file diff --git a/www/core/components/contentlinks/lang/sr-lt.json b/www/core/components/contentlinks/lang/sr-lt.json new file mode 100644 index 00000000000..2d375d7a366 --- /dev/null +++ b/www/core/components/contentlinks/lang/sr-lt.json @@ -0,0 +1,7 @@ +{ + "chooseaccount": "Izaberi nalog", + "chooseaccounttoopenlink": "Izaberite nalog sa kojim treba otvoriti link.", + "confirmurlothersite": "Ovaj link pripada drugom sajtu. Da li želite da ga otvorite?", + "errornoactions": "Nije moguće pronaći akciju koju treba izvesti sa ovim linkom.", + "errornosites": "Nije moguće pronaći bilo koji sajt koji može izaći na kraj sa ovim linkom." +} \ No newline at end of file diff --git a/www/core/components/contentlinks/lang/uk.json b/www/core/components/contentlinks/lang/uk.json index a759354d9f2..7ee18752677 100644 --- a/www/core/components/contentlinks/lang/uk.json +++ b/www/core/components/contentlinks/lang/uk.json @@ -2,6 +2,6 @@ "chooseaccount": "Виберіть аккаунт", "chooseaccounttoopenlink": "Виберіть обліковий запис, щоб відкрити посилання.", "confirmurlothersite": "Це посилання відноситься до іншого місця. Ви хочете відкрити?", - "errornoactions": "Не вдалося знайти дію, яка виконує за цим посиланням.", + "errornoactions": "Не вдалося знайти дію, яка виконується за цим посиланням.", "errornosites": "Не вдалося знайти сайт, щоб впоратися з цим посиланням." } \ No newline at end of file diff --git a/www/core/components/contentlinks/services/delegate.js b/www/core/components/contentlinks/services/delegate.js index 892378b608d..f9b7e9ca23c 100644 --- a/www/core/components/contentlinks/services/delegate.js +++ b/www/core/components/contentlinks/services/delegate.js @@ -191,7 +191,7 @@ angular.module('mm.core.contentlinks') } if (handler.instance && handler.instance.handles) { - var siteUrl = handler.instance.handles(url); + var siteUrl = handler.instance.getHandlerUrl(url); if (siteUrl) { return siteUrl; } diff --git a/www/core/components/contentlinks/services/handlerfactory.js b/www/core/components/contentlinks/services/handlerfactory.js index 65fb04662e2..8490f1adbf2 100644 --- a/www/core/components/contentlinks/services/handlerfactory.js +++ b/www/core/components/contentlinks/services/handlerfactory.js @@ -46,13 +46,23 @@ angular.module('mm.core') return []; }; + /** + * Check if the URL is handled by this handler. + * + * @param {String} url URL to check. + * @return {Boolean} If the URL is handled. + */ + this.handles = function(url) { + return this.pattern && url.search(this.pattern) >= 0; + }; + /** * Check if the URL is handled by this handler. If so, returns the URL of the site. * * @param {String} url URL to check. * @return {String} Site URL. Undefined if the URL doesn't belong to this handler. */ - this.handles = function(url) { + this.getHandlerUrl = function(url) { if (this.pattern) { var position = url.search(this.pattern); if (position > -1) { diff --git a/www/core/components/course/controllers/sections.js b/www/core/components/course/controllers/sections.js index 82f9dbd431e..bd515513f06 100644 --- a/www/core/components/course/controllers/sections.js +++ b/www/core/components/course/controllers/sections.js @@ -25,7 +25,8 @@ angular.module('mm.core.course') $mmSite, $mmCoursePrefetchDelegate, $mmCourses, $q, $ionicHistory, $ionicPlatform, mmCoreCourseAllSectionsId, mmCoreEventSectionStatusChanged, $state, $timeout, $mmCoursesDelegate, $controller) { var courseId = $stateParams.courseid, - sectionId = $stateParams.sid, + sectionId = parseInt($stateParams.sid, 10), + sectionNumber = parseInt($stateParams.sectionnumber, 10), moduleId = $stateParams.moduleid, course = $stateParams.course ? angular.copy($stateParams.course) : false; @@ -130,9 +131,9 @@ angular.module('mm.core.course') }).then(function(downloadpromises) { // If we restored any download we'll recalculate the status once all of them have finished. if (downloadpromises && downloadpromises.length) { - $mmUtil.allPromises(downloadpromises).catch(function() { + $mmUtil.allPromises(downloadpromises).catch(function(error) { if (!$scope.$$destroyed) { - $mmUtil.showErrorModal('mm.course.errordownloadingsection', true); + $mmUtil.showErrorModalDefault(error, 'mm.course.errordownloadingsection', true); } }).finally(function() { if (!$scope.$$destroyed) { @@ -147,7 +148,7 @@ angular.module('mm.core.course') // Prefetch a section. The second parameter indicates if the prefetch was started manually (true) // or it was automatically started because all modules are being downloaded (false). function prefetch(section, manual) { - $mmCourseHelper.prefetch(section, courseId, $scope.sections).catch(function() { + $mmCourseHelper.prefetch(section, courseId, $scope.sections).catch(function(error) { // Don't show error message if scope is destroyed or it's an automatic download but we aren't in this state. if ($scope.$$destroyed) { return; @@ -160,7 +161,7 @@ angular.module('mm.core.course') return; } - $mmUtil.showErrorModal('mm.course.errordownloadingsection', true); + $mmUtil.showErrorModalDefault(error, 'mm.course.errordownloadingsection', true); }).finally(function() { if (!$scope.$$destroyed) { // Recalculate the status. @@ -171,14 +172,17 @@ angular.module('mm.core.course') // Convenience function to autoload a section if sectionId param is set. function autoloadSection() { - if (sectionId) { + if (sectionId || sectionNumber >= 0) { if ($ionicPlatform.isTablet()) { // Search the position of the section to load. - angular.forEach($scope.sections, function(section, index) { - if (section.id == sectionId) { - $scope.sectionToLoad = index + 1; + for (var index in $scope.sections) { + var section = $scope.sections[index]; + if (section.id == sectionId || (sectionNumber >= 0 && section.section === sectionNumber)) { + $scope.sectionToLoad = parseInt(index, 10) + 1; + break; } - }); + } + // Set moduleId to pass it to the new state when the section is autoloaded. We unset it after this // to prevent autoloading the module when the user manually loads a section. $scope.moduleId = moduleId; @@ -186,11 +190,24 @@ angular.module('mm.core.course') $scope.moduleId = null; // Unset moduleId when }, 500); } else { - $state.go('site.mm_course-section', { - sectionid: sectionId, - cid: courseId, - mid: moduleId - }); + if (!sectionId) { + // Search the section ID by section number. + for (var index in $scope.sections) { + var section = $scope.sections[index]; + if (section.section == sectionNumber) { + sectionId = section.id + break; + } + } + } + + if (sectionId) { + $state.go('site.mm_course-section', { + sectionid: sectionId, + cid: courseId, + mid: moduleId + }); + } } } } diff --git a/www/core/components/course/lang/ar.json b/www/core/components/course/lang/ar.json index 47a7f04e4bb..ab7fafab59b 100644 --- a/www/core/components/course/lang/ar.json +++ b/www/core/components/course/lang/ar.json @@ -1,8 +1,8 @@ { "allsections": "كل الأقسام", - "contents": "محتويات", + "contents": "المحتويات", "couldnotloadsections": "لم يتم تحميل كل الأقسام، من فضلك حاول مرة أخرى لاحقاَ", "errordownloadingsection": "خطأ عن تنزيل الأقسام", "hiddenfromstudents": "مخفي عن الطلاب", - "showall": "عرض الكل {{$a}}" + "showall": "عرض الكل" } \ No newline at end of file diff --git a/www/core/components/course/lang/bg.json b/www/core/components/course/lang/bg.json index 370471981b9..56a7382e3aa 100644 --- a/www/core/components/course/lang/bg.json +++ b/www/core/components/course/lang/bg.json @@ -5,5 +5,5 @@ "couldnotloadsections": "Неуспех при зареждането на секциите, моля опитайте отново.", "hiddenfromstudents": "Скрит от ученици", "nocontentavailable": "В момента няма достъпно съдържание.", - "showall": "Показване на всичко" + "showall": "Показване на всичките {{$a}}" } \ No newline at end of file diff --git a/www/core/components/course/lang/da.json b/www/core/components/course/lang/da.json index 2d70a448b4f..9242ee4ca2d 100644 --- a/www/core/components/course/lang/da.json +++ b/www/core/components/course/lang/da.json @@ -9,5 +9,5 @@ "hiddenfromstudents": "Skjult for studerende", "nocontentavailable": "Intet indhold tilgængeligt lige nu.", "overriddennotice": "Din endelige karakter fra denne aktivitet blev justeret manuelt.", - "showall": "Vis alle {{$a}}" + "showall": "Vis alt" } \ No newline at end of file diff --git a/www/core/components/course/lang/el.json b/www/core/components/course/lang/el.json index 5882734e565..ee4ca9da68c 100644 --- a/www/core/components/course/lang/el.json +++ b/www/core/components/course/lang/el.json @@ -1,4 +1,5 @@ { + "activitydisabled": "Ο οργανισμός σας απενεργοποίησε αυτήν την δραστηριότητα στην εφαρμογή για κινητά.", "activitynotyetviewableinapp": "Εργαζόμαστε για την υποστήριξη της δραστηριότητας {{$a}} .", "activitynotyetviewableremoteaddon": "Ο οργανισμός σας εγκατέστησε ένα plugin που δεν υποστηρίζεται ακόμη.", "activitynotyetviewablesiteupgradeneeded": "Η πλατφόρμα Moodle του οργανισμού σας πρέπει να αναβαθμιστεί.", diff --git a/www/core/components/course/lang/es.json b/www/core/components/course/lang/es.json index 40087d97665..140acb12ae9 100644 --- a/www/core/components/course/lang/es.json +++ b/www/core/components/course/lang/es.json @@ -1,4 +1,5 @@ { + "activitydisabled": "Su organización ha deshabilitado esta actividad en la aplicación móvil.", "activitynotyetviewableinapp": "Estamos trabajando para soportar la actividad de {{$a}}.", "activitynotyetviewableremoteaddon": "Esta actividad es un complemento de terceros que todavía no está soportada por la aplicación.", "activitynotyetviewablesiteupgradeneeded": "El sitio no está usando la versión más reciente de Moodle. Por favor, contacte al administrador del sitio.", @@ -13,7 +14,7 @@ "couldnotloadsections": "No se ha podido cargar las secciones, por favor inténtelo más tarde.", "errordownloadingsection": "Error durante la descarga de la sección.", "errorgetmodule": "Se ha producido un error recuperando los datos del módulo.", - "hiddenfromstudents": "Oculto de estudiantes", + "hiddenfromstudents": "No mostrado a los estudiantes", "nocontentavailable": "No hay contenido disponible en este momento.", "overriddennotice": "La calificación final de esta actividad ha sido ajustada manualmente.", "showall": "Mostrar todo", diff --git a/www/core/components/course/lang/es_mx.json b/www/core/components/course/lang/es_mx.json deleted file mode 100644 index 174565e66ba..00000000000 --- a/www/core/components/course/lang/es_mx.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "contents": "Contenidos", - "showall": "Mostrar todo" -} \ No newline at end of file diff --git a/www/core/components/course/lang/fa.json b/www/core/components/course/lang/fa.json index cb91088f8e6..5000e3146db 100644 --- a/www/core/components/course/lang/fa.json +++ b/www/core/components/course/lang/fa.json @@ -5,10 +5,10 @@ "confirmdownload": "شما در آستانهٔ دریافت {{size}} هستید. آیا مطمئنید که می‌خواهید ادامه دهید؟", "confirmdownloadunknownsize": "ما نتوانستیم حجم دریافت را محاسبه کنیم. آیا مطمئنید که می‌خواهید ادامه دهید؟", "confirmpartialdownloadsize": "شما در آستانهٔ دریافت حداقل {{size}} هستید. آیا مطمئنید که می‌خواهید ادامه دهید؟", - "contents": "محتواها", + "contents": "محتویات", "couldnotloadsectioncontent": "محتوای قسمت نتوانست بارگیری شود. لطفا بعدا دوباره تلاش کنید.", "couldnotloadsections": "قسمت‌ها نتوانستند بارگیری شوند. لطفا بعدا دوباره تلاش کنید.", "hiddenfromstudents": "پنهان از شاگردان", - "showall": "نمایش همه", + "showall": "نمایش همه {{$a}}", "useactivityonbrowser": "البته همچنان می‌توانید با استفاده از مرورگر دستگاه خود، از آن استفاده کنید." } \ No newline at end of file diff --git a/www/core/components/course/lang/he.json b/www/core/components/course/lang/he.json index 413e5343000..1789a2e476e 100644 --- a/www/core/components/course/lang/he.json +++ b/www/core/components/course/lang/he.json @@ -6,5 +6,5 @@ "hiddenfromstudents": "מוסתר בפני סטודנטים", "nocontentavailable": "אין תוכן זמין כרגע.", "overriddennotice": "הציון הסופי שלך מפעילות זו הותאם ידנית.", - "showall": "תצוגת כל ה-{{$a}}" + "showall": "הראה הכל" } \ No newline at end of file diff --git a/www/core/components/course/lang/ja.json b/www/core/components/course/lang/ja.json index 2e41ef36acc..2059fb9fb13 100644 --- a/www/core/components/course/lang/ja.json +++ b/www/core/components/course/lang/ja.json @@ -3,5 +3,5 @@ "contents": "コンテンツ", "hiddenfromstudents": "学生から非表示", "overriddennotice": "この活動に関するあなたの評点は手動で調整されました。", - "showall": "すべての {{$a}} を表示する" + "showall": "すべて表示" } \ No newline at end of file diff --git a/www/core/components/course/lang/pt_br.json b/www/core/components/course/lang/pt_br.json deleted file mode 100644 index ff9e75afa9c..00000000000 --- a/www/core/components/course/lang/pt_br.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "contents": "Conteúdos", - "showall": "Mostrar todos" -} \ No newline at end of file diff --git a/www/core/components/course/lang/ro.json b/www/core/components/course/lang/ro.json index 2069aa89421..8db8d4081f2 100644 --- a/www/core/components/course/lang/ro.json +++ b/www/core/components/course/lang/ro.json @@ -2,7 +2,7 @@ "allsections": "Toate secțiunile", "confirmdownload": "Porniți o descărcare de {{size}}. Sunteți sigur ca doriți să continuați?", "confirmdownloadunknownsize": "Nu putem calcula dimensiunea fișierului pe care doriți să îl descărcați. Sunteți sigur că doriți să descărcați?", - "contents": "Conținut", + "contents": "Conţinut", "couldnotloadsectioncontent": "Nu se poate încărca conținutul acestei secțiuni, încercați mai târziu.", "couldnotloadsections": "Nu se pot încărca secțiunile, încercați mai târziu.", "errordownloadingsection": "A apărut o eroare la descărcarea secțiunii.", @@ -10,5 +10,5 @@ "hiddenfromstudents": "Ascuns de cursanţi", "nocontentavailable": "Pentru moment nu există conținut.", "overriddennotice": "Nota finală obţinută de dumneavoastră pentru această activitate a fost ajustată manual.", - "showall": "Arată tot" + "showall": "Afişează toate {{$a}}" } \ No newline at end of file diff --git a/www/core/components/course/lang/sr-cr.json b/www/core/components/course/lang/sr-cr.json new file mode 100644 index 00000000000..40ab9bef16c --- /dev/null +++ b/www/core/components/course/lang/sr-cr.json @@ -0,0 +1,22 @@ +{ + "activitydisabled": "Ваша институција је онемогућила ову активност у мобилној апликацији.", + "activitynotyetviewableinapp": "Радимо на подршци за активност {{$a}}.", + "activitynotyetviewableremoteaddon": "Ваша институција је инсталирала додатак који још увек није подржан.", + "activitynotyetviewablesiteupgradeneeded": "Потребно је да се ажурира Moodle инсталација ваше институције.", + "allsections": "Све секције", + "askadmintosupport": "Обратите се администратору сајта и реците му да желите да користите ову активност са Moodle Mobile апликацијом.", + "confirmdeletemodulefiles": "Да ли сте сигурни да желите да избришете датотеке овог модула?", + "confirmdownload": "Намеравате да преузмете {{size}}. Да ли сте сигурни да желите да наставите?", + "confirmdownloadunknownsize": "Нисмо могли да израчунамо величину преузимање. Да ли сте сигурни да желите да преузмете?", + "confirmpartialdownloadsize": "Намеравате да преузмете најмање {{size}}. Да ли сте сигурни да желите да наставите?", + "contents": "Садржаји", + "couldnotloadsectioncontent": "Није могуће учитати садржај секције, покушајте поново касније.", + "couldnotloadsections": "Није могуће учитати секције, покушајте поново касније.", + "errordownloadingsection": "Грешка приликом преузимања секције.", + "errorgetmodule": "Грешка приликом преузимања података модула.", + "hiddenfromstudents": "Сакривено од полазника", + "nocontentavailable": "Никакав садржај није доступан у овом тренутку.", + "overriddennotice": "Ваша завршна оцена за ову активност је ручно подешена", + "showall": "Прикажи све", + "useactivityonbrowser": "Још увек можете да га користите помоћу веб читача вашег уређаја." +} \ No newline at end of file diff --git a/www/core/components/course/lang/sr-lt.json b/www/core/components/course/lang/sr-lt.json new file mode 100644 index 00000000000..744f10eb4f0 --- /dev/null +++ b/www/core/components/course/lang/sr-lt.json @@ -0,0 +1,22 @@ +{ + "activitydisabled": "Vaša institucija je onemogućila ovu aktivnost u mobilnoj aplikaciji.", + "activitynotyetviewableinapp": "Radimo na podršci za aktivnost {{$a}}.", + "activitynotyetviewableremoteaddon": "Vaša institucija je instalirala dodatak koji još uvek nije podržan.", + "activitynotyetviewablesiteupgradeneeded": "Potrebno je da se ažurira Moodle instalacija vaše institucije.", + "allsections": "Sve sekcije", + "askadmintosupport": "Obratite se administratoru sajta i recite mu da želite da koristite ovu aktivnost sa Moodle Mobile aplikacijom.", + "confirmdeletemodulefiles": "Da li ste sigurni da želite da izbrišete datoteke ovog modula?", + "confirmdownload": "Nameravate da preuzmete {{size}}. Da li ste sigurni da želite da nastavite?", + "confirmdownloadunknownsize": "Nismo mogli da izračunamo veličinu preuzimanje. Da li ste sigurni da želite da preuzmete?", + "confirmpartialdownloadsize": "Nameravate da preuzmete najmanje {{size}}. Da li ste sigurni da želite da nastavite?", + "contents": "Sadržaji", + "couldnotloadsectioncontent": "Nije moguće učitati sadržaj sekcije, pokušajte ponovo kasnije.", + "couldnotloadsections": "Nije moguće učitati sekcije, pokušajte ponovo kasnije.", + "errordownloadingsection": "Greška prilikom preuzimanja sekcije.", + "errorgetmodule": "Greška prilikom preuzimanja podataka modula.", + "hiddenfromstudents": "Sakriveno od polaznika", + "nocontentavailable": "Nikakav sadržaj nije dostupan u ovom trenutku.", + "overriddennotice": "Vaša završna ocena za ovu aktivnost je ručno podešena", + "showall": "Prikaži sve", + "useactivityonbrowser": "Još uvek možete da ga koristite pomoću veb čitača vašeg uređaja." +} \ No newline at end of file diff --git a/www/core/components/course/lang/uk.json b/www/core/components/course/lang/uk.json index f1e7e1b958b..232aa47f117 100644 --- a/www/core/components/course/lang/uk.json +++ b/www/core/components/course/lang/uk.json @@ -1,10 +1,10 @@ { "activitydisabled": "Ваша організація відключила цю активність в мобільному додатку.", - "activitynotyetviewableinapp": "Ми працюємо на підтримку {{$a}} діяльності.", + "activitynotyetviewableinapp": "Ми працюємо на підтримку діяльності {{$a}}.", "activitynotyetviewableremoteaddon": "Ваша організація встановила плагін, який ще не підтримується.", - "activitynotyetviewablesiteupgradeneeded": "Установка Moodle вашої організації повинна бути оновлена.", + "activitynotyetviewablesiteupgradeneeded": "Установка версія Moodle вашої організації повинна бути оновлена.", "allsections": "Всі секції", - "askadmintosupport": "Зверніться до адміністратора сайту і скажіть їм, що ви хочете використовувати цю діяльність з додатком Moodle Mobile.", + "askadmintosupport": "Зверніться до адміністратора сайту і скажіть, що ви хочете використовувати цю діяльність з додатком Moodle Mobile.", "confirmdeletemodulefiles": "Ви впевнені, що хочете видалити цей модуль?", "confirmdownload": "Ви збираєтеся завантажити {{size}}. Ви впевнені, що хочете продовжити?", "confirmdownloadunknownsize": "Ми не змогли розрахувати розмір файлу. Ви впевнені, що ви хочете завантажити?", diff --git a/www/core/components/course/lang/zh_cn.json b/www/core/components/course/lang/zh_cn.json deleted file mode 100644 index 4e4dcf0c8d2..00000000000 --- a/www/core/components/course/lang/zh_cn.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "contents": "内容", - "showall": "全部显示" -} \ No newline at end of file diff --git a/www/core/components/course/lang/zh_tw.json b/www/core/components/course/lang/zh_tw.json deleted file mode 100644 index 378159a75b6..00000000000 --- a/www/core/components/course/lang/zh_tw.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "contents": "內容", - "showall": "顯示全部" -} \ No newline at end of file diff --git a/www/core/components/course/main.js b/www/core/components/course/main.js index ea85c0ea079..99205b24219 100644 --- a/www/core/components/course/main.js +++ b/www/core/components/course/main.js @@ -17,7 +17,7 @@ angular.module('mm.core.course', ['mm.core.courses']) .constant('mmCoreCoursePriority', 800) .constant('mmCoreCourseAllSectionsId', -1) -.config(function($stateProvider, $mmCoursesDelegateProvider, mmCoreCoursePriority) { +.config(function($stateProvider) { $stateProvider @@ -26,6 +26,7 @@ angular.module('mm.core.course', ['mm.core.courses']) params: { courseid: null, sid: null, // Section to load. Not naming it sectionid because it collides with 'mm_course-section' param in split-view. + sectionnumber: null, // Section to load. If sid is provided there is no need to provide sectionnumber and vice versa. moduleid: null, // Module to load. course: null }, diff --git a/www/core/components/course/services/helper.js b/www/core/components/course/services/helper.js index 67ac9522f35..2283ff9b969 100644 --- a/www/core/components/course/services/helper.js +++ b/www/core/components/course/services/helper.js @@ -23,7 +23,8 @@ angular.module('mm.core.course') */ .factory('$mmCourseHelper', function($q, $mmCoursePrefetchDelegate, $mmFilepool, $mmUtil, $mmCourse, $mmSite, $state, $mmText, mmCoreNotDownloaded, mmCoreOutdated, mmCoreDownloading, mmCoreCourseAllSectionsId, $mmSitesManager, $mmAddonManager, - $controller, $mmCourseDelegate, $translate, $mmEvents, mmCoreEventPackageStatusChanged, mmCoreNotDownloadable) { + $controller, $mmCourseDelegate, $translate, $mmEvents, mmCoreEventPackageStatusChanged, mmCoreNotDownloadable, + mmCoreDownloaded) { var self = {}, calculateSectionStatus = false; @@ -243,9 +244,10 @@ angular.module('mm.core.course') * @param {Object} module Module to get the info from. * @param {Number} courseid Course ID the section belongs to. * @param {Number} [invalidateCache=false] Invalidates the cache first. + * @param {String} [component] Component of the module. * @return {Promise} Promise resolved with the download size, timemodified and module status. */ - self.getModulePrefetchInfo = function(module, courseId, invalidateCache) { + self.getModulePrefetchInfo = function(module, courseId, invalidateCache, component) { var moduleInfo = { size: false, @@ -255,6 +257,7 @@ angular.module('mm.core.course') status: false, statusIcon: false }, + siteId = $mmSite.getId(), promises = []; if (typeof invalidateCache != "undefined" && invalidateCache) { @@ -298,6 +301,22 @@ angular.module('mm.core.course') } })); + // Get the time it was downloaded (if it was downloaded). + promises.push($mmFilepool.getPackageData(siteId, component, module.id).then(function(data) { + if (data && data.downloadtime && (data.status == mmCoreOutdated || data.status == mmCoreDownloaded)) { + moduleInfo.downloadtime = data.downloadtime; + var now = $mmUtil.timestamp(); + if (now - data.downloadtime < 7 * 86400) { + moduleInfo.downloadtimeReadable = moment(data.downloadtime * 1000).fromNow(); + } else { + moduleInfo.downloadtimeReadable = moment(data.downloadtime * 1000).calendar(); + } + } + }).catch(function() { + // Not downloaded. + moduleInfo.downloadtime = 0; + })); + return $q.all(promises).then(function () { return moduleInfo; }); @@ -530,9 +549,10 @@ angular.module('mm.core.course') return $q.reject(); } - return promise.catch(function() { + return promise.catch(function(error) { if (!scope.$$destroyed) { - $mmUtil.showErrorModal('mm.core.errordownloading', true); + $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true); + return $q.reject(); } }); }); @@ -613,10 +633,7 @@ angular.module('mm.core.course') // We prefetch all the modules to prevent incoeherences in the download count // and also to download stale data that might not be marked as outdated. - return $mmCoursePrefetchDelegate.prefetchAll(downloadid, modules, courseid).then(function() {}, function() { - // Return a rejected promise so errors are handled outside of this function. - return $q.reject(); - }, function(id) { + return $mmCoursePrefetchDelegate.prefetchAll(downloadid, modules, courseid).then(undefined, undefined, function(id) { // Progress. Check that the module downloaded is one of the expected ones. var index = section.dwnModuleIds.indexOf(id); if (index > -1) { @@ -677,8 +694,8 @@ angular.module('mm.core.course') // We need to call getDownloadSize, the package might have been updated. return $mmCoursePrefetchDelegate.getModuleDownloadSize(module, courseId).then(function(size) { return $mmUtil.confirmDownloadSize(size).then(function() { - return $mmCoursePrefetchDelegate.prefetchModule(module, courseId).catch(function() { - return failPrefetch(!scope.$$destroyed); + return $mmCoursePrefetchDelegate.prefetchModule(module, courseId).catch(function(error) { + return failPrefetch(!scope.$$destroyed, error); }); }, function() { // User hasn't confirmed, stop spinner. @@ -713,7 +730,7 @@ angular.module('mm.core.course') * @return {Promise} Promise resolved when done. */ self.fillContextMenu = function(scope, module, courseId, invalidateCache, component) { - return self.getModulePrefetchInfo(module, courseId, invalidateCache).then(function(moduleInfo) { + return self.getModulePrefetchInfo(module, courseId, invalidateCache, component).then(function(moduleInfo) { scope.size = moduleInfo.size > 0 ? moduleInfo.sizeReadable : 0; scope.prefetchStatusIcon = moduleInfo.statusIcon; @@ -721,6 +738,8 @@ angular.module('mm.core.course') // Module is downloadable, calculate timemodified. if (moduleInfo.timemodified > 0) { scope.timemodified = $translate.instant('mm.core.lastmodified') + ': ' + moduleInfo.timemodifiedReadable; + } else if (moduleInfo.downloadtime > 0) { + scope.timemodified = $translate.instant('mm.core.lastdownloaded') + ': ' + moduleInfo.downloadtimeReadable; } else { // Cannot calculate time modified, show a default text. scope.timemodified = $translate.instant('mm.core.download'); diff --git a/www/core/components/course/services/prefetchdelegate.js b/www/core/components/course/services/prefetchdelegate.js index 6859ca5ed9d..5a4c9d4afd6 100644 --- a/www/core/components/course/services/prefetchdelegate.js +++ b/www/core/components/course/services/prefetchdelegate.js @@ -1318,9 +1318,9 @@ angular.module('mm.core') $q.all(promises).then(function() { delete deferreds[siteid][id]; // Remove from array before resolving. deferred.resolve(); - }, function() { + }, function(error) { delete deferreds[siteid][id]; // Remove from array before rejecting. - deferred.reject(); + deferred.reject(error); }); return deferred.promise; diff --git a/www/core/components/course/services/prefetchfactory.js b/www/core/components/course/services/prefetchfactory.js index b651a2d01e6..db6dabfbd0a 100644 --- a/www/core/components/course/services/prefetchfactory.js +++ b/www/core/components/course/services/prefetchfactory.js @@ -278,7 +278,7 @@ angular.module('mm.core.course') } if (module.description) { - return $q.when($mmUtil.extractDownloadableFilesFromHtmlAsFakeFileObjects(module.description)); + return $mmUtil.extractDownloadableFilesFromHtmlAsFakeFileObjects(module.description); } return []; diff --git a/www/core/components/courses/lang/ar.json b/www/core/components/courses/lang/ar.json index f96af19297b..ac8c6650a59 100644 --- a/www/core/components/courses/lang/ar.json +++ b/www/core/components/courses/lang/ar.json @@ -1,16 +1,16 @@ { "allowguests": "يسمح للمستخدمين الضيوف بالدخول إلى هذا المقرر الدراسي", "availablecourses": "المقررات الدراسية المتاحة", - "categories": "تصنيفات المقررات الدراسية", + "categories": "التصنيفات", "courses": "تصنيف المقررات الدراسية", "enrolme": "سجلني", "frontpage": "الصفحة الرئيسية", "mycourses": "مقرراتي الدراسية", - "nocourses": "لا يوجد معلومات لمقرر دراسي ليتم اظهرها", + "nocourses": "لا يوجد مقررات", "nocoursesyet": "لا توجد مقررات دراسية لهذه الفئة", - "nosearchresults": "لا توجد نتائج لهذا البحث", + "nosearchresults": "لا يوجد نتائج", "notenroled": "أنت لست مسجلاً كطالب في هذا المقرر", - "password": "كلمة المرور", + "password": "كلمة مرور", "search": "بحث", - "searchcourses": "بحث مقررات دراسية" + "searchcourses": "البحث في المقررات الدراسية" } \ No newline at end of file diff --git a/www/core/components/courses/lang/bg.json b/www/core/components/courses/lang/bg.json index 704b295e74a..1ef954e47fd 100644 --- a/www/core/components/courses/lang/bg.json +++ b/www/core/components/courses/lang/bg.json @@ -1,16 +1,16 @@ { "allowguests": "В този курс могат да влизат гости", "availablecourses": "Налични курсове", - "categories": "Категории курсове", + "categories": "Категории", "courses": "Курсове", "enrolme": "Запишете ме", "errorloadcourses": "Грешка при зареждането на курсовете.", "frontpage": "Заглавна страница", "mycourses": "Моите курсове", - "nocourses": "Няма информация за курса, която да бъде показана.", + "nocourses": "Няма курсове", "nocoursesyet": "Няма курсове в тази категория", - "nosearchresults": "Няма открити резултати за Вашето търсене", - "password": "Ключ за записване", + "nosearchresults": "Няма резултати", + "password": "Парола", "search": "Търсене", "searchcourses": "Търсене на курсове" } \ No newline at end of file diff --git a/www/core/components/courses/lang/ca.json b/www/core/components/courses/lang/ca.json index dc6c6af16fd..20ba97b397c 100644 --- a/www/core/components/courses/lang/ca.json +++ b/www/core/components/courses/lang/ca.json @@ -2,7 +2,7 @@ "allowguests": "Aquest curs permet entrar als usuaris visitants", "availablecourses": "Cursos disponibles", "cannotretrievemorecategories": "No es poden recuperar categories més enllà del nivell {{$a}}.", - "categories": "Categories de cursos", + "categories": "Categories", "confirmselfenrol": "Segur que voleu autoinscriure-us en aquest curs?", "courses": "Cursos", "enrolme": "Inscriu-me", @@ -16,10 +16,10 @@ "nocourses": "No hi ha informació del curs per mostrar.", "nocoursesyet": "No hi ha cursos en aquesta categoria", "nosearchresults": "No hi ha resultats per la vostra cerca", - "notenroled": "No esteu inscrit en aquest curs", + "notenroled": "No us heu inscrit en aquest curs", "notenrollable": "No podeu autoinscriure-us en aquest curs.", "password": "Clau d'inscripció", - "search": "Cerca", + "search": "Cerca...", "searchcourses": "Cerca cursos", "searchcoursesadvice": "Podeu fer servir el botó de cercar cursos per accedir als cursos com a convidat o autoinscriure-us en cursos que ho permetin.", "selfenrolment": "Autoinscripció", diff --git a/www/core/components/courses/lang/cs.json b/www/core/components/courses/lang/cs.json index 10ad53dc40c..3edb8f247c1 100644 --- a/www/core/components/courses/lang/cs.json +++ b/www/core/components/courses/lang/cs.json @@ -2,7 +2,7 @@ "allowguests": "Tento kurz je otevřen i pro hosty", "availablecourses": "Dostupné kurzy", "cannotretrievemorecategories": "Kategorie hlubší než úroveň {{$a}} nelze načíst.", - "categories": "Kategorie kurzů", + "categories": "Kategorie", "confirmselfenrol": "Jste si jisti, že chcete zapsat se do tohoto kurzu?", "courses": "Kurzy", "enrolme": "Zapsat se", @@ -19,7 +19,7 @@ "notenroled": "V tomto kurzu nejste zapsán", "notenrollable": "Do tohoto kurzu se nemůžete sami zapsat.", "password": "Klíč zápisu", - "search": "Hledat", + "search": "Vyhledat", "searchcourses": "Vyhledat kurzy", "searchcoursesadvice": "Můžete použít tlačítko Vyhledat kurzy, pracovat jako host nebo se zapsat do kurzů, které to umožňují.", "selfenrolment": "Zápis sebe sama", diff --git a/www/core/components/courses/lang/da.json b/www/core/components/courses/lang/da.json index f5f007f4d13..d55c5eb24b7 100644 --- a/www/core/components/courses/lang/da.json +++ b/www/core/components/courses/lang/da.json @@ -1,7 +1,7 @@ { "allowguests": "Dette kursus tillader gæster", "availablecourses": "Tilgængelige kurser", - "categories": "Kursuskategorier", + "categories": "Kategorier", "confirmselfenrol": "Er du sikker på at du ønsker at tilmelde dig dette kursus?", "courses": "Alle kurser", "enrolme": "Tilmeld mig", @@ -11,14 +11,14 @@ "filtermycourses": "Filtrer mit kursus", "frontpage": "Forside", "mycourses": "Mine kurser", - "nocourses": "Du er ikke tilmeldt nogen kurser.", + "nocourses": "Der er ingen kursusoplysninger at vise.", "nocoursesyet": "Der er ingen kurser i denne kategori", - "nosearchresults": "Der var ingen beskeder der opfyldte søgekriteriet", + "nosearchresults": "Din søgning gav ingen resultater", "notenroled": "Du er ikke tilmeldt dette kursus", "notenrollable": "Du kan ikke selv tilmelde dig dette kursus.", - "password": "Delt hemmelig streng", - "search": "Søg", - "searchcourses": "Søg efter kurser", + "password": "Tilmeldingsnøgle", + "search": "Søg...", + "searchcourses": "Søg kurser", "searchcoursesadvice": "Du kan bruge knappen kursussøgning for at få adgang som gæst eller tilmelde dig kurser der tillader det.", "selfenrolment": "Selvtilmelding", "totalcoursesearchresults": "Kurser i alt: {{$a}}" diff --git a/www/core/components/courses/lang/de.json b/www/core/components/courses/lang/de.json index 4e3b14126e9..25280c83d2e 100644 --- a/www/core/components/courses/lang/de.json +++ b/www/core/components/courses/lang/de.json @@ -2,7 +2,7 @@ "allowguests": "Der Kurs ist für Gäste zugänglich", "availablecourses": "Kursliste", "cannotretrievemorecategories": "Kursbereiche tiefer als Level {{$a}} können nicht abgerufen werden.", - "categories": "Kursbereiche", + "categories": "Kategorien", "confirmselfenrol": "Möchten Sie sich selbst in diesen Kurs einschreiben?", "courses": "Kurse", "enrolme": "Selbst einschreiben", @@ -19,7 +19,7 @@ "notenroled": "Sie sind nicht in diesen Kurs eingeschrieben.", "notenrollable": "Sie können sich nicht selbst in diesen Kurs einschreiben.", "password": "Einschreibeschlüssel", - "search": "Suchen", + "search": "Suche", "searchcourses": "Kurse suchen", "searchcoursesadvice": "Sie können Kurse suchen, um als Gast teilzunehmen oder sich selbst einzuschreiben, falls dies erlaubt ist.", "selfenrolment": "Selbsteinschreibung", diff --git a/www/core/components/courses/lang/el.json b/www/core/components/courses/lang/el.json index def66c4256d..e662603390c 100644 --- a/www/core/components/courses/lang/el.json +++ b/www/core/components/courses/lang/el.json @@ -1,10 +1,12 @@ { "allowguests": "Σε αυτό το μάθημα επιτρέπονται και οι επισκέπτες", "availablecourses": "Διαθέσιμα Μαθήματα", - "categories": "Κατηγορίες μαθημάτων", + "cannotretrievemorecategories": "Δεν είναι δυνατή η ανάκτηση κατηγοριών μετά από το επίπεδο {{$a}}.", + "categories": "Κατηγορίες", "confirmselfenrol": "Είστε σίγουροι ότι θέλετε να εγγραφείτε σε αυτό το μάθημα;", "courses": "Μαθήματα", "enrolme": "Εγγραφή", + "errorloadcategories": "Παρουσιάστηκε σφάλμα κατά την φόρτωση των κατηγοριών.", "errorloadcourses": "Παρουσιάστηκε σφάλμα κατά τη φόρτωση των μαθημάτων.", "errorsearching": "Παρουσιάστηκε σφάλμα κατά τη διάρκεια της αναζήτησης.", "errorselfenrol": "Παρουσιάστηκε σφάλμα κατά τη διάρκεια της αυτο-εγγραφής.", @@ -17,7 +19,7 @@ "notenroled": "Δεν έχετε εγγραφεί σε αυτό το μάθημα", "notenrollable": "Δεν μπορείτε να αυτο-εγγραφείτε σε αυτό το μάθημα.", "password": "Κλειδί εγγραφής", - "search": "Αναζήτηση", + "search": "Έρευνα", "searchcourses": "Αναζήτηση μαθημάτων", "searchcoursesadvice": "Μπορείτε να χρησιμοποιήσετε το κουμπί Αναζήτηση μαθημάτων για πρόσβαση ως επισκέπτης ή για να αυτο-εγγραφείτε σε μαθήματα που το επιτρέπουν.", "selfenrolment": "Αυτο-εγγραφή", diff --git a/www/core/components/courses/lang/es-mx.json b/www/core/components/courses/lang/es-mx.json index 3b5fa60c3b6..f01124ceca1 100644 --- a/www/core/components/courses/lang/es-mx.json +++ b/www/core/components/courses/lang/es-mx.json @@ -19,7 +19,7 @@ "notenroled": "Usted no está inscrito en este curso", "notenrollable": "Usted no puede inscribirse a Usted mismo en este curso.", "password": "Clave de inscripción", - "search": "Buscar", + "search": "Búsqueda", "searchcourses": "Buscar cursos", "searchcoursesadvice": "Usted puede usar el botón de 'buscar cursos' para acceder como invitado o para inscribirse Usted mismo en los cursos que lo permitan.", "selfenrolment": "Auto-inscripción", diff --git a/www/core/components/courses/lang/es.json b/www/core/components/courses/lang/es.json index c631db3a6aa..07e585e13d0 100644 --- a/www/core/components/courses/lang/es.json +++ b/www/core/components/courses/lang/es.json @@ -1,10 +1,12 @@ { "allowguests": "Este curso permite la entrada de invitados", "availablecourses": "Cursos disponibles", + "cannotretrievemorecategories": "No se pueden recuperar categorías más profundas que el nivel {{$a}}.", "categories": "Categorías", "confirmselfenrol": "¿Está seguro que desea auto-matricularse en este curso?", "courses": "Cursos", "enrolme": "Matricularme", + "errorloadcategories": "Ocurrió un error al cargar categorías.", "errorloadcourses": "Se ha producido un error cargando los cursos.", "errorsearching": "Se ha producido un error durante la búsqueda.", "errorselfenrol": "Se ha producido un error durante la auto-matriculación.", @@ -17,7 +19,7 @@ "notenroled": "No está inscrito en este curso", "notenrollable": "No puede auto-matricularse en este curso.", "password": "Clave", - "search": "Buscar", + "search": "Búsqueda", "searchcourses": "Buscar cursos", "searchcoursesadvice": "Puede utilizar el botón de buscar cursos para acceder como invitado o auto-matricularse en los cursos que lo permitan.", "selfenrolment": "Auto-matriculación", diff --git a/www/core/components/courses/lang/es_mx.json b/www/core/components/courses/lang/es_mx.json deleted file mode 100644 index d2a05393d10..00000000000 --- a/www/core/components/courses/lang/es_mx.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "filter": "Filtro", - "frontpage": "Portada", - "mycourses": "Mis cursos" -} \ No newline at end of file diff --git a/www/core/components/courses/lang/eu.json b/www/core/components/courses/lang/eu.json index 9a58ba8bf36..b5c88bc0330 100644 --- a/www/core/components/courses/lang/eu.json +++ b/www/core/components/courses/lang/eu.json @@ -2,7 +2,7 @@ "allowguests": "Ikastaro honetan bisitariak sar daitezke", "availablecourses": "Eskura dauden ikastaroak", "cannotretrievemorecategories": "{{$a}}. maila baino sakonagoko kategoriak ezin dira eskuratu.", - "categories": "Ikastaro-kategoriak", + "categories": "Kategoriak", "confirmselfenrol": "Ziur zaude ikastaro honetan izena eman nahi duzula?", "courses": "Ikastaroak", "enrolme": "Matrikulatu nazazu", @@ -19,8 +19,8 @@ "notenroled": "Ez zaude matrikulatuta ikastaro honetan", "notenrollable": "Ezin duzu zeure burua matrikulatu ikastaro honetan.", "password": "Matrikulazio-giltza", - "search": "Bilatu", - "searchcourses": "Bilatu Ikastaroak", + "search": "Bilatu...", + "searchcourses": "Bilatu ikastaroak", "searchcoursesadvice": "Bilatu botoia erabil dezakezu ikastaroak topatu eta bisitari gisa sartu edo bertan matrikulatzeko ikastaroak baimentzen badu.", "selfenrolment": "Matrikulazio automatikoa", "totalcoursesearchresults": "Ikastaroak guztira: {{$a}}" diff --git a/www/core/components/courses/lang/fa.json b/www/core/components/courses/lang/fa.json index 72a50f444ca..3462880e955 100644 --- a/www/core/components/courses/lang/fa.json +++ b/www/core/components/courses/lang/fa.json @@ -1,7 +1,7 @@ { "allowguests": "ورود کاربران مهمان به این درس مجاز است", "availablecourses": "درس‌های موجود", - "categories": "طبقه‌های درسی", + "categories": "دسته‌ها", "confirmselfenrol": "آیا مطمئنید که می‌خواهید خود را در این درس ثبت‌نام کنید؟", "courses": "درس‌ها", "enrolme": "ثبت‌نام من", @@ -9,11 +9,11 @@ "filtermycourses": "پالایش درس‌های من", "frontpage": "صفحهٔ اول", "mycourses": "درس‌های من", - "nocourses": "هیچ درسی برای نمایش وجود ندارد", + "nocourses": "هیچ درسی", "nocoursesyet": "درسی در این طبقه وجود ندارد", - "nosearchresults": "نتایجی برای جستجوی شما وجود نداشت.", + "nosearchresults": "بدون نتیجه", "notenroled": "شما در این درس ثبت‌نام نیستید", - "password": "رمز ورود", - "search": "جستجو", - "searchcourses": "جستجو بین درس‌ها" + "password": "کلمهٔ رمز", + "search": "جستجو...", + "searchcourses": "جستجوی درس‌ها" } \ No newline at end of file diff --git a/www/core/components/courses/lang/fr.json b/www/core/components/courses/lang/fr.json index 1861d031977..703265270ca 100644 --- a/www/core/components/courses/lang/fr.json +++ b/www/core/components/courses/lang/fr.json @@ -2,7 +2,7 @@ "allowguests": "Les visiteurs anonymes sont autorisés dans ce cours", "availablecourses": "Cours disponibles", "cannotretrievemorecategories": "Les catégories de niveau plus grand que {{$a}} ne peuvent pas être chargées.", - "categories": "Catégories de cours", + "categories": "Catégories", "confirmselfenrol": "Voulez-vous vraiment vous inscrire vous-même dans ce cours ?", "courses": "Cours", "enrolme": "M'inscrire", @@ -19,8 +19,8 @@ "notenroled": "Vous n'êtes pas inscrit à ce cours", "notenrollable": "Vous ne pouvez pas vous inscrire vous-même à ce cours.", "password": "Clef d'inscription", - "search": "Rechercher", - "searchcourses": "Rechercher des cours", + "search": "Recherche", + "searchcourses": "Rechercher les cours", "searchcoursesadvice": "Veuillez utiliser le bouton de recherche de cours pour accéder anonymement à des cours ou vous inscrire vous-même à des cours qui le permettent.", "selfenrolment": "Auto-inscription", "totalcoursesearchresults": "Nombre de cours : {{$a}}" diff --git a/www/core/components/courses/lang/he.json b/www/core/components/courses/lang/he.json index abb5cf53a41..888922a2943 100644 --- a/www/core/components/courses/lang/he.json +++ b/www/core/components/courses/lang/he.json @@ -1,17 +1,17 @@ { "allowguests": "הקורס הזה מרשה למשתמשים אורחים להכנס", "availablecourses": "קורסים זמינים", - "categories": "קטגוריות קורסים", + "categories": "קטגוריות חישוב ציונים", "courses": "קורסים", "enrolme": "רשום אותי", "errorloadcourses": "התרחשה שגיאה בזמן טעינת הקורסים.", "frontpage": "עמוד ראשי", "mycourses": "הקורסים שלי", - "nocourses": "אין מידע שניתן להציג על הקורס", + "nocourses": "אף קורס", "nocoursesyet": "אין קורסים בקטגוריה זו", - "nosearchresults": "לחיפוש שלך לא היו תוצאות", + "nosearchresults": "אין תוצאות", "notenroled": "אינך רשום לקורס זה", - "password": "סיסמה (secret)", - "search": "חיפוש", + "password": "סיסמה", + "search": "חפשו", "searchcourses": "חיפוש קורסים" } \ No newline at end of file diff --git a/www/core/components/courses/lang/hu.json b/www/core/components/courses/lang/hu.json index 7348fc46578..fb7d3ac5d45 100644 --- a/www/core/components/courses/lang/hu.json +++ b/www/core/components/courses/lang/hu.json @@ -1,16 +1,16 @@ { "allowguests": "Ez a kurzus megengedi vendégek belépését", "availablecourses": "Felvehető kurzusok", - "categories": "Kurzuskategóriák", + "categories": "Kategóriák", "courses": "Kurzusok", "enrolme": "Iratkoztasson be", "frontpage": "Kezdőoldal", "mycourses": "Kurzusaim", - "nocourses": "Nincs megjelenítendő kurzusinformáció.", + "nocourses": "Nincs kurzus", "nocoursesyet": "Ebben a kategóriában nincsenek kurzusok", - "nosearchresults": "Keresése nem adott eredményt", + "nosearchresults": "Nincs eredmény", "notenroled": "Ezt a kurzust nem vette föl", - "password": "Megosztott titkos jel", - "search": "Keresés", - "searchcourses": "Kurzusok keresése" + "password": "Jelszó", + "search": "Keresés...", + "searchcourses": "Keresés a kurzusokban" } \ No newline at end of file diff --git a/www/core/components/courses/lang/it.json b/www/core/components/courses/lang/it.json index c46c10af2f5..f0f3a476b70 100644 --- a/www/core/components/courses/lang/it.json +++ b/www/core/components/courses/lang/it.json @@ -1,7 +1,7 @@ { "allowguests": "Questo corso consente l'accesso ad utenti ospiti", "availablecourses": "Corsi disponibili", - "categories": "Categorie di corso", + "categories": "Categorie", "confirmselfenrol": "Desideri iscriverti al corso?", "courses": "Corsi", "enrolme": "Iscrivimi", @@ -17,7 +17,7 @@ "notenroled": "Non sei iscritto in questo corso", "notenrollable": "Non puoi iscriverti al corso.", "password": "Chiave di iscrizione", - "search": "Cerca", + "search": "Ricerca", "searchcourses": "Cerca corsi", "searchcoursesadvice": "Puoi utilizzare la ricerca corsi per accedere come ospite oppure iscriverti nei corsi che lo consentono.", "selfenrolment": "Iscrizione spontanea", diff --git a/www/core/components/courses/lang/ja.json b/www/core/components/courses/lang/ja.json index 32d5b81c2c9..5c4918df412 100644 --- a/www/core/components/courses/lang/ja.json +++ b/www/core/components/courses/lang/ja.json @@ -1,16 +1,16 @@ { "allowguests": "このコースにはゲストユーザも入ることができます。", "availablecourses": "コース一覧", - "categories": "コースカテゴリ", + "categories": "カテゴリ", "courses": "コース", "enrolme": "私を登録する", "frontpage": "フロントページ", "mycourses": "マイコース", - "nocourses": "表示するコース情報はありません。", + "nocourses": "コースなし", "nocoursesyet": "このカテゴリにコースはありません。", - "nosearchresults": "あなたの検索の該当データは見つかりませんでした。", + "nosearchresults": "該当なし", "notenroled": "あなたはこのコースに登録されていません。", - "password": "共有秘密鍵", - "search": "検索", + "password": "パスワード", + "search": "検索 ...", "searchcourses": "コースを検索する" } \ No newline at end of file diff --git a/www/core/components/courses/lang/lt.json b/www/core/components/courses/lang/lt.json index cc7eb529a53..976ffd32237 100644 --- a/www/core/components/courses/lang/lt.json +++ b/www/core/components/courses/lang/lt.json @@ -1,7 +1,7 @@ { "allowguests": "Į šiuos kursus leidžiama įeiti svečiui", "availablecourses": "Kursai", - "categories": "Kursų kategorijos", + "categories": "Kategorijos", "confirmselfenrol": "Ar Jūs tikrai norite įsirašyti į šiuos mokymo kursus?", "courses": "Kursai", "enrolme": "Įrašyti mane", @@ -14,10 +14,10 @@ "nocourses": "Nėra ką rodyti", "nocoursesyet": "Nėra šios kategorijos kursų", "nosearchresults": "Paieškos rezultatų nėra", - "notenroled": "Nesate įrašytas į šį kursą", + "notenroled": "Nesate įsiregistravęs kaip šių kursų besimokantysis", "notenrollable": "Negalite įrašyti savęs į šį kursą.", "password": "Įrašymo raktas", - "search": "Ieškoti", + "search": "Paieška", "searchcourses": "Ieškoti kursų", "searchcoursesadvice": "Jūs galite naudoti kursų paieškos mygtuką ieškant kursų su svečio prieiga arba įrašyti save į kursus, kurie yra prieinami.", "selfenrolment": "Savarankiška registracija", diff --git a/www/core/components/courses/lang/nl.json b/www/core/components/courses/lang/nl.json index 60fc63d43fe..71fd4592a9e 100644 --- a/www/core/components/courses/lang/nl.json +++ b/www/core/components/courses/lang/nl.json @@ -2,7 +2,7 @@ "allowguests": "In deze cursus zijn gasten toegestaan", "availablecourses": "Beschikbare cursussen", "cannotretrievemorecategories": "Categorieën dieper dan niveau {{$a}} kunnen niet opgehaald worden.", - "categories": "Cursuscategorieën", + "categories": "Categorieën", "confirmselfenrol": "Weet je zeker dat je je wil aanmelden in deze cursus?", "courses": "Cursussen", "enrolme": "Meld me aan", @@ -19,7 +19,7 @@ "notenroled": "Je bent niet aangemeld in deze cursus.", "notenrollable": "Je kunt jezelf niet aanmelden in deze cursus.", "password": "Aanmeldingssleutel", - "search": "Zoek", + "search": "Zoeken...", "searchcourses": "Zoek cursussen", "searchcoursesadvice": "Je kunt via de cursus zoekknop toegang krijgen als gast of jezelf aanmelden in cursussen die dit toestaan.", "selfenrolment": "Zelf aanmelden", diff --git a/www/core/components/courses/lang/pl.json b/www/core/components/courses/lang/pl.json index 9831e317b6a..1f508177b96 100644 --- a/www/core/components/courses/lang/pl.json +++ b/www/core/components/courses/lang/pl.json @@ -1,16 +1,16 @@ { "allowguests": "W tym kursie mogą uczestniczyć również goście", "availablecourses": "Dostępne kursy", - "categories": "Kategorie kursów", + "categories": "Kategorie", "courses": "Kursy", "enrolme": "Zapisz mnie", "frontpage": "Strona startowa", "mycourses": "Moje kursy", - "nocourses": "Nie ma informacji do pokazania", + "nocourses": "żadnego kursu", "nocoursesyet": "Brak kursów w tej kategorii", - "nosearchresults": "Brak rezultatów wyszukiwania", + "nosearchresults": "Brak wyników", "notenroled": "Nie jesteś zapisany w tym kursie", - "password": "Wspólne tajne hasło", - "search": "Wyszukaj", - "searchcourses": "Przeszukaj kursy" + "password": "Hasło", + "search": "Szukaj", + "searchcourses": "Szukaj kursów" } \ No newline at end of file diff --git a/www/core/components/courses/lang/pt-br.json b/www/core/components/courses/lang/pt-br.json index 759c80f03a6..d5becaf9a2e 100644 --- a/www/core/components/courses/lang/pt-br.json +++ b/www/core/components/courses/lang/pt-br.json @@ -2,7 +2,7 @@ "allowguests": "Visitantes podem entrar neste curso", "availablecourses": "Cursos disponíveis", "cannotretrievemorecategories": "Categorias mais profundas que o nível {{$a}} não podem ser recuperadas.", - "categories": "Categorias de Cursos", + "categories": "Categorias", "confirmselfenrol": "Tem certeza de que deseja inscrever-se neste curso?", "courses": "Cursos", "enrolme": "Inscreva-me", @@ -16,10 +16,10 @@ "nocourses": "Sem informações sobre o curso para mostrar.", "nocoursesyet": "Nenhum curso nesta categoria", "nosearchresults": "Não foram encontrados resultados da sua pesquisa", - "notenroled": "Você não está registrado neste curso", + "notenroled": "Você não está inscrito como estudante neste curso", "notenrollable": "Você não pode inscrever-se neste curso.", "password": "Chave de inscrição", - "search": "Buscar", + "search": "Busca", "searchcourses": "Buscar cursos", "searchcoursesadvice": "Você pode usar o botão de busca para acessar os cursos como convidado ou matricular-se em cursos que permitem que ele.", "selfenrolment": "Auto-inscrição", diff --git a/www/core/components/courses/lang/pt.json b/www/core/components/courses/lang/pt.json index 6cf8a068032..7379099e810 100644 --- a/www/core/components/courses/lang/pt.json +++ b/www/core/components/courses/lang/pt.json @@ -2,7 +2,7 @@ "allowguests": "Esta disciplina permite o acesso a visitantes", "availablecourses": "Disciplinas disponíveis", "cannotretrievemorecategories": "Categorias abaixo do nível {{$a}} não podem ser recuperadas.", - "categories": "Categorias de disciplinas", + "categories": "Categorias", "confirmselfenrol": "Tem certeza de que deseja inscrever-se nesta disciplina?", "courses": "Disciplinas", "enrolme": "Inscreva-me", @@ -16,10 +16,10 @@ "nocourses": "Sem informações das disciplinas para mostrar", "nocoursesyet": "Nenhuma disciplina nesta categoria", "nosearchresults": "Não foram encontrados resultados na sua pesquisa", - "notenroled": "Não está inscrito nesta disciplina", + "notenroled": "Não está inscrito como aluno nesta disciplina", "notenrollable": "Não se pode inscrever nesta disciplina.", "password": "Senha de inscrição", - "search": "Procurar", + "search": "Pesquisa", "searchcourses": "Procurar disciplinas", "searchcoursesadvice": "Pode usar o botão de pesquisa de disciplinas para aceder às mesmas como visitante ou autoinscrever-se caso o permitam.", "selfenrolment": "Autoinscrição", diff --git a/www/core/components/courses/lang/pt_br.json b/www/core/components/courses/lang/pt_br.json deleted file mode 100644 index 91cd85aa064..00000000000 --- a/www/core/components/courses/lang/pt_br.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "filter": "Filtrar", - "frontpage": "Página principal", - "mycourses": "Meus cursos" -} \ No newline at end of file diff --git a/www/core/components/courses/lang/ro.json b/www/core/components/courses/lang/ro.json index d2e6db9c9e2..64ab3e14670 100644 --- a/www/core/components/courses/lang/ro.json +++ b/www/core/components/courses/lang/ro.json @@ -1,23 +1,23 @@ { "allowguests": "Acest curs permite accesul vizitatorilor", "availablecourses": "Cursuri disponibile", - "categories": "Categorii de cursuri", + "categories": "Categorii", "confirmselfenrol": "Sunteți sigur/ă că doriți să vă înregistrați la acest curs?", "courses": "Cursuri", - "enrolme": "Înregistrează-mă", + "enrolme": "Înscrie-mă", "errorloadcourses": "A apărut o eroare la încărcarea cursurilor.", "errorsearching": "A apărut o eroare în procesul de căutare.", "errorselfenrol": "A apărut o eroare în procesul de auto-înregistrare.", "filtermycourses": "Filtrează cursurile", "frontpage": "Prima pagină", "mycourses": "Cursurile mele", - "nocourses": "Nu există informații despre curs", + "nocourses": "Nicio informație legată de cursuri este disponibilă", "nocoursesyet": "Nu s-au găsit cursuri în această categorie", - "nosearchresults": "Nu există rezultate pentru căutarea dumneavoastră", - "notenroled": "Nu sunteți înregistrat la acest curs", + "nosearchresults": "Căutarea iniţiată de dumneavoastră nu a generat niciun rezultat", + "notenroled": "Nu sunteți înregistrat în acest curs", "notenrollable": "Nu vă puteți auto-înregistra la acest curs.", - "password": "Parola de înregistrare", - "search": "Caută", + "password": "Parolă", + "search": "Căutați", "searchcourses": "Caută cursuri", "searchcoursesadvice": "Puteți folosi butonul pentru căutarea cursurilor pentru a cauta și accesa ca vizitator sau pentru a vă auto-înregistra la acele cursuri care permit aceste opțiuni.", "selfenrolment": "Auto înscriere", diff --git a/www/core/components/courses/lang/ru.json b/www/core/components/courses/lang/ru.json index 60a255745fb..214add26e59 100644 --- a/www/core/components/courses/lang/ru.json +++ b/www/core/components/courses/lang/ru.json @@ -1,17 +1,18 @@ { "allowguests": "Курс доступен гостю", "availablecourses": "Доступные курсы", - "categories": "Категории курсов", + "categories": "Категории", "courses": "Курсы", "enrolme": "Записаться на курс", "errorloadcourses": "При загрузке курсов произошла ошибка.", + "filtermycourses": "Поиск моих курсов", "frontpage": "Главная страница", "mycourses": "Мои курсы", - "nocourses": "Нет информации для отображения.", + "nocourses": "Нет курсов", "nocoursesyet": "В этой категории нет курсов", - "nosearchresults": "Поиск не дал результатов", + "nosearchresults": "Нет результатов", "notenroled": "Вы не записаны на этот курс", - "password": "Общий секретный ключ", - "search": "Найти", - "searchcourses": "Поиск курса" + "password": "Пароль", + "search": "Искать", + "searchcourses": "Поиск курсов" } \ No newline at end of file diff --git a/www/core/components/courses/lang/sr-cr.json b/www/core/components/courses/lang/sr-cr.json new file mode 100644 index 00000000000..12cd32f1434 --- /dev/null +++ b/www/core/components/courses/lang/sr-cr.json @@ -0,0 +1,27 @@ +{ + "allowguests": "Приступ курсу је дозвољен гостима", + "availablecourses": "Доступни курсеви", + "cannotretrievemorecategories": "Категорије које су испод нивоа {{$a}} не могу се преузети.", + "categories": "Категорије курсева", + "confirmselfenrol": "Да ли сте сигурни да желите да се упишете на овај курс?", + "courses": "Курсеви", + "enrolme": "Упиши ме", + "errorloadcategories": "Дошло је до грешке приликом учитавања категорија.", + "errorloadcourses": "Дошло је до грешке приликом учитавања курсева.", + "errorsearching": "Дошло је до грешке приликом претраживања.", + "errorselfenrol": "Дошло је до грешке приликом покушаја самосталног уписа.", + "filtermycourses": "Филтрирај моје курсеве", + "frontpage": "Насловна страница", + "mycourses": "Моји курсеви", + "nocourses": "Нема информација о курсевима за приказ.", + "nocoursesyet": "Нема курсева у овој категорији", + "nosearchresults": "Није било резултата ваше претраге", + "notenroled": "Нисте уписани на овај курс", + "notenrollable": "Не можете сами да се упишете на овај курс.", + "password": "Приступна лозинка курса", + "search": "Претрага", + "searchcourses": "Претражи курсеве", + "searchcoursesadvice": "Можете користити дугме за претрагу курсева како бисте им приступили као гост или се уписали на курсеве који то допуштају.", + "selfenrolment": "Самостални упис", + "totalcoursesearchresults": "Укупно курсева: {{$a}}" +} \ No newline at end of file diff --git a/www/core/components/courses/lang/sr-lt.json b/www/core/components/courses/lang/sr-lt.json new file mode 100644 index 00000000000..9a1e41e0d6d --- /dev/null +++ b/www/core/components/courses/lang/sr-lt.json @@ -0,0 +1,27 @@ +{ + "allowguests": "Pristup kursu je dozvoljen gostima", + "availablecourses": "Dostupni kursevi", + "cannotretrievemorecategories": "Kategorije koje su ispod nivoa {{$a}} ne mogu se preuzeti.", + "categories": "Kategorije kurseva", + "confirmselfenrol": "Da li ste sigurni da želite da se upišete na ovaj kurs?", + "courses": "Kursevi", + "enrolme": "Upiši me", + "errorloadcategories": "Došlo je do greške prilikom učitavanja kategorija.", + "errorloadcourses": "Došlo je do greške prilikom učitavanja kurseva.", + "errorsearching": "Došlo je do greške prilikom pretraživanja.", + "errorselfenrol": "Došlo je do greške prilikom pokušaja samostalnog upisa.", + "filtermycourses": "Filtriraj moje kurseve", + "frontpage": "Naslovna stranica", + "mycourses": "Moji kursevi", + "nocourses": "Nema informacija o kursevima za prikaz.", + "nocoursesyet": "Nema kurseva u ovoj kategoriji", + "nosearchresults": "Nije bilo rezultata vaše pretrage", + "notenroled": "Niste upisani na ovaj kurs", + "notenrollable": "Ne možete sami da se upišete na ovaj kurs.", + "password": "Pristupna lozinka kursa", + "search": "Pretraga", + "searchcourses": "Pretraži kurseve", + "searchcoursesadvice": "Možete koristiti dugme za pretragu kurseva kako biste im pristupili kao gost ili se upisali na kurseve koji to dopuštaju.", + "selfenrolment": "Samostalni upis", + "totalcoursesearchresults": "Ukupno kurseva: {{$a}}" +} \ No newline at end of file diff --git a/www/core/components/courses/lang/sv.json b/www/core/components/courses/lang/sv.json index f7b7aea83fe..dd610088dbb 100644 --- a/www/core/components/courses/lang/sv.json +++ b/www/core/components/courses/lang/sv.json @@ -1,7 +1,7 @@ { "allowguests": "Denna kurs tillåter gäster.", "availablecourses": "Tillgängliga kurser", - "categories": "Kurskategorier", + "categories": "Kategorier", "confirmselfenrol": "Är du säker att du vill registrera dig i den här kursen ?", "courses": "Kurser", "enrolme": "Registrera mig", @@ -17,7 +17,7 @@ "notenroled": "Du är inte registrerad i kursen", "notenrollable": "Du kan inte självregistrera dig i kursen", "password": "Kursnyckel", - "search": "Sök", + "search": "Sök...", "searchcourses": "Sök kurser", "searchcoursesadvice": "Du kan använda knappen \"Sök kurser\" för att få tillgång som gäst eller registrera dig på kurser som tillåter det .", "selfenrolment": "Kursnyckel (Student)", diff --git a/www/core/components/courses/lang/tr.json b/www/core/components/courses/lang/tr.json index 59192e73b8d..10cfff494c7 100644 --- a/www/core/components/courses/lang/tr.json +++ b/www/core/components/courses/lang/tr.json @@ -1,16 +1,16 @@ { "allowguests": "Bu derse konuk olarak girilebilir", "availablecourses": "Mevcut dersler", - "categories": "Ders Kategorileri", + "categories": "Kategoriler", "courses": "Dersler", "enrolme": "Beni kaydet", "frontpage": "Ön sayfa", "mycourses": "Derslerim", - "nocourses": "Gösterilecek ders bilgisi yok", + "nocourses": "Ders yok", "nocoursesyet": "Bu kategoride ders yok", - "nosearchresults": "Aramanızla ilgili sonuç yok", + "nosearchresults": "Sonuç yok", "notenroled": "Bu derse kayıtlı değilsiniz", - "password": "Şifre", - "search": "Ara", - "searchcourses": "Dersleri ara" + "password": "Kayıt anahtarı", + "search": "Arama...", + "searchcourses": "Kursları ara" } \ No newline at end of file diff --git a/www/core/components/courses/lang/uk.json b/www/core/components/courses/lang/uk.json index 2821e8d6a72..33b4e8511f2 100644 --- a/www/core/components/courses/lang/uk.json +++ b/www/core/components/courses/lang/uk.json @@ -2,7 +2,7 @@ "allowguests": "Дозволено гостьовий доступ до курсу", "availablecourses": "Доступні курси", "cannotretrievemorecategories": "Категорії глибші, ніж рівень {{$a}} не можуть бути відновлені.", - "categories": "Категорії курсів", + "categories": "Категорії", "confirmselfenrol": "Ви впевнені, що хочете зареєструвати себе в цьому курсі?", "courses": "Курси", "enrolme": "Відрахувати мене", @@ -18,10 +18,10 @@ "nosearchresults": "Ніяких результатів пошуку", "notenroled": "Ви не зареєстровані в цьому курсі", "notenrollable": "Ви не можете зареєструвати себе в цьому курсі.", - "password": "ключ подачі заявок", - "search": "Знайти", + "password": "Ключ подачі заявок", + "search": "Пошук", "searchcourses": "Пошук курсів", - "searchcoursesadvice": "Ви можете використовувати кнопку пошуку курсів, щоб отримати доступ в якості гостя або зареєструвати себе в курсах, які дозволяють їй.", + "searchcoursesadvice": "Ви можете використовувати кнопку пошуку курсів, щоб отримати доступ в якості гостя або зареєструвати себе в курсах, які дозволяють це.", "selfenrolment": "Самостійна реєстрація", "totalcoursesearchresults": "Всього курсів: {{$a}}" } \ No newline at end of file diff --git a/www/core/components/courses/lang/zh-cn.json b/www/core/components/courses/lang/zh-cn.json index 8428ade7a27..3ab280913aa 100644 --- a/www/core/components/courses/lang/zh-cn.json +++ b/www/core/components/courses/lang/zh-cn.json @@ -1,16 +1,16 @@ { "allowguests": "该课程允许访客进入", "availablecourses": "现有课程", - "categories": "课程分类", + "categories": "类别", "courses": "课程", "enrolme": "将我加入", "frontpage": "首页", "mycourses": "我的课程", - "nocourses": "没有可显示的课程信息。", + "nocourses": "没有课程", "nocoursesyet": "此类中无课程", - "nosearchresults": "您的搜索没有结果", + "nosearchresults": "无结果", "notenroled": "您没有加入此课程", - "password": "设置密码", + "password": "密码", "search": "搜索", "searchcourses": "搜索课程" } \ No newline at end of file diff --git a/www/core/components/courses/lang/zh-tw.json b/www/core/components/courses/lang/zh-tw.json index eb2fde191e0..69f2bba6433 100644 --- a/www/core/components/courses/lang/zh-tw.json +++ b/www/core/components/courses/lang/zh-tw.json @@ -1,7 +1,7 @@ { "allowguests": "本課程允許無帳號者進入", "availablecourses": "可使用的課程", - "categories": "課程類別", + "categories": "類別", "confirmselfenrol": "您確定要註冊本課程嗎?", "courses": "課程", "enrolme": "註冊報名", @@ -14,10 +14,10 @@ "nocourses": "沒有課程資料可以顯示", "nocoursesyet": "此類別中無課程", "nosearchresults": "您的搜索沒有任何結果.", - "notenroled": "您沒有註冊此課程", + "notenroled": "您沒有加入此課程", "notenrollable": "您無法註冊本課程.", "password": "註冊碼", - "search": "搜尋", + "search": "搜尋中...", "searchcourses": "搜尋課程", "searchcoursesadvice": "您可以使用搜尋課程按鈕以訪客身份登入, 或在允許它的課程中註冊", "selfenrolment": "自行註冊", diff --git a/www/core/components/courses/lang/zh_cn.json b/www/core/components/courses/lang/zh_cn.json deleted file mode 100644 index cc50f82219a..00000000000 --- a/www/core/components/courses/lang/zh_cn.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "filter": "过滤器", - "frontpage": "首页", - "mycourses": "我的课程" -} \ No newline at end of file diff --git a/www/core/components/courses/lang/zh_tw.json b/www/core/components/courses/lang/zh_tw.json deleted file mode 100644 index b682781fb0c..00000000000 --- a/www/core/components/courses/lang/zh_tw.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "filter": "過濾器", - "frontpage": "首頁", - "mycourses": "我的課程" -} \ No newline at end of file diff --git a/www/core/components/courses/scss/styles.scss b/www/core/components/courses/scss/styles.scss index b6762dc0036..3387c0bf5cf 100644 --- a/www/core/components/courses/scss/styles.scss +++ b/www/core/components/courses/scss/styles.scss @@ -2,7 +2,7 @@ $chart-size: 70px; $doughnut-border-size: 15px; $doughnut-dasharray: 173; $doughnut-empty-colour: $gray-light; -$doughnut-fill-colour: $orange-light; +$doughnut-fill-colour: $mm-color-light; $doughnut-border-colour: $gray-dark; $doughnut-text-colour: $gray-darker; diff --git a/www/core/components/courses/services/handlers.js b/www/core/components/courses/services/handlers.js index 6ebbe389417..08daca0ee07 100644 --- a/www/core/components/courses/services/handlers.js +++ b/www/core/components/courses/services/handlers.js @@ -91,17 +91,29 @@ angular.module('mm.core.courses') self.courseLinksHandler.getActions = function(siteIds, url, params, courseId) { courseId = parseInt(params.id, 10); + var sectionId = params.sectionid ? parseInt(params.sectionid, 10) : null, + sectionNumber = typeof params.section != 'undefined' ? parseInt(params.section, 10) : NaN, + stateParams = { + courseid: courseId, + sid: sectionId || null + }; + + if (!isNaN(sectionNumber)) { + stateParams.sectionnumber = sectionNumber; + } + return [{ action: function(siteId) { siteId = siteId || $mmSite.getId(); if (siteId == $mmSite.getId()) { - actionEnrol(courseId, url); + actionEnrol(courseId, url, stateParams); } else { + // Use redirect to make the course the new history root (to avoid "loops" in history). $state.go('redirect', { siteid: siteId, state: 'site.mm_course', - params: {courseid: courseId} + params: stateParams }); } } @@ -111,11 +123,12 @@ angular.module('mm.core.courses') /** * Action to perform when an enrol link is clicked. * - * @param {Number} courseId Course ID. - * @param {String} url Treated URL. + * @param {Number} courseId Course ID. + * @param {String} url Treated URL. + * @param {Object} stateParams Params to send to the new state. * @return {Void} */ - function actionEnrol(courseId, url) { + function actionEnrol(courseId, url, stateParams) { var modal = $mmUtil.showModalLoading(), isEnrolUrl = !!url.match(/(\/enrol\/index\.php)|(\/course\/enrol\.php)/); @@ -164,7 +177,7 @@ angular.module('mm.core.courses') $state.go('redirect', { siteid: $mmSite.getId(), state: 'site.mm_course', - params: {courseid: courseId} + params: stateParams }); }); } diff --git a/www/core/components/emulator/main.js b/www/core/components/emulator/main.js new file mode 100644 index 00000000000..ae23d656926 --- /dev/null +++ b/www/core/components/emulator/main.js @@ -0,0 +1,23 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Module to support Cordova plugins in desktop and some of them in browser too. +angular.module('mm.core.emulator', ['mm.core']) + +.config(function($mmInitDelegateProvider, mmInitDelegateMaxAddonPriority) { + if (!ionic.Platform.isWebView()) { + $mmInitDelegateProvider.registerProcess('mmEmulator', '$mmEmulatorManager.loadHTMLAPI', + mmInitDelegateMaxAddonPriority + 500, true); + } +}); diff --git a/www/core/components/emulator/scss/styles.scss b/www/core/components/emulator/scss/styles.scss new file mode 100644 index 00000000000..7bfb9f8e8dd --- /dev/null +++ b/www/core/components/emulator/scss/styles.scss @@ -0,0 +1,81 @@ +.mm-capture-media-modal { + background-color: $gray-light; + + .bar-header { + @include bar-style($bar-content-bg, $bar-content-border, $bar-content-text); + + .button { + color: $bar-content-text; + font-weight: normal; + } + } + + .mm-capture-media-modal-content { + text-align: center; + + .mm-av-wrapper { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + display: table; + height: 100%; + width: 100%; + margin: 0; + padding: 0; + clear: both; + } + + audio, video, img { + width: 100%; + height: 100%; + display: table-cell; + text-align: center; + vertical-align: middle; + object-fit: contain; + + &.mm-webcam-stream { + -webkit-transform: scaleX(-1); + transform: scaleX(-1); + } + } + + .mm-webcam-image-canvas { + display: none; + } + + .mm-audio-record-container { + width: 100%; + height: 100%; + + .mm-audio-canvas { + width: 100%; + height: 100%; + } + + .mm-audio-captured { + width: 100%; + } + } + } + + + .bar-footer { + background-color: $gray; + border-top-color: $gray-dark; + + .col { + padding: 0; + line-height: $bar-height - $bar-padding-portrait * 2; + + .button-icon { + color: $black; + } + + .ion-record, .ion-trash-a { + color: $red; + } + } + } +} diff --git a/www/core/components/emulator/services/clipboard.js b/www/core/components/emulator/services/clipboard.js new file mode 100644 index 00000000000..75bd66d9d09 --- /dev/null +++ b/www/core/components/emulator/services/clipboard.js @@ -0,0 +1,112 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.core.emulator') + +/** + * This service handles the emulation of the clipboard Cordova plugin in desktop apps and in browser. + * + * @ngdoc service + * @name $mmEmulatorClipboard + * @module mm.core.emulator + */ +.factory('$mmEmulatorClipboard', function($log, $q, $mmApp, $cordovaClipboard) { + + $log = $log.getInstance('$mmEmulatorClipboard'); + + var self = {}; + + /** + * Load the emulation of the Cordova plugin. It might not work in some browsers. + * + * @module mm.core.emulator + * @ngdoc method + * @name $mmEmulatorClipboard#load + * @return {Promise} Promise resolved when done. + */ + self.load = function() { + var isDesktop = $mmApp.isDesktop(), + clipboard, + copyTextarea; + + if (isDesktop) { + clipboard = require('electron').clipboard; + } else { + // In browser the text must be selected in order to copy it. Create a hidden textarea to put the text in it. + copyTextarea = document.createElement('textarea'); + angular.element(copyTextarea).addClass('mm-browser-copy-area'); + copyTextarea.setAttribute('aria-hidden', 'true'); + document.body.append(copyTextarea); + } + + // We need to redefine $cordovaClipboard methods instead of the core plugin (window.cordova.plugins.clipboard) + // because creating window.cordova breaks the app (it thinks it's a real device). + $cordovaClipboard.copy = function(text) { + var deferred = $q.defer(); + + if (isDesktop) { + clipboard.writeText(text); + deferred.resolve(); + } else { + // Put the text in the hidden textarea and select it. + copyTextarea.innerHTML = text; + copyTextarea.select(); + + try { + if (document.execCommand('copy')) { + deferred.resolve(); + } else { + deferred.reject(); + } + } catch (err) { + deferred.reject(); + } + + copyTextarea.innerHTML = ''; + } + + return deferred.promise; + }; + + $cordovaClipboard.paste = function() { + var deferred = $q.defer(); + + if (isDesktop) { + deferred.resolve(clipboard.readText()); + } else { + // Paste the text in the hidden textarea and get it. + copyTextarea.innerHTML = ''; + copyTextarea.select(); + + try { + if (document.execCommand('paste')) { + deferred.resolve(copyTextarea.innerHTML); + } else { + deferred.reject(); + } + } catch (err) { + deferred.reject(); + } + + copyTextarea.innerHTML = ''; + } + + return deferred.promise; + }; + + return $q.when(); + }; + + return self; +}); diff --git a/www/core/components/emulator/services/customurl.js b/www/core/components/emulator/services/customurl.js new file mode 100644 index 00000000000..50fdab480f0 --- /dev/null +++ b/www/core/components/emulator/services/customurl.js @@ -0,0 +1,52 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.core.emulator') + +/** + * This service handles the emulation of the Cordova Custom URL Scheme plugin in desktop apps. + * + * @ngdoc service + * @name $mmEmulatorCustomURLScheme + * @module mm.core.emulator + */ +.factory('$mmEmulatorCustomURLScheme', function($log, $q, $mmApp) { + + $log = $log.getInstance('$mmEmulatorCustomURLScheme'); + + var self = {}; + + /** + * Load the emulation of the Cordova plugin. + * + * @module mm.core.emulator + * @ngdoc method + * @name $mmEmulatorCustomURLScheme#load + * @return {Promise} Promise resolved when done. + */ + self.load = function() { + if (!$mmApp.isDesktop()) { + return $q.when(); + } + + // Listen for app launched events. + require('electron').ipcRenderer.on('mmAppLaunched', function(event, url) { + window.handleOpenURL && window.handleOpenURL(url); + }); + + return $q.when(); + }; + + return self; +}); diff --git a/www/core/components/emulator/services/emulator.js b/www/core/components/emulator/services/emulator.js new file mode 100644 index 00000000000..19894c62d79 --- /dev/null +++ b/www/core/components/emulator/services/emulator.js @@ -0,0 +1,66 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.core.emulator') + +/** + * @ngdoc service + * @name $mmEmulatorManager + * @module mm.core.emulator + * @description + * This service handles the emulation of Cordova plugins in other environments like browser. + */ +.factory('$mmEmulatorManager', function($log, $q, $mmFS, $mmEmulatorClipboard, $mmEmulatorCustomURLScheme, $mmEmulatorFile, + $mmEmulatorFileTransfer, $mmEmulatorGlobalization, $mmEmulatorInAppBrowser, $mmEmulatorLocalNotifications, + $mmEmulatorPushNotifications, $mmEmulatorZip, $mmUtil, $mmEmulatorMediaCapture) { + + $log = $log.getInstance('$mmEmulatorManager'); + + var self = {}; + + /** + * Loads HTML API to simulate Cordova APIs. Reserved for core use. + * + * @module mm.core.emulator + * @ngdoc method + * @name $mmEmulatorManager#loadHTMLAPI + * @return {Promise} Promise resolved when the API is loaded. + * @protected + */ + self.loadHTMLAPI = function() { + if ($mmFS.isAvailable()) { + $log.debug('Stop loading HTML API, it was already loaded or the environment doesn\'t need it.'); + return $q.when(); + } + + $log.debug('Loading HTML API.'); + + var promises = []; + + promises.push($mmEmulatorClipboard.load()); + promises.push($mmEmulatorCustomURLScheme.load()); + promises.push($mmEmulatorFile.load()); + promises.push($mmEmulatorFileTransfer.load()); + promises.push($mmEmulatorGlobalization.load()); + promises.push($mmEmulatorInAppBrowser.load()); + promises.push($mmEmulatorLocalNotifications.load()); + promises.push($mmEmulatorMediaCapture.load()); + promises.push($mmEmulatorPushNotifications.load()); + promises.push($mmEmulatorZip.load()); + + return $mmUtil.allPromises(promises); + }; + + return self; +}); diff --git a/www/core/components/emulator/services/file.js b/www/core/components/emulator/services/file.js new file mode 100644 index 00000000000..01885a7f874 --- /dev/null +++ b/www/core/components/emulator/services/file.js @@ -0,0 +1,595 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.core.emulator') + +/** + * This service handles the emulation of the Cordova File plugin in desktop apps and in browser. + * + * @ngdoc service + * @name $mmEmulatorFile + * @module mm.core.emulator + */ +.factory('$mmEmulatorFile', function($log, $q, $mmFS, $window, $mmApp, mmCoreConfigConstants) { + + $log = $log.getInstance('$mmEmulatorFile'); + + var self = {}; + + /** + * Delete an empty folder. + * + * @param {Object} fs Node module 'fs'. + * @param {String} path Path of the folder. + * @param {Function} successCallback Function to call when success. + * @param {Function} errorCallback Function to call when error. + * @return {Void} + */ + function deleteEmptyFolder(fs, path, successCallback, errorCallback) { + fs.rmdir(path, function(err) { + if (err) { + // Error removing directory. + errorCallback && errorCallback(err); + } else { + successCallback && successCallback(); + } + }); + } + + /** + * Delete a file or folder recursively. + * + * @param {Object} fs Node module 'fs'. + * @param {String} path Path of the folder. + * @param {Function} successCallback Function to call when success. + * @param {Function} errorCallback Function to call when error. + * @return {Void} + */ + function deleteRecursive(fs, path, successCallback, errorCallback) { + // Check if it exists. + fs.stat(path, function(err, stats) { + if (err) { + // File not found, reject. + errorCallback && errorCallback(err); + } else if (stats.isFile()) { + // It's a file, remove it. + fs.unlink(path, function(err) { + if (err) { + // Error removing file, reject. + errorCallback && errorCallback(err); + } else { + successCallback && successCallback(); + } + }); + } else { + // It's a directory, read the contents. + fs.readdir(path, function(err, files) { + if (err) { + // Error reading directory contents, reject. + errorCallback && errorCallback(err); + } else if (!files.length) { + // No files to delete, delete the folder. + deleteEmptyFolder(fs, path, successCallback, errorCallback); + } else { + // Remove all the files and directories. + var removed = 0; + files.forEach(function(filename) { + deleteRecursive(fs, $mmFS.concatenatePaths(path, filename), function() { + // Success deleting the file/dir. + removed++; + if (removed == files.length) { + // All files deleted, delete the folder. + deleteEmptyFolder(fs, path, successCallback, errorCallback); + } + }, errorCallback); + }); + } + }); + } + }); + } + + /** + * Emulate Cordova file plugin using NodeJS functions. This is only for NodeJS environments, + * browser works with the default resolveLocalFileSystemURL. + * + * @param {Object} fs Node module 'fs'. + * @return {Void} + */ + function emulateCordovaFileForDesktop(fs) { + if (!$mmApp.isDesktop()) { + return; + } + + emulateEntry(fs); + emulateFileWriter(fs); + emulateDirectoryReader(fs); + emulateFileEntry(fs); + emulateDirectoryEntry(fs); + + // Implement resolveLocalFileSystemURL. + $window.resolveLocalFileSystemURL = function(path, successCallback, errorCallback) { + // Check that the file/dir exists. + fs.stat(path, function(err, stats) { + if (err) { + errorCallback && errorCallback(err); + } else { + // The file/dir exists, return an instance. + var constructorFn = stats.isDirectory() ? DirectoryEntry : FileEntry, + fileAndDir = $mmFS.getFileAndDirectoryFromPath(path); + successCallback && successCallback(new constructorFn(fileAndDir.name, path)); + } + }); + }; + } + + /** + * Emulate DirectoryEntry object of the Cordova file plugin using NodeJS functions. + * + * @param {Object} fs Node module 'fs'. + * @return {Void} + */ + function emulateDirectoryEntry(fs) { + // Create DirectoryEntry and its functions, inheriting from Entry. + $window.DirectoryEntry = function(name, fullPath, fileSystem, nativeURL) { + // Add trailing slash if it is missing. + if ((fullPath) && !/\/$/.test(fullPath)) { + fullPath += '/'; + } + if (nativeURL && !/\/$/.test(nativeURL)) { + nativeURL += '/'; + } + + $window.Entry.call(this, false, true, name, fullPath, fileSystem, nativeURL); + }; + + $window.DirectoryEntry.prototype = Object.create($window.Entry.prototype); // Inherit Entry prototype. + + $window.DirectoryEntry.prototype.createReader = function() { + return new DirectoryReader(this.fullPath); + }; + + $window.DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) { + getDirOrFile(fs, this, true, path, options, successCallback, errorCallback); + }; + + $window.DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) { + // Use a promise to make sure only one callback is called. + var deferred = $q.defer(); + + deferred.promise.then(function() { + successCallback && successCallback(); + }).catch(function(error) { + errorCallback && errorCallback(error); + }); + + deleteRecursive(fs, this.fullPath, deferred.resolve, deferred.reject); + }; + + $window.DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) { + getDirOrFile(fs, this, false, path, options, successCallback, errorCallback); + }; + } + + /** + * Emulate DirectoryReader object of the Cordova file plugin using NodeJS functions. + * + * @param {Object} fs Node module 'fs'. + * @return {Void} + */ + function emulateDirectoryReader(fs) { + // DirectoryReader to read directory contents. + $window.DirectoryReader = function(localURL) { + this.localURL = localURL || null; + }; + + $window.DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) { + var that = this; + + fs.readdir(this.localURL, function(err, files) { + if (err) { + errorCallback && errorCallback(err); + } else { + // Use try/catch because it includes sync calls. + try { + var entries = []; + for (var i = 0; i < files.length; i++) { + var fileName = files[i], + filePath = $mmFS.concatenatePaths(that.localURL, fileName), + stats = fs.statSync(filePath); // Use sync function to make code simpler. + + if (stats.isDirectory()) { + entries.push(new DirectoryEntry(fileName, filePath)); + } else if (stats.isFile()) { + entries.push(new FileEntry(fileName, filePath)); + } + } + + successCallback && successCallback(entries); + } catch(ex) { + errorCallback && errorCallback(ex); + } + } + }); + }; + } + + /** + * Emulate Entry object of the Cordova file plugin using NodeJS functions. + * + * @param {Object} fs Node module 'fs'. + * @return {Void} + */ + function emulateEntry(fs) { + // Create the Entry object, parent of DirectoryEntry and FileEntry. + // It includes fileSystem and nativeURL as the Cordova plugin does, but they aren't used. + $window.Entry = function(isFile, isDirectory, name, fullPath, fileSystem, nativeURL) { + this.isFile = !!isFile; + this.isDirectory = !!isDirectory; + this.name = name || ''; + this.fullPath = fullPath || ''; + this.filesystem = fileSystem || null; + this.nativeURL = nativeURL || null; + }; + + // Implement Entry functions. + $window.Entry.prototype.getMetadata = function(successCallback, errorCallback) { + fs.stat(this.fullPath, function(err, stats) { + if (err) { + errorCallback && errorCallback(err); + } else { + successCallback && successCallback({ + size: stats.size, + modificationTime: stats.mtime + }); + } + }); + }; + + $window.Entry.prototype.setMetadata = function(successCallback, errorCallback, metadataObject) { + // Not supported. + errorCallback && errorCallback('Not supported'); + }; + + $window.Entry.prototype.moveTo = function(parent, newName, successCallback, errorCallback) { + newName = newName || this.name; + + var srcPath = this.fullPath, + destPath = $mmFS.concatenatePaths(parent.fullPath, newName), + that = this; + + fs.rename(srcPath, destPath, function(err) { + if (err) { + errorCallback && errorCallback(err); + } else { + var constructorFn = that.isDirectory ? DirectoryEntry : FileEntry; + successCallback && successCallback(new constructorFn(newName, destPath)); + } + }); + }; + + $window.Entry.prototype.copyTo = function(parent, newName, successCallback, errorCallback) { + newName = newName || this.name; + + // There is no function to copy a file, read the source and write the dest. + var srcPath = this.fullPath, + destPath = $mmFS.concatenatePaths(parent.fullPath, newName), + reader = fs.createReadStream(srcPath), + writer = fs.createWriteStream(destPath), + deferred = $q.defer(), // Use a promise to make sure only one callback is called. + that = this; + + deferred.promise.then(function() { + var constructorFn = that.isDirectory ? DirectoryEntry : FileEntry; + successCallback && successCallback(new constructorFn(newName, destPath)); + }).catch(function(error) { + errorCallback && errorCallback(error); + }); + + reader.on('error', deferred.reject); + + writer.on('error', deferred.reject); + + writer.on('close', deferred.resolve); + + reader.pipe(writer); + }; + + $window.Entry.prototype.toInternalURL = function() { + return 'file://' + this.fullPath; + }; + + $window.Entry.prototype.toURL = function() { + return this.fullPath; + }; + + $window.Entry.prototype.remove = function(successCallback, errorCallback) { + var removeFn = this.isDirectory ? fs.rmdir : fs.unlink; + removeFn(this.fullPath, function(err) { + if (err < 0) { + errorCallback && errorCallback(err); + } else { + successCallback && successCallback(); + } + }); + }; + + $window.Entry.prototype.getParent = function(successCallback, errorCallback) { + // Remove last slash if present and get the path of the parent. + var fullPath = this.fullPath.slice(-1) == '/' ? this.fullPath.slice(0, -1) : this.fullPath, + parentPath = fullPath.substr(0, fullPath.lastIndexOf('/')); + + // Check that parent exists. + fs.stat(parentPath, function(err, stats) { + if (err || !stats.isDirectory()) { + errorCallback && errorCallback(err); + } else { + var fileAndDir = $mmFS.getFileAndDirectoryFromPath(parentPath); + successCallback && successCallback(new DirectoryEntry(fileAndDir.name, parentPath)); + } + }); + }; + } + + /** + * Emulate FileEntry object of the Cordova file plugin using NodeJS functions. + * + * @param {Object} fs Node module 'fs'. + * @return {Void} + */ + function emulateFileEntry(fs) { + // Create FileEntry and its functions, inheriting from Entry. + $window.FileEntry = function(name, fullPath, fileSystem, nativeURL) { + // Remove trailing slash if it is present. + if (fullPath && /\/$/.test(fullPath)) { + fullPath = fullPath.substring(0, fullPath.length - 1); + } + if (nativeURL && /\/$/.test(nativeURL)) { + nativeURL = nativeURL.substring(0, nativeURL.length - 1); + } + + $window.Entry.call(this, true, false, name, fullPath, fileSystem, nativeURL); + }; + + $window.FileEntry.prototype = Object.create($window.Entry.prototype); // Inherit Entry prototype. + + $window.FileEntry.prototype.createWriter = function(successCallback, errorCallback) { + this.file(function(file) { + successCallback && successCallback(new FileWriter(file)); + }, errorCallback); + }; + + $window.FileEntry.prototype.file = function(successCallback, errorCallback) { + var that = this; + + // Get the metadata to know the time modified. + this.getMetadata(function(metadata) { + // Read the file. + fs.readFile(that.fullPath, function(err, data) { + if (err) { + errorCallback && errorCallback(err); + } else { + // Create a File instance and return it. + data = Uint8Array.from(data).buffer; // Convert the NodeJS Buffer to ArrayBuffer. + var file = new File([data], that.name || '', { + lastModified: metadata.modificationTime || null, + type: $mmFS.getMimeType($mmFS.getFileExtension(that.name)) || null + }); + file.localURL = that.fullPath; + file.start = 0; + file.end = file.size; + + successCallback && successCallback(file); + } + }); + }, errorCallback); + }; + } + + /** + * Emulate FileWriter object of the Cordova file plugin using NodeJS functions. + * + * @param {Object} fs Node module 'fs'. + * @return {Void} + */ + function emulateFileWriter(fs) { + // FileWriter to write data in files. Don't support abort, seek and truncate. + $window.FileWriter = function(file) { + this.fileName = ''; + this.length = 0; + if (file) { + this.localURL = file.localURL || file; + this.length = file.size || 0; + } + + this.position = 0; // Default is to write at the beginning of the file. + this.readyState = 0; // EMPTY + this.result = null; + this.error = null; + + // Event handlers + this.onwritestart = null; // When writing starts + this.onprogress = null; // While writing the file, and reporting partial file data + this.onwrite = null; // When the write has successfully completed. + this.onwriteend = null; // When the request has completed (either in success or failure). + this.onabort = null; // When the write has been aborted. For instance, by invoking the abort() method. + this.onerror = null; // When the write has failed (see errors). + }; + + $window.FileWriter.prototype.write = function(data) { + var that = this; + if (data && data.toString() == '[object Blob]') { + // Can't write Blobs, convert it to a Buffer. + var reader = new FileReader(); + reader.onload = function() { + if (reader.readyState == 2) { + write(new Buffer(reader.result)); + } + }; + reader.readAsArrayBuffer(data); + } else if (data && data.toString() == '[object ArrayBuffer]') { + // Convert it to a Buffer. + write(Buffer.from(new Uint8Array(data))); + } else { + write(data); + } + + function write(data) { + fs.writeFile(that.localURL, data, function(err) { + if (err) { + that.onerror && that.onerror(err); + } else { + that.onwrite && that.onwrite(); + } + that.onwriteend && that.onwriteend(); + }); + + that.onwritestart && that.onwritestart(); + } + }; + } + + /** + * Helper function for getDirectory and getFile in DirectoryEntry. + * + * @param {Object} fs Node module 'fs'. + * @param {Object} entry DirectoryEntry to get the file/dir in. + * @param {Boolean} isDir True if getting a directory, false if getting a file. + * @param {String} path Path of the file or dir. + * @param {Object} options Options. + * @param {Function} successCallback Function to call in success. + * @param {Function} errorCallback Function to call in error. + * @return {Void} + */ + function getDirOrFile(fs, entry, isDir, path, options, successCallback, errorCallback) { + var filename = $mmFS.getFileAndDirectoryFromPath(path).name, + fileDirPath = $mmFS.concatenatePaths(entry.fullPath, path); + + // Check if file/dir exists. + fs.stat(fileDirPath, function(err) { + if (err) { + if (options.create) { + // File/Dir probably doesn't exist, create it. + create(function(error2) { + if (!error2) { + // File created successfully, return it. + success(); + } else if (error2.code === 'EEXIST') { + // File exists, success. + success(); + } else if (error2.code === 'ENOENT') { + // Seems like the parent doesn't exist, create it too. + var parent = fileDirPath.substring(0, fileDirPath.lastIndexOf('/')); + + if (parent) { + entry.getDirectory(parent, options, function() { + // Parent created, try to create the child again. + create(function(error3) { + if (!error3) { + success(); + } else { + errorCallback && errorCallback(error3); + } + }); + }, errorCallback); + } else { + errorCallback && errorCallback(error2); + } + } else { + errorCallback && errorCallback(error2); + } + }); + } else { + errorCallback && errorCallback(err); + } + } else { + success(); + } + }); + + // Success, return the DirectoryEntry or FileEntry. + function success() { + var constructorFn = isDir ? DirectoryEntry : FileEntry; + successCallback && successCallback(new constructorFn(filename, fileDirPath)); + } + + // Create the file/dir. + function create(done) { + if (isDir) { + fs.mkdir(fileDirPath, done); + } else { + fs.writeFile(fileDirPath, '', done); + } + } + } + + /** + * Load the emulation of the Cordova plugin. + * + * @module mm.core.emulator + * @ngdoc method + * @name $mmEmulatorFile#load + * @return {Promise} Promise resolved when done. + */ + self.load = function() { + var deferred = $q.defer(), + basePath; + + $window.requestFileSystem = $window.requestFileSystem || $window.webkitRequestFileSystem; + $window.resolveLocalFileSystemURL = $window.resolveLocalFileSystemURL || $window.webkitResolveLocalFileSystemURL; + $window.LocalFileSystem = { + PERSISTENT: 1 + }; + + if ($mmApp.isDesktop()) { + var fs = require('fs'), + app = require('electron').remote.app; + + emulateCordovaFileForDesktop(fs); + + // Initialize File System. Get the path to use. + basePath = app.getPath('documents') || app.getPath('home'); + if (!basePath) { + deferred.reject('Cannot calculate base path for file system.'); + return; + } + + basePath = $mmFS.concatenatePaths(basePath.replace(/\\/g, '/'), mmCoreConfigConstants.app_id) + '/'; + + // Create the folder if needed. + fs.mkdir(basePath, function(e) { + if (!e || (e && e.code === 'EEXIST')) { + // Create successful or it already exists. Resolve. + $mmFS.setHTMLBasePath(basePath); + deferred.resolve(); + } else { + deferred.reject('Error creating base path.'); + } + }); + } else { + // It's browser, request a quota to use. Request 500MB. + $window.webkitStorageInfo.requestQuota(PERSISTENT, 500 * 1024 * 1024, function(granted) { + $window.requestFileSystem(PERSISTENT, granted, function(entry) { + basePath = entry.root.toURL(); + $mmFS.setHTMLBasePath(basePath); + deferred.resolve(); + }, deferred.reject); + }, deferred.reject); + } + + return deferred.promise; + }; + + return self; +}); diff --git a/www/core/components/emulator/services/filetransfer.js b/www/core/components/emulator/services/filetransfer.js new file mode 100644 index 00000000000..19101c56007 --- /dev/null +++ b/www/core/components/emulator/services/filetransfer.js @@ -0,0 +1,286 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.core.emulator') + +/** + * This service handles the emulation of the Cordova FileTransfer plugin in desktop apps and in browser. + * + * @ngdoc service + * @name $mmEmulatorFileTransfer + * @module mm.core.emulator + */ +.factory('$mmEmulatorFileTransfer', function($log, $q, $mmFS, $window, $mmApp) { + + $log = $log.getInstance('$mmEmulatorFileTransfer'); + + var self = {}, + fileTransferIdCounter = 0; + + /** + * Given a URL, check if it has a credentials in it and, if so, return them in a header object. + * This code is extracted from Cordova FileTransfer plugin. + * + * @param {String} urlString The URL to get the credentials from. + * @return {Object} The header with the credentials, null if no credentials. + */ + function getBasicAuthHeader(urlString) { + var header = null; + + // This is changed due to MS Windows doesn't support credentials in http uris + // so we detect them by regexp and strip off from result url. + if (window.btoa) { + var credentials = getUrlCredentials(urlString); + if (credentials) { + var authHeader = 'Authorization'; + var authHeaderValue = 'Basic ' + window.btoa(credentials); + + header = { + name : authHeader, + value : authHeaderValue + }; + } + } + + return header; + } + + /** + * Get the credentials from a URL. + * This code is extracted from Cordova FileTransfer plugin. + * + * @param {String} urlString The URL to get the credentials from. + * @return {String} Retrieved credentials. + */ + function getUrlCredentials(urlString) { + var credentialsPattern = /^https?\:\/\/(?:(?:(([^:@\/]*)(?::([^@\/]*))?)?@)?([^:\/?#]*)(?::(\d*))?).*$/, + credentials = credentialsPattern.exec(urlString); + + return credentials && credentials[1]; + } + + /** + * Load the emulation of the Cordova plugin. + * + * @module mm.core.emulator + * @ngdoc method + * @name $mmEmulatorFileTransfer#load + * @return {Promise} Promise resolved when done. + */ + self.load = function() { + // Create the FileTransferError object. + $window.FileTransferError = function(code, source, target, status, body, exception) { + this.code = code || null; + this.source = source || null; + this.target = target || null; + this.http_status = status || null; + this.body = body || null; + this.exception = exception || null; + }; + + $window.FileTransferError.FILE_NOT_FOUND_ERR = 1; + $window.FileTransferError.INVALID_URL_ERR = 2; + $window.FileTransferError.CONNECTION_ERR = 3; + $window.FileTransferError.ABORT_ERR = 4; + $window.FileTransferError.NOT_MODIFIED_ERR = 5; + + // Create the FileTransfer object and its functions. + $window.FileTransfer = function() { + this._id = ++fileTransferIdCounter; + this.onprogress = null; // Optional callback. + }; + + $window.FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts, options) { + // Use XMLHttpRequest instead of $http to support onprogress and abort. + var basicAuthHeader = getBasicAuthHeader(source), + xhr = new XMLHttpRequest(), + isDesktop = $mmApp.isDesktop(), + deferred = $q.defer(), // Use a promise to make sure only one callback is called. + headers = null; + + deferred.promise.then(function(entry) { + successCallback && successCallback(entry); + }).catch(function(error) { + errorCallback && errorCallback(error); + }); + + this.xhr = xhr; + this.deferred = deferred; + this.source = source; + this.target = target; + + if (basicAuthHeader) { + source = source.replace(getUrlCredentials(source) + '@', ''); + + options = options || {}; + options.headers = options.headers || {}; + options.headers[basicAuthHeader.name] = basicAuthHeader.value; + } + + if (options) { + headers = options.headers || null; + } + + // Prepare the request. + xhr.open('GET', source, true); + xhr.responseType = isDesktop ? 'arraybuffer' : 'blob'; + angular.forEach(headers, function(value, name) { + xhr.setRequestHeader(name, value); + }); + + if (this.onprogress) { + xhr.onprogress = this.onprogress; + } + + xhr.onerror = function() { + deferred.reject(new FileTransferError(-1, source, target, xhr.status, xhr.statusText)); + }; + + xhr.onload = function() { + // Finished dowloading the file. + var response = xhr.response; + if (!response) { + deferred.reject(); + } else { + var basePath = $mmFS.getBasePathInstant(); + target = target.replace(basePath, ''); // Remove basePath from the target. + target = target.replace(/%20/g, ' '); // Replace all %20 with spaces. + if (isDesktop) { + // In desktop we need to convert the arraybuffer into a Buffer. + response = Buffer.from(new Uint8Array(response)); + } + + $mmFS.writeFile(target, response).then(deferred.resolve, deferred.reject); + } + }; + + xhr.send(); + }; + + $window.FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options, trustAllHosts) { + var fileKey = null, + fileName = null, + mimeType = null, + params = null, + headers = null, + httpMethod = null, + deferred = $q.defer(), // Use a promise to make sure only one callback is called. + basicAuthHeader = getBasicAuthHeader(server), + that = this; + + deferred.promise.then(function(result) { + successCallback && successCallback(result); + }).catch(function(error) { + errorCallback && errorCallback(error); + }); + + if (basicAuthHeader) { + server = server.replace(getUrlCredentials(server) + '@', ''); + + options = options || {}; + options.headers = options.headers || {}; + options.headers[basicAuthHeader.name] = basicAuthHeader.value; + } + + if (options) { + fileKey = options.fileKey; + fileName = options.fileName; + mimeType = options.mimeType; + headers = options.headers; + httpMethod = options.httpMethod || 'POST'; + + if (httpMethod.toUpperCase() == "PUT"){ + httpMethod = 'PUT'; + } else { + httpMethod = 'POST'; + } + + if (options.params) { + params = options.params; + } else { + params = {}; + } + } + + // Add fileKey and fileName to the headers. + headers = headers || {}; + if (!headers['Content-Disposition']) { + headers['Content-Disposition'] = 'form-data;' + (fileKey ? ' name="' + fileKey + '";' : '') + + (fileName ? ' filename="' + fileName + '"' : '') + } + + // For some reason, adding a Content-Type header with the mimeType makes the request fail (it doesn't detect + // the token in the params). Don't include this header, and delete it if it's supplied. + delete headers['Content-Type']; + + // Get the file to upload. + $mmFS.getFile(filePath).then(function(fileEntry) { + return $mmFS.getFileObjectFromFileEntry(fileEntry); + }).then(function(file) { + // Use XMLHttpRequest instead of $http to support onprogress and abort. + var xhr = new XMLHttpRequest(); + xhr.open(httpMethod || 'POST', server); + angular.forEach(headers, function(value, name) { + // Filter "unsafe" headers. + if (name != 'Connection') { + xhr.setRequestHeader(name, value); + } + }); + + if (that.onprogress) { + xhr.onprogress = that.onprogress; + } + + that.xhr = xhr; + that.deferred = deferred; + this.source = filePath; + this.target = server; + + xhr.onerror = function() { + deferred.reject(new FileTransferError(-1, filePath, server, xhr.status, xhr.statusText)); + }; + + xhr.onload = function() { + // Finished uploading the file. + deferred.resolve({ + bytesSent: file.size, + responseCode: xhr.status, + response: xhr.response, + objectId: '' + }); + }; + + // Create a form data to send params and the file. + var fd = new FormData(); + angular.forEach(params, function(value, name) { + fd.append(name, value); + }); + fd.append('file', file); + + xhr.send(fd); + }).catch(deferred.reject); + }; + + $window.FileTransfer.prototype.abort = function() { + if (this.xhr) { + this.xhr.abort(); + this.deferred.reject(new FileTransferError(FileTransferError.ABORT_ERR, this.source, this.target)); + } + }; + + return $q.when(); + }; + + return self; +}); diff --git a/www/core/components/emulator/services/globalization.js b/www/core/components/emulator/services/globalization.js new file mode 100644 index 00000000000..3b612bc905a --- /dev/null +++ b/www/core/components/emulator/services/globalization.js @@ -0,0 +1,130 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.core.emulator') + +/** + * This service handles the emulation of the Cordova Globalization plugin in desktop apps and in browser. + * + * @ngdoc service + * @name $mmEmulatorGlobalization + * @module mm.core.emulator + */ +.factory('$mmEmulatorGlobalization', function($log, $q, $window, $mmApp) { + + $log = $log.getInstance('$mmEmulatorGlobalization'); + + var self = {}; + + /** + * Get the current locale. + * + * @return {String} Locale. + */ + function getLocale() { + var navLang = navigator.userLanguage || navigator.language; + try { + if ($mmApp.isDesktop()) { + var locale = require('electron').remote.app.getLocale(); + return locale || navLang; + } else { + return navLang; + } + } catch(ex) { + // Something went wrong, return browser language. + return navLang; + } + } + + /** + * Load the emulation of the Cordova plugin. + * Only some of the functions are supported. + * + * @module mm.core.emulator + * @ngdoc method + * @name $mmEmulatorGlobalization#load + * @return {Promise} Promise resolved when done. + */ + self.load = function() { + // Create the GlobalizationError object. + $window.GlobalizationError = function(code, message) { + this.code = code || null; + this.message = message || ''; + }; + + $window.GlobalizationError.UNKNOWN_ERROR = 0; + $window.GlobalizationError.FORMATTING_ERROR = 1; + $window.GlobalizationError.PARSING_ERROR = 2; + $window.GlobalizationError.PATTERN_ERROR = 3; + + // Create the Globalization object. + navigator.globalization = { + getLocaleName: function(successCallback, errorCallback) { + var locale = getLocale(); + if (locale) { + successCallback && successCallback({value: locale}); + } else { + var error = new GlobalizationError(GlobalizationError.UNKNOWN_ERROR, 'Cannot get language'); + errorCallback && errorCallback(error); + } + }, + numberToString: function(number, successCallback, errorCallback, options) { + var error = new GlobalizationError(GlobalizationError.UNKNOWN_ERROR, 'Not supported.'); + errorCallback && errorCallback(error); + }, + isDayLightSavingsTime: function(date, successCallback, errorCallback) { + var error = new GlobalizationError(GlobalizationError.UNKNOWN_ERROR, 'Not supported.'); + errorCallback && errorCallback(error); + }, + getFirstDayOfWeek: function(successCallback, errorCallback) { + var error = new GlobalizationError(GlobalizationError.UNKNOWN_ERROR, 'Not supported.'); + errorCallback && errorCallback(error); + }, + getDateNames: function (successCallback, errorCallback, options) { + var error = new GlobalizationError(GlobalizationError.UNKNOWN_ERROR, 'Not supported.'); + errorCallback && errorCallback(error); + }, + getDatePattern: function(successCallback, errorCallback, options) { + var error = new GlobalizationError(GlobalizationError.UNKNOWN_ERROR, 'Not supported.'); + errorCallback && errorCallback(error); + }, + getNumberPattern: function(successCallback, errorCallback, options) { + var error = new GlobalizationError(GlobalizationError.UNKNOWN_ERROR, 'Not supported.'); + errorCallback && errorCallback(error); + }, + getCurrencyPattern: function(currencyCode, successCallback, errorCallback) { + var error = new GlobalizationError(GlobalizationError.UNKNOWN_ERROR, 'Not supported.'); + errorCallback && errorCallback(error); + }, + stringToDate: function(dateString, successCallback, errorCallback, options) { + var error = new GlobalizationError(GlobalizationError.UNKNOWN_ERROR, 'Not supported.'); + errorCallback && errorCallback(error); + }, + stringToNumber: function(numberString, successCallback, errorCallback, options) { + var error = new GlobalizationError(GlobalizationError.UNKNOWN_ERROR, 'Not supported.'); + errorCallback && errorCallback(error); + }, + dateToString: function(date, successCallback, errorCallback, options) { + var error = new GlobalizationError(GlobalizationError.UNKNOWN_ERROR, 'Not supported.'); + errorCallback && errorCallback(error); + }, + }; + + navigator.globalization.getPreferredLanguage = navigator.globalization.getLocaleName; + + return $q.when(); + }; + + return self; +}); diff --git a/www/core/components/emulator/services/helper.js b/www/core/components/emulator/services/helper.js new file mode 100644 index 00000000000..a95570a5b4a --- /dev/null +++ b/www/core/components/emulator/services/helper.js @@ -0,0 +1,179 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.core.emulator') + +.constant('mmCoreEmulatorLastReceivedNotificationStore', 'mm_emulator_last_received_notification') + +.config(function($mmSitesFactoryProvider, mmCoreEmulatorLastReceivedNotificationStore) { + var stores = [ + { + name: mmCoreEmulatorLastReceivedNotificationStore, + keyPath: 'component' // Only 1 entry per component. + } + ]; + $mmSitesFactoryProvider.registerStores(stores); +}) + +.factory('$mmEmulatorHelper', function($log, $mmSitesManager, $mmApp, $q, $mmLocalNotifications, $mmUtil, mmCoreSecondsDay, + mmCoreEmulatorLastReceivedNotificationStore) { + + $log = $log.getInstance('$mmEmulatorHelper'); + + var self = {}; + + /** + * Check if there are new notifications, triggering a local notification if found. + * Only for desktop apps since they don't support push notifications. + * + * @module mm.core.emulator + * @ngdoc method + * @name $mmEmulatorHelper#checkNewNotifications + * @param {String} [siteId] Site ID to check. If not defined, check all sites. + * @return {Promise} Promise resolved when done. + */ + self.checkNewNotifications = function(component, fetchFn, getDataFn, siteId) { + if (!$mmApp.isDesktop() || !$mmLocalNotifications.isAvailable()) { + return $q.when(); + } + + if (!$mmApp.isOnline()) { + $log.debug('Cannot check push notifications because device is offline.'); + return $q.reject(); + } + + var promise; + if (!siteId) { + // No site ID defined, check all sites. + promise = $mmSitesManager.getSitesIds(); + } else { + promise = $q.when([siteId]); + } + + return promise.then(function(siteIds) { + var sitePromises = []; + + angular.forEach(siteIds, function(siteId) { + // Check new notifications for each site. + sitePromises.push(checkNewNotificationsForSite(component, fetchFn, getDataFn, siteId)); + }); + + return $q.all(sitePromises); + }); + }; + + /** + * Check if there are new notifications for a certain site, triggering a local notification if found. + * + * @param {String} siteId Site ID to check. + * @return {Promise} Promise resolved when done. + */ + function checkNewNotificationsForSite(component, fetchFn, getDataFn, siteId) { + // Get the last received notification in the app. + return self.getLastReceivedNotification(component, siteId).then(function(lastNotification) { + // Now fetch the latest notifications from the server. + return fetchFn(siteId).then(function(notifications) { + if (!lastNotification || !notifications.length) { + // No last notification stored (first call) or no new notifications. Stop. + return; + } + + var notification = notifications[0]; + + if (notification.id == lastNotification.id || notification.timecreated <= lastNotification.timecreated || + $mmUtil.timestamp() - notification.timecreated > mmCoreSecondsDay) { + // There are no new notifications or the newest one happened more than a day ago, stop. + return; + } + + // There is a new notification, show it. + return $q.when(getDataFn(notification)).then(function(titleAndText) { + var localNotif = { + id: 1, + at: new Date(), + title: titleAndText.title, + text: titleAndText.text, + data: { + notif: notification, + site: siteId + } + }; + + $mmLocalNotifications.schedule(localNotif, component, siteId); + }); + }); + }); + } + + + /** + * Get the last notification received in a certain site for a certain component. + * + * @module mm.core.emulator + * @ngdoc method + * @name $mmEmulatorHelper#getLastReceivedNotification + * @param {String} component Component of the notification to get. + * @param {String} siteId Site ID of the notification. + * @return {Promise} Promise resolved with the notification or false if not found. + */ + self.getLastReceivedNotification = function(component, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.getDb().get(mmCoreEmulatorLastReceivedNotificationStore, component); + }).catch(function() { + return false; + }); + }; + + /** + * Check if the app is running in a Windows environment. + * + * @module mm.core.emulator + * @ngdoc method + * @name $mmEmulatorHelper#isWindows + * @return {Boolean} Whether it's running in a Windows environment. + */ + self.isWindows = function() { + try { + var os = require('os'); + return os.platform().indexOf('win') === 0; + } catch(ex) { + return false; + } + }; + + /** + * Store the last notification received in a certain site. + * + * @module mm.core.emulator + * @ngdoc method + * @name $mmEmulatorHelper#storeLastReceivedNotification + * @param {String} component Component of the notification to store. + * @param {Object} notification Notification to store. + * @param {String} siteId Site ID of the notification. + * @return {Promise} Promise resolved when done. + */ + self.storeLastReceivedNotification = function(component, notification, siteId) { + if (!notification) { + // No notification, store a fake one. + notification = {id: -1, timecreated: 0}; + } + notification.component = component; + + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.getDb().insert(mmCoreEmulatorLastReceivedNotificationStore, notification); + }); + }; + + return self; +}); diff --git a/www/core/components/emulator/services/inappbrowser.js b/www/core/components/emulator/services/inappbrowser.js new file mode 100644 index 00000000000..93b40a8690c --- /dev/null +++ b/www/core/components/emulator/services/inappbrowser.js @@ -0,0 +1,161 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.core.emulator') + +/** + * This service handles the emulation of the Cordova InAppBrowser plugin in desktop apps. + * + * @ngdoc service + * @name $mmEmulatorInAppBrowser + * @module mm.core.emulator + */ +.factory('$mmEmulatorInAppBrowser', function($log, $q, $mmFS, $window, $mmApp) { + + $log = $log.getInstance('$mmEmulatorInAppBrowser'); + + var self = {}; + + /** + * Load the emulation of the Cordova plugin. + * + * @module mm.core.emulator + * @ngdoc method + * @name $mmEmulatorInAppBrowser#load + * @return {Promise} Promise resolved when done. + */ + self.load = function() { + if (!$mmApp.isDesktop()) { + return $q.when(); + } + + var BrowserWindow = require('electron').remote.BrowserWindow, + screen = require('electron').screen; + + // Redefine window open to be able to have full control over the new window. + $window.open = function(url, frameName, features) { + var width = 800, + height = 600, + display, + newWindow, + listeners = {}; + + if (screen) { + display = screen.getPrimaryDisplay(); + if (display && display.workArea) { + width = display.workArea.width || width; + height = display.workArea.height || height; + } + } + + newWindow = new BrowserWindow({ + width: width, + height: height + }); + newWindow.loadURL(url); + + // Add the missing functions that InAppBrowser supports but BrowserWindow doesn't. + newWindow.addEventListener = function(name, callback) { + var that = this; + + switch (name) { + case 'loadstart': + that.webContents.addListener('did-start-loading', received); + break; + + case 'loadstop': + that.webContents.addListener('did-finish-load', received); + break; + + case 'loaderror': + that.webContents.addListener('did-fail-load', received); + break; + + case 'exit': + that.addListener('close', received); + break; + } + + // Store the received function instance to be able to remove the listener. + listeners[callback] = received; + + function received(event) { + try { + event.url = that.getURL(); + callback(event); + } catch(ex) {} + } + }; + + newWindow.removeEventListener = function(name, callback) { + var that = this, + listener = listeners[callback]; + + switch (name) { + case 'loadstart': + that.webContents.removeListener('did-start-loading', listener); + break; + + case 'loadstop': + that.webContents.removeListener('did-finish-load', listener); + break; + + case 'loaderror': + that.webContents.removeListener('did-fail-load', listener); + break; + + case 'exit': + that.removeListener('close', listener); + break; + } + }; + + newWindow.executeScript = function(details, callback) { + var that = this; + + if (details.code) { + that.webContents.executeJavaScript(details.code, false, callback); + } else if (details.file) { + $mmFS.readFile(details.file).then(function(code) { + that.webContents.executeJavaScript(code, false, callback); + }).catch(callback); + } else { + callback('executeScript requires exactly one of code or file to be specified'); + } + }; + + newWindow.insertCSS = function(details, callback) { + var that = this; + + if (details.code) { + that.webContents.insertCSS(details.code); + callback(); + } else if (details.file) { + $mmFS.readFile(details.file).then(function(code) { + that.webContents.insertCSS(code); + callback(); + }).catch(callback); + } else { + callback('insertCSS requires exactly one of code or file to be specified'); + } + }; + + return newWindow; + }; + + return $q.when(); + }; + + return self; +}); diff --git a/www/core/components/emulator/services/localnotif.js b/www/core/components/emulator/services/localnotif.js new file mode 100644 index 00000000000..54b45ba1215 --- /dev/null +++ b/www/core/components/emulator/services/localnotif.js @@ -0,0 +1,617 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.core.emulator') + +.constant('mmCoreDesktopLocalNotificationsStore', 'desktop_local_notifications') + +.config(function($mmAppProvider, mmCoreDesktopLocalNotificationsStore) { + var stores = [ + { + name: mmCoreDesktopLocalNotificationsStore, // Store to schedule notifications in desktop apps. + keyPath: 'id', + indexes: [ + { + name: 'triggered' + } + ] + } + ]; + $mmAppProvider.registerStores(stores); +}) + +/** + * This service handles the emulation of the local notifications Cordova plugin in desktop apps. + * + * @ngdoc service + * @name $mmEmulatorLocalNotifications + * @module mm.core.emulator + */ +.factory('$mmEmulatorLocalNotifications', function($log, $q, $mmApp, $mmUtil, $timeout, $interval, $rootScope, + $cordovaLocalNotification, mmCoreDesktopLocalNotificationsStore, mmCoreSecondsYear, mmCoreSecondsDay, + mmCoreSecondsHour, mmCoreSecondsMinute, $mmEmulatorHelper, mmCoreConfigConstants) { + + $log = $log.getInstance('$mmEmulatorLocalNotifications'); + + var self = {}, + scheduled = {}, + triggered = {}, + defaults = { + text: '', + title: '', + sound: '', + badge: 0, + id: 0, + data: undefined, + every: undefined, + at: undefined + }, + winNotif, // Library for Windows notifications. + toastTemplate = '%s' + + '%s', // Template for Windows ToastNotifications. + tileBindingTemplate = '%s' + + '%s', + tileTemplate = '' + + '' + tileBindingTemplate + '' + + '' + tileBindingTemplate + '' + + '' + tileBindingTemplate + '' + + ''; // Template for Windows TileNotifications. Use same template for all sizes. + + /** + * Cancel a local notification. + * + * @param {Number} id Notification ID. + * @param {Boolean} omitEvent If true, the clear/cancel event won't be triggered. + * @param {[type]} eventName Name of the event to trigger. + * @return {Void} + */ + function cancelNotification(id, omitEvent, eventName) { + var notification = scheduled[id].notification; + + $timeout.cancel(scheduled[id].timeout); + $interval.cancel(scheduled[id].interval); + delete scheduled[id]; + delete triggered[id]; + + removeNotification(id); + + if (!omitEvent) { + $rootScope.$broadcast(eventName, notification, 'foreground'); + } + } + + /** + * Convert a list of IDs to numbers. + * Code extracted from the Cordova plugin. + * + * @param {Mixed[]} ids List of IDs. + * @return {Number[]} List of IDs as numbers. + */ + function convertIds(ids) { + var convertedIds = []; + + for (var i = 0; i < ids.length; i++) { + convertedIds.push(Number(ids[i])); + } + + return convertedIds; + } + + /** + * Convert the notification options to their required type. + * Code extracted from the Cordova plugin. + * + * @param {Object} options Notification options. + * @return {Object} Converted options. + */ + function convertProperties(options) { + if (options.id) { + if (isNaN(options.id)) { + options.id = defaults.id; + $log.warn('Id is not a number: ' + options.id); + } else { + options.id = Number(options.id); + } + } + + if (options.title) { + options.title = options.title.toString(); + } + + if (options.text) { + options.text = options.text.toString(); + } + + if (options.badge) { + if (isNaN(options.badge)) { + options.badge = defaults.badge; + $log.warn('Badge number is not a number: ' + options.id); + } else { + options.badge = Number(options.badge); + } + } + + if (options.at) { + if (typeof options.at == 'object') { + options.at = options.at.getTime(); + } + + options.at = Math.round(options.at / 1000); + } + + if (typeof options.data == 'object') { + options.data = JSON.stringify(options.data); + } + + return options; + } + + /** + * Get all the notification stored in local DB. + * + * @return {Promise} Promise resolved with the notifications. + */ + function getAllNotifications() { + return $mmApp.getDB().getAll(mmCoreDesktopLocalNotificationsStore); + } + + /** + * Get a set of notifications. If ids isn't specified, return all the notifications. + * + * @param {Number[]} [ids] Ids of notifications to get. If not specified, get all notifications. + * @param {Boolean} [getScheduled] Get scheduled notifications. + * @param {Boolean} [getTriggered] Get triggered notifications. + * @return {Object[]} List of notifications. + */ + function getNotifications(ids, getScheduled, getTriggered) { + var notifications = []; + + if (getScheduled) { + angular.forEach(scheduled, function(entry, id) { + if (!ids || ids.indexOf(id) != -1) { + notifications.push(entry.notification); + } + }); + } + + if (getTriggered) { + angular.forEach(triggered, function(notification, id) { + if ((!getScheduled || !scheduled[id]) && (!ids || ids.indexOf(id) != -1)) { + notifications.push(notification); + } + }); + } + + return notifications; + } + + /** + * Given an object of options and a list of properties, return the first property that exists. + * Code extracted from the Cordova plugin. + * + * @param {Object} options Notification options. + * @return {Mixed} First value found. + */ + function getValueFor(options) { + var keys = Array.apply(null, arguments).slice(1); + + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + + if (options.hasOwnProperty(key)) { + return options[key]; + } + } + } + + /** + * Load the emulation of the Cordova plugin. Only for desktop apps. + * + * @module mm.core.emulator + * @ngdoc method + * @name $mmEmulatorLocalNotifications#load + * @return {Promise} Promise resolved when done. + */ + self.load = function() { + if (!$mmApp.isDesktop()) { + return $q.when(); + } + + if ($mmEmulatorHelper.isWindows()) { + try { + winNotif = require('electron-windows-notifications'); + } catch(ex) {} + } + + // Redefine $cordovaLocalNotification methods instead of the core plugin (window.cordova.plugins.notification.local) + // because creating window.cordova breaks the app (it thinks it's a real device). + $cordovaLocalNotification.schedule = function(notifications, scope, isUpdate) { + var promises = []; + + notifications = Array.isArray(notifications) ? notifications : [notifications]; + + angular.forEach(notifications, function(notification) { + mergeWithDefaults(notification); + convertProperties(notification); + + // Cancel current notification if exists. + $cordovaLocalNotification.cancel(notification.id, null, true); + + // Store the notification in the scheduled list and in the DB. + scheduled[notification.id] = { + notification: notification + }; + promises.push(storeNotification(notification, false)); + + if (Math.abs(moment().diff(notification.at * 1000, 'days')) > 15) { + // Notification should trigger more than 15 days from now, don't schedule it. Using $timeout + // with numbers higher than (2^31 - 1) will trigger the function immediately. + return; + } + + // Schedule the notification. + var toTrigger = notification.at * 1000 - Date.now(); + scheduled[notification.id].timeout = $timeout(function trigger() { + // Trigger the notification. + triggerNotification(notification); + + // Store the notification as triggered. Don't remove it from scheduled, it's how the plugin works. + triggered[notification.id] = notification; + storeNotification(notification, true); + + // Launch the trigger event. + $rootScope.$broadcast('$cordovaLocalNotification:trigger', notification, 'foreground'); + + if (notification.every && scheduled[notification.id] && !scheduled[notification.id].interval) { + var interval = parseInterval(notification.every); + if (interval > 0) { + scheduled[notification.id].interval = $interval(trigger, interval); + } + } + }, toTrigger); + + // Launch the scheduled/update event. + var eventName = isUpdate ? 'update' : 'schedule'; + $rootScope.$broadcast('$cordovaLocalNotification:' + eventName, notification, 'foreground'); + }); + + return $q.when(); + }; + + $cordovaLocalNotification.update = function(notifications) { + // Just schedule them again, since scheduling cancels the existing one. + return $cordovaLocalNotification.schedule(notifications, null, true); + }; + + $cordovaLocalNotification.clear = function(ids, scope, omitEvent) { + var promises = []; + + ids = Array.isArray(ids) ? ids : [ids]; + ids = convertIds(ids); + + // Clear the notifications. + angular.forEach(ids, function(id) { + // Cancel only the notifications that aren't repeating. + if (scheduled[id] && scheduled[id].notification && !scheduled[id].notification.every) { + promises.push(cancelNotification(id, omitEvent, '$cordovaLocalNotification:clear')); + } + }); + + return $q.all(promises); + }; + + $cordovaLocalNotification.clearAll = function(scope, omitEvent) { + var ids = Object.keys(scheduled); + return $cordovaLocalNotification.clear(ids, scope, omitEvent).then(function() { + if (!omitEvent) { + $rootScope.$broadcast('$cordovaLocalNotification:clearall', 'foreground'); + } + }); + }; + + $cordovaLocalNotification.cancel = function(ids, scope, omitEvent) { + var promises = []; + + ids = Array.isArray(ids) ? ids : [ids]; + ids = convertIds(ids); + + // Cancel the notifications. + angular.forEach(ids, function(id) { + if (scheduled[id]) { + promises.push(cancelNotification(id, omitEvent, '$cordovaLocalNotification:cancel')); + } + }); + + return $q.all(promises); + }; + + $cordovaLocalNotification.cancelAll = function(scope, omitEvent) { + var ids = Object.keys(scheduled); + return $cordovaLocalNotification.cancel(ids, scope, omitEvent).then(function() { + if (!omitEvent) { + $rootScope.$broadcast('$cordovaLocalNotification:cancelall', 'foreground'); + } + }); + }; + + $cordovaLocalNotification.isPresent = function(id) { + return $q.when(!!scheduled[id] || !!triggered[notification.id]); + }; + + $cordovaLocalNotification.isScheduled = function(id) { + return $q.when(!!scheduled[id]); + }; + + $cordovaLocalNotification.isTriggered = function(id) { + return $q.when(!!triggered[notification.id]); + }; + + $cordovaLocalNotification.hasPermission = function() { + return $q.when(true); + }; + + $cordovaLocalNotification.registerPermission = function() { + return $q.when(true); + }; + + $cordovaLocalNotification.getAllIds = function() { + return $q.when($mmUtil.mergeArraysWithoutDuplicates(Object.keys(scheduled), Object.keys(triggered))); + }; + $cordovaLocalNotification.getIds = $cordovaLocalNotification.getAllIds; + + $cordovaLocalNotification.getScheduledIds = function() { + return $q.when(Object.keys(scheduled)); + }; + + $cordovaLocalNotification.getTriggeredIds = function() { + return $q.when(Object.keys(triggered)); + }; + + $cordovaLocalNotification.get = function(ids) { + ids = Array.isArray(ids) ? ids : [ids]; + ids = convertIds(ids); + return $q.when(getNotifications(ids, true, true)); + }; + + $cordovaLocalNotification.getAll = function() { + return $q.when(getNotifications(null, true, true)); + }; + + $cordovaLocalNotification.getScheduled = function(ids) { + ids = Array.isArray(ids) ? ids : [ids]; + ids = convertIds(ids); + return $q.when(getNotifications(ids, true, false)); + }; + + $cordovaLocalNotification.getAllScheduled = function() { + return $q.when(getNotifications(null, true, false)); + }; + + $cordovaLocalNotification.getTriggered = function(ids) { + ids = Array.isArray(ids) ? ids : [ids]; + ids = convertIds(ids); + return $q.when(getNotifications(ids, false, true)); + }; + + $cordovaLocalNotification.getAllTriggered = function() { + return $q.when(getNotifications(null, false, true)); + }; + + $cordovaLocalNotification.getDefaults = function() { + return defaults; + }; + + $cordovaLocalNotification.setDefaults = function(newDefaults) { + for (var key in defaults) { + if (newDefaults.hasOwnProperty(key)) { + defaults[key] = newDefaults[key]; + } + } + }; + + // App is being loaded, re-schedule all the notifications that were scheduled before. + return getAllNotifications().catch(function() { + return []; + }).then(function(notifications) { + angular.forEach(notifications, function(notification) { + if (notification.triggered) { + // Notification was triggered already, store it in memory but don't schedule it again. + delete notification.triggered; + scheduled[notification.id] = { + notification: notification + }; + triggered[notification.id] = notification; + } else { + // Schedule the notification again unless it should have been triggered more than an hour ago. + delete notification.triggered; + notification.at = notification.at * 1000; + if (notification.at - Date.now() > - mmCoreSecondsHour * 1000) { + $cordovaLocalNotification.schedule(notification); + } + } + }); + }); + }; + + /** + * Merge notification options with default values. + * Code extracted from the Cordova plugin. + * + * @param {Object} options Notification options. + * @return {Object} Merged options. + */ + function mergeWithDefaults(options) { + options.at = getValueFor(options, 'at', 'firstAt', 'date'); + options.text = getValueFor(options, 'text', 'message'); + options.data = getValueFor(options, 'data', 'json'); + + if (defaults.hasOwnProperty('autoClear')) { + options.autoClear = getValueFor(options, 'autoClear', 'autoCancel'); + } + + if (options.autoClear !== true && options.ongoing) { + options.autoClear = false; + } + + if (options.at === undefined || options.at === null) { + options.at = new Date(); + } + + for (var key in defaults) { + if (options[key] === null || options[key] === undefined) { + if (options.hasOwnProperty(key) && ['data','sound'].indexOf(key) > -1) { + options[key] = undefined; + } else { + options[key] = defaults[key]; + } + } + } + + for (key in options) { + if (!defaults.hasOwnProperty(key)) { + delete options[key]; + $log.warn('Unknown property: ' + key); + } + } + + return options; + } + + /** + * Function called when a notification is clicked. + * + * @param {Object} notification Clicked notification. + * @return {Void} + */ + function notificationClicked(notification) { + $rootScope.$broadcast('$cordovaLocalNotification:click', notification, 'foreground'); + // Focus the app. + require('electron').ipcRenderer.send('focusApp'); + } + + /** + * Parse a interval and convert it to a number of milliseconds (0 if not valid). + * Code extracted from the Cordova plugin. + * + * @param {String} every Interval to convert. + * @return {Number} Number of milliseconds of the interval- + */ + function parseInterval(every) { + var interval; + + every = String(every).toLowerCase(); + + if (!every || every == 'undefined') { + interval = 0; + } else if (every == 'second') { + interval = 1000; + } else if (every == 'minute') { + interval = mmCoreSecondsMinute * 1000; + } else if (every == 'hour') { + interval = mmCoreSecondsHour * 1000; + } else if (every == 'day') { + interval = mmCoreSecondsDay * 1000; + } else if (every == 'week') { + interval = mmCoreSecondsDay * 7 * 1000; + } else if (every == 'month') { + interval = mmCoreSecondsDay * 31 * 1000; + } else if (every == 'quarter') { + interval = mmCoreSecondsHour * 2190 * 1000; + } else if (every == 'year') { + interval = mmCoreSecondsYear * 1000; + } else { + interval = parseInt(every, 10); + if (isNaN(interval)) { + interval = 0; + } else { + interval *= 60000; + } + } + + return interval; + } + + /** + * Remove a notification from local DB. + * + * @param {Number} id ID of the notification. + * @return {Promise} Promise resolved when done. + */ + function removeNotification(id) { + return $mmApp.getDB().remove(mmCoreDesktopLocalNotificationsStore, id); + } + + /** + * Store a notification in local DB. + * + * @param {Object} notification Notification to store. + * @param {Boolean} triggered Whether the notification has been triggered. + * @return {Promise} Promise resolved when stored. + */ + function storeNotification(notification, triggered) { + notification = angular.copy(notification); + notification.triggered = !!triggered; + return $mmApp.getDB().insert(mmCoreDesktopLocalNotificationsStore, notification); + } + + /** + * Trigger a notification, using the best method depending on the OS. + * + * @param {Object} notification Notification to trigger. + * @return {Void} + */ + function triggerNotification(notification) { + if (winNotif) { + // Use Windows notifications. + var notifInstance = new winNotif.ToastNotification({ + appId: mmCoreConfigConstants.app_id, + template: toastTemplate, + strings: [notification.title, notification.text] + }); + + // Listen for click events. + notifInstance.on('activated', function() { + notificationClicked(notification); + }); + + notifInstance.show(); + + try { + // Show it in Tile too. + var tileNotif = new winNotif.TileNotification({ + tag: notification.id + '', + template: tileTemplate, + strings: [notification.title, notification.text, notification.title, notification.text, notification.title, notification.text], + expirationTime: new Date(Date.now() + mmCoreSecondsHour * 1000) // Expire in 1 hour. + }) + + tileNotif.show() + } catch(ex) { + $log.warn('Error showing TileNotification. Please notice they only work with the app installed.', ex); + } + } else { + // Use Electron default notifications. + var notifInstance = new Notification(notification.title, { + body: notification.text + }); + + // Listen for click events. + notifInstance.onclick = function() { + notificationClicked(notification); + }; + } + } + + return self; +}); diff --git a/www/core/components/emulator/services/mediacapture.js b/www/core/components/emulator/services/mediacapture.js new file mode 100644 index 00000000000..98d5e34557d --- /dev/null +++ b/www/core/components/emulator/services/mediacapture.js @@ -0,0 +1,606 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.core.emulator') + +/** + * This service handles the emulation of the Cordova Media Capture plugin in desktop apps and in browser. + * + * @ngdoc service + * @name $mmEmulatorMediaCapture + * @module mm.core.emulator + */ +.factory('$mmEmulatorMediaCapture', function($log, $q, $ionicModal, $rootScope, $window, $mmUtil, $mmFS, $timeout) { + + $log = $log.getInstance('$mmEmulatorMediaCapture'); + + var self = {}, + possibleAudioMimeTypes = { + 'audio/webm': 'weba', + 'audio/ogg': 'ogg' + }, + possibleVideoMimeTypes = { + 'video/webm;codecs=vp9': 'webm', + 'video/webm;codecs=vp8': 'webm', + 'video/ogg': 'ogv' + }, + videoMimeType, + audioMimeType; + + /** + * Capture media (image, audio, video). + * + * @param {String} type Type of media: image, audio, video. + * @param {Function} successCallback Function called when media taken. + * @param {Function} errorCallback Function called when error or cancel. + * @param {Object} [options] Optional options. + * @return {Void} + */ + function captureMedia(type, successCallback, errorCallback, options) { + options = options || {}; + + var loadingModal; + + try { + var scope = $rootScope.$new(), + facingMode = 'environment', + mimetype, + extension, + quality = 0.92, // Image only. + returnData = false, // Image only. + isCaptureImage = false; // To identify if it's capturing an image using media capture plugin (instead of camera). + + loadingModal = $mmUtil.showModalLoading(); + + if (type == 'captureimage') { + isCaptureImage = true; + type = 'image'; + } + + // Initialize some data based on the type of media to capture. + if (type == 'video') { + scope.isVideo = true; + title = 'mm.core.capturevideo'; + mimetype = videoMimeType; + extension = possibleVideoMimeTypes[mimetype]; + } else if (type == 'audio') { + scope.isAudio = true; + title = 'mm.core.captureaudio'; + mimetype = audioMimeType; + extension = possibleAudioMimeTypes[mimetype]; + } else if (type == 'image') { + scope.isImage = true; + title = 'mm.core.captureimage'; + + if (typeof options.sourceType != 'undefined' && options.sourceType != Camera.PictureSourceType.CAMERA) { + errorCallback && errorCallback('This source type is not supported in desktop.'); + loadingModal.dismiss(); + return; + } + + if (options.cameraDirection == Camera.Direction.FRONT) { + facingMode = 'user'; + } + + if (options.encodingType == Camera.EncodingType.PNG) { + mimetype = 'image/png'; + extension = 'png'; + } else { + mimetype = 'image/jpeg'; + extension = 'jpeg'; + } + + if (options.quality >= 0 && options.quality <= 100) { + quality = options.quality / 100; + } + + if (options.destinationType == Camera.DestinationType.DATA_URL) { + returnData = true; + } + } + + if (options.duration) { + scope.chronoEndTime = options.duration * 1000; + } + + initModal(scope).then(function(modal) { + var constraints = { + video: scope.isAudio ? false : {facingMode: facingMode}, + audio: !scope.isImage + }; + + return navigator.mediaDevices.getUserMedia(constraints).then(function(localMediaStream) { + var streamVideo, + previewMedia, + canvas, + imgEl, + mediaRecorder, + chunks = [], + mediaBlob, + audioDrawer; + + if (scope.isImage) { + canvas = modal.modalEl.querySelector('canvas.mm-webcam-image-canvas'); + imgEl = modal.modalEl.querySelector('img.mm-webcam-image'); + } else { + if (scope.isVideo) { + previewMedia = modal.modalEl.querySelector('video.mm-webcam-video-captured'); + } else { + previewMedia = modal.modalEl.querySelector('audio.mm-audio-captured'); + canvas = modal.modalEl.querySelector('canvas.mm-audio-canvas'); + audioDrawer = initAudioDrawer(localMediaStream, canvas); + audioDrawer.start(); + } + + mediaRecorder = new MediaRecorder(localMediaStream, {mimeType: mimetype}); + + // When video or audio is recorded, add it to the list of chunks. + mediaRecorder.ondataavailable = function(e) { + if (e.data.size > 0) { + chunks.push(e.data); + } + }; + + // When recording stops, create a Blob element with the recording and set it to the video or audio. + mediaRecorder.onstop = function() { + mediaBlob = new Blob(chunks); + chunks = []; + + previewMedia.src = $window.URL.createObjectURL(mediaBlob); + }; + } + + if (scope.isImage || scope.isVideo) { + var hasLoaded = false, + waitTimeout; + + // Set the stream as the source of the video. + streamVideo = modal.modalEl.querySelector('video.mm-webcam-stream'); + streamVideo.src = $window.URL.createObjectURL(localMediaStream); + + // Stream ready, show modal. + streamVideo.onloadedmetadata = function() { + if (hasLoaded) { + // Already loaded or timeout triggered, stop. + return; + } + + hasLoaded = true; + $timeout.cancel(waitTimeout); + loadingModal.dismiss(); + modal.show(); + scope.readyToCapture = true; + streamVideo.onloadedmetadata = null; + }; + + // If stream isn't ready in a while, show error. + waitTimeout = $timeout(function() { + if (!hasLoaded) { + // Show error. + hasLoaded = true; + loadingModal.dismiss(); + errorCallback && errorCallback({code: -1, message: 'Cannot connect to webcam.'}); + } + }, 10000); + } else { + // No need to wait to show the modal. + loadingModal.dismiss(); + modal.show(); + scope.readyToCapture = true; + } + + // Capture or stop capturing (stop is only for video and audio). + scope.actionClicked = function() { + if (scope.isCapturing) { + // It's capturing, stop. + scope.stopCapturing(); + } else { + if (!scope.isImage) { + // Start the capture. + scope.isCapturing = true; + mediaRecorder.start(); + scope.$broadcast('mm-chrono-start'); + } else { + // Get the image from the video and set it to the canvas, using video width/height. + var width = streamVideo.videoWidth, + height = streamVideo.videoHeight; + + canvas.width = width; + canvas.height = height; + canvas.getContext('2d').drawImage(streamVideo, 0, 0, width, height); + + // Convert the image to blob and show it in an image element. + loadingModal = $mmUtil.showModalLoading(); + canvas.toBlob(function(blob) { + loadingModal.dismiss(); + + mediaBlob = blob; + imgEl.setAttribute('src', $window.URL.createObjectURL(mediaBlob)); + scope.hasCaptured = true; + }, mimetype, quality); + + } + } + }; + + // Stop capturing. Only for video and audio. + scope.stopCapturing = function() { + streamVideo && streamVideo.pause(); + audioDrawer && audioDrawer.stop(); + mediaRecorder.stop(); + scope.isCapturing = false; + scope.hasCaptured = true; + scope.$broadcast('mm-chrono-stop'); + }; + + // Discard the captured media. + scope.discard = function() { + previewMedia && previewMedia.pause(); + streamVideo && streamVideo.play(); + audioDrawer && audioDrawer.start(); + + scope.hasCaptured = false; + scope.isCapturing = false; + scope.$broadcast('mm-chrono-reset'); + delete mediaBlob; + }; + + // Done capturing, write the file. + scope.done = function() { + if (returnData) { + // Return the image as a base64 string. + success(canvas.toDataURL(mimetype, quality)); + return; + } + + if (!mediaBlob) { + // Shouldn't happen. + $mmUtil.showErrorModal('Please capture the media first.'); + return; + } + + // Create the file and return it. + var fileName = type + '_' + $mmUtil.readableTimestamp() + '.' + extension, + path = $mmFS.concatenatePaths($mmFS.getTmpFolder(), 'media/' + fileName); + + loadingModal = $mmUtil.showModalLoading(); + + $mmFS.writeFile(path, mediaBlob).then(function(fileEntry) { + if (scope.isImage && !isCaptureImage) { + success(fileEntry.toURL()); + } else { + // The capture plugin returns a MediaFile, not a FileEntry. The only difference is that + // it supports a new function that won't be supported in desktop. + fileEntry.getFormatData = function(successFn, errorFn) { + errorFn && errorFn('Not supported'); + }; + + success([fileEntry]); + } + }).catch(function(err) { + $mmUtil.showErrorModal(err); + }).finally(function() { + loadingModal.dismiss(); + }); + }; + + // Success capturing the data. + function success(data) { + scope.modal.hide(); + + // Wait for the modal to close before calling the callback to prevent Ionic bug with modals. + $timeout(function() { + successCallback && successCallback(data); + }, 400); + } + + // Capture cancelled. + scope.cancel = function() { + scope.modal.hide(); + var error = scope.isImage && !isCaptureImage ? 'Camera cancelled' : {code: 3, message: 'Canceled.'}; + errorCallback && errorCallback(error); + }; + + scope.$on('modal.hidden', function() { + // Modal hidden, stop video and stream and destroy the scope. + var tracks = localMediaStream.getTracks(); + angular.forEach(tracks, function(track) { + track.stop(); + }); + streamVideo && streamVideo.pause(); + previewMedia && previewMedia.pause(); + audioDrawer && audioDrawer.stop(); + scope.$destroy(); + }); + + scope.$on('$destroy', function() { + scope.modal.remove(); + }); + }); + }).catch(function(err) { + loadingModal && loadingModal.dismiss(); + errorCallback && errorCallback(err); + }); + } catch(ex) { + loadingModal && loadingModal.dismiss(); + errorCallback && errorCallback(ex.toString()); + } + } + + /** + * Initialize the audio drawer. This code has been extracted from MDN's example on MediaStream Recording: + * https://github.com/mdn/web-dictaphone + * + * @param {Object} stream Stream returned by getUserMedia. + * @param {Object} canvas Canvas element where to draw the audio waves. + * @return {Object} Object to start and stop the drawer. + */ + function initAudioDrawer(stream, canvas) { + var audioCtx = new (window.AudioContext || webkitAudioContext)(), + canvasCtx = canvas.getContext("2d"), + source = audioCtx.createMediaStreamSource(stream), + analyser = audioCtx.createAnalyser(), + bufferLength = analyser.frequencyBinCount, + dataArray = new Uint8Array(bufferLength), + width = canvas.width, + height = canvas.height, + running = false, + skip = true; + + analyser.fftSize = 2048; + source.connect(analyser); + + return { + start: function() { + if (running) { + return; + } + + running = true; + drawAudio(); + }, + stop: function() { + running = false; + } + }; + + function drawAudio() { + if (!running) { + return; + } + + // Update the draw every animation frame. + requestAnimationFrame(drawAudio); + + // Skip half of the frames to improve performance, shouldn't affect the smoothness. + skip = !skip; + if (skip) { + return; + } + + var sliceWidth = width / bufferLength, + x = 0; + + analyser.getByteTimeDomainData(dataArray); + + canvasCtx.fillStyle = 'rgb(200, 200, 200)'; + canvasCtx.fillRect(0, 0, width, height); + + canvasCtx.lineWidth = 1; + canvasCtx.strokeStyle = 'rgb(0, 0, 0)'; + + canvasCtx.beginPath(); + + for(var i = 0; i < bufferLength; i++) { + var v = dataArray[i] / 128.0, + y = v * height / 2; + + if (i === 0) { + canvasCtx.moveTo(x, y); + } else { + canvasCtx.lineTo(x, y); + } + + x += sliceWidth; + } + + canvasCtx.lineTo(width, height / 2); + canvasCtx.stroke(); + } + } + + /** + * Init the getUserMedia function, using a deprecated function as fallback if the new one doesn't exist. + * + * @return {Boolean} Whether the function is supported. + */ + function initGetUserMedia() { + // Check if there is a function to get user media. + navigator.mediaDevices = navigator.mediaDevices || {}; + + if (!navigator.mediaDevices.getUserMedia) { + // New function doesn't exist, check if the deprecated function is supported. + navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || + navigator.mozGetUserMedia || navigator.msGetUserMedia; + + if (navigator.getUserMedia) { + // Deprecated function exists, support the new function using the deprecated one. + navigator.mediaDevices.getUserMedia = function(constraints) { + var deferred = $q.defer(); + navigator.getUserMedia(constraints, deferred.resolve, deferred.reject); + return deferred.promise; + }; + } else { + return false; + } + } + + return true; + } + + /** + * Initialize the mimetypes to use when capturing. + * + * @return {Void} + */ + function initMimeTypes() { + // Determine video and audio mimetype to use. + for (var mimeType in possibleVideoMimeTypes) { + if (MediaRecorder.isTypeSupported(mimeType)) { + videoMimeType = mimeType; + break; + } + } + + for (mimeType in possibleAudioMimeTypes) { + if (MediaRecorder.isTypeSupported(mimeType)) { + audioMimeType = mimeType; + break; + } + } + } + + /** + * Initialize the modal to capture media. + * + * @param {Object} scope Scope to use in the modal. + * @return {Promise} Promise resolved when the modal is initialized. + */ + function initModal(scope) { + // Chat users modal. + return $ionicModal.fromTemplateUrl('core/components/emulator/templates/capturemediamodal.html', { + scope: scope, + animation: 'slide-in-up' + }).then(function(modal) { + scope.modal = modal; + + return modal; + }); + } + + /** + * Load the emulation of the Cordova plugin. + * + * @module mm.core.emulator + * @ngdoc method + * @name $mmEmulatorMediaCapture#load + * @return {Promise} Promise resolved when done. + */ + self.load = function() { + if (typeof window.MediaRecorder == 'undefined') { + // Cannot record. + return $q.when(); + } + + if (!initGetUserMedia()) { + // Function not supported, stop. + return $q.when(); + } + + initMimeTypes(); + + navigator.device = navigator.device || {}; + navigator.device.capture = navigator.device.capture || {}; + navigator.camera = navigator.camera || {}; + + // Create Camera constants. + $window.Camera = $window.Camera || {}; + + $window.Camera.DestinationType = { + DATA_URL: 0, + FILE_URI: 1, + NATIVE_URI: 2 + }; + + $window.Camera.Direction = { + BACK: 0, + FRONT: 1 + }; + + $window.Camera.EncodingType = { + JPEG: 0, + PNG: 1 + }; + + $window.Camera.MediaType = { + PICTURE: 0, + VIDEO: 1, + ALLMEDIA: 2 + }; + + $window.Camera.PictureSourceType = { + PHOTOLIBRARY: 0, + CAMERA: 1, + SAVEDPHOTOALBUM: 2 + }; + + $window.Camera.PopoverArrowDirection = { + ARROW_UP: 1, + ARROW_DOWN: 2, + ARROW_LEFT: 4, + ARROW_RIGHT: 8, + ARROW_ANY: 15 + }; + + // Copy the constants to navigator.camera. + angular.extend(navigator.camera, $window.Camera); + + // Create CameraPopoverOptions and CameraPopoverHandle. + $window.CameraPopoverOptions = function() { + // Nothing to do, not supported in desktop. + }; + + $window.CameraPopoverHandle = function() { + // Nothing to do, not supported in desktop. + }; + $window.CameraPopoverHandle.prototype.setPosition = function() { + // Nothing to do, not supported in desktop. + }; + + // Create camera methods. + navigator.camera.getPicture = function(successCallback, errorCallback, options) { + return captureMedia('image', successCallback, errorCallback, options); + }; + + navigator.camera.cleanup = function(successCallback, errorCallback) { + // The tmp folder is cleaned when the app is started, do nothing. + successCallback && successCallback(); + }; + + // Support Media Capture methods. + navigator.device.capture.captureImage = function(successCallback, errorCallback, options) { + return captureMedia('captureimage', successCallback, errorCallback, options); + }; + + navigator.device.capture.captureVideo = function(successCallback, errorCallback, options) { + return captureMedia('video', successCallback, errorCallback, options); + }; + + navigator.device.capture.captureAudio = function(successCallback, errorCallback, options) { + return captureMedia('audio', successCallback, errorCallback, options); + }; + + // Support other Media Capture variables. + $window.CaptureAudioOptions = function() {}; + $window.CaptureImageOptions = function() {}; + $window.CaptureVideoOptions = function() {}; + $window.CaptureError = function(c) { + this.code = c || null; + }; + + return $q.when(); + }; + + return self; +}); diff --git a/www/core/components/emulator/services/pushnotifications.js b/www/core/components/emulator/services/pushnotifications.js new file mode 100644 index 00000000000..81942971df6 --- /dev/null +++ b/www/core/components/emulator/services/pushnotifications.js @@ -0,0 +1,116 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.core.emulator') + +/** + * This service handles the emulation of the Cordova PushNotifications plugin. + * + * @ngdoc service + * @name $mmEmulatorPushNotifications + * @module mm.core.emulator + */ +.factory('$mmEmulatorPushNotifications', function($log, $q, $window, $mmApp) { + + $log = $log.getInstance('$mmEmulatorPushNotifications'); + + var self = {}; + + /** + * Load the emulation of the Cordova plugin. + * Only some functions are supported. + * + * @module mm.core.emulator + * @ngdoc method + * @name $mmEmulatorPushNotifications#load + * @return {Promise} Promise resolved when done. + */ + self.load = function() { + // Create the PushNotification object. + var PushNotification = function(options) {}; + + PushNotification.prototype.unregister = function(successCallback, errorCallback, options) { + errorCallback && errorCallback('Unregister is only supported in mobile devices'); + }; + + PushNotification.prototype.subscribe = function(topic, successCallback, errorCallback) { + errorCallback && errorCallback('Suscribe is only supported in mobile devices'); + }; + + PushNotification.prototype.unsubscribe = function(topic, successCallback, errorCallback) { + errorCallback && errorCallback('Unsuscribe is only supported in mobile devices'); + }; + + PushNotification.prototype.setApplicationIconBadgeNumber = function(successCallback, errorCallback, badge) { + if (!$mmApp.isDesktop()) { + errorCallback && errorCallback('setApplicationIconBadgeNumber is not supported in browser'); + return; + } + + try { + var app = require('electron').remote.app; + if (app.setBadgeCount(badge)) { + successCallback && successCallback(); + } else { + errorCallback && errorCallback(); + } + } catch(ex) { + errorCallback && errorCallback(ex); + } + }; + + PushNotification.prototype.getApplicationIconBadgeNumber = function(successCallback, errorCallback) { + if (!$mmApp.isDesktop()) { + errorCallback && errorCallback('getApplicationIconBadgeNumber is not supported in browser'); + return; + } + + try { + var app = require('electron').remote.app; + successCallback && successCallback(app.getBadgeCount()); + } catch(ex) { + errorCallback && errorCallback(ex); + } + }; + + PushNotification.prototype.clearAllNotifications = function(successCallback, errorCallback) { + errorCallback && errorCallback('clearAllNotifications is only supported in mobile devices'); + }; + + PushNotification.prototype.on = function(eventName, callback) {}; + PushNotification.prototype.off = function(eventName, handle) {}; + PushNotification.prototype.emit = function() {}; + + PushNotification.prototype.finish = function(successCallback, errorCallback, id) { + errorCallback && errorCallback('finish is only supported in mobile devices'); + }; + + // Create the visible PushNotification object. + $window.PushNotification = { + init: function(options) { + return new PushNotification(options); + }, + + hasPermission: function(successCallback, errorCallback) { + errorCallback && errorCallback('hasPermission is only supported in mobile devices'); + }, + + PushNotification: PushNotification + }; + + return $q.when(); + }; + + return self; +}); diff --git a/www/core/components/emulator/services/zip.js b/www/core/components/emulator/services/zip.js new file mode 100644 index 00000000000..1e736beced8 --- /dev/null +++ b/www/core/components/emulator/services/zip.js @@ -0,0 +1,89 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.core.emulator') + +/** + * This service handles the emulation of the Cordova Zip plugin in desktop apps and in browser. + * + * @ngdoc service + * @name $mmEmulatorZip + * @module mm.core.emulator + */ +.factory('$mmEmulatorZip', function($log, $q, $mmFS, $window) { + + $log = $log.getInstance('$mmEmulatorZip'); + + var self = {}; + + /** + * Load the emulation of the Cordova plugin. + * Only support the unzip function, the rest of functions won't be supported for now. + * + * @module mm.core.emulator + * @ngdoc method + * @name $mmEmulatorZip#load + * @return {Promise} Promise resolved when done. + */ + self.load = function() { + $window.zip = { + unzip: function(source, destination, callback, progressCallback) { + // Remove basePath from the source and destination. Also, replace all %20 with spaces. + var basePath = $mmFS.getBasePathInstant(); + source = source.replace(basePath, '').replace(/%20/g, ' '); + destination = destination.replace(basePath, '').replace(/%20/g, ' '); + + $mmFS.readFile(source, $mmFS.FORMATARRAYBUFFER).then(function(data) { + var zip = new JSZip(data), + promises = [], + loaded = 0, + total = Object.keys(zip.files).length; + + angular.forEach(zip.files, function(file, name) { + var filePath = $mmFS.concatenatePaths(destination, name), + type, + promise; + + if (!file.dir) { + // It's a file. Get the mimetype and write the file. + type = $mmFS.getMimeType($mmFS.getFileExtension(name)); + promise = $mmFS.writeFile(filePath, new Blob([file.asArrayBuffer()], {type: type})); + } else { + // It's a folder, create it if it doesn't exist. + promise = $mmFS.createDir(filePath); + } + + promises.push(promise.then(function() { + // File unzipped, call the progress. + loaded++; + progressCallback && progressCallback({loaded: loaded, total: total}); + })); + }); + + return $q.all(promises).then(function() { + // Success. + callback(0); + }); + }).catch(function() { + // Error. + callback(-1); + }); + } + }; + + return $q.when(); + }; + + return self; +}); diff --git a/www/core/components/emulator/templates/capturemediamodal.html b/www/core/components/emulator/templates/capturemediamodal.html new file mode 100644 index 00000000000..7d8be7d37d9 --- /dev/null +++ b/www/core/components/emulator/templates/capturemediamodal.html @@ -0,0 +1,39 @@ + + + +

{{ title }}

+ +
+ + + +
+ + + + + + + + + {{ 'mm.core.capturedimage' | translate }} + + +
+ + +
+
+
+ + +
+
+ + +
+
+ +
+
+
\ No newline at end of file diff --git a/www/core/components/fileuploader/lang/ar.json b/www/core/components/fileuploader/lang/ar.json index 68a20669859..3756250ce62 100644 --- a/www/core/components/fileuploader/lang/ar.json +++ b/www/core/components/fileuploader/lang/ar.json @@ -5,12 +5,12 @@ "errorcapturingimage": "خطأ في التقاط الصورة", "errorcapturingvideo": "خطأ في التقاط الفيديو", "errormustbeonlinetoupload": "لابد أن تكون متصل بالأنترنت لكي يتم رفع الملفات", - "errorreadingfile": "خطاء في قراءة ملف \"{{$a}}\"", + "errorreadingfile": "خطأ في قراءة الملف", "file": "ملف", "fileuploaded": "الملف الذي تم رفعه", "maxbytesfile": "حجم الملف {{$a.file}} كبير جداً . الحد الأقصى الذي تستطيع رفعه هو {{$a.size}}.", "readingfile": "يتم قراءة الملف", - "uploadafile": "تحميل ملف", - "uploading": "يتم التحميل", + "uploadafile": "إرفع ملف", + "uploading": "يتم الرفع", "video": "فيديو" } \ No newline at end of file diff --git a/www/core/components/fileuploader/lang/bg.json b/www/core/components/fileuploader/lang/bg.json index 9d46df4051f..9d95e088674 100644 --- a/www/core/components/fileuploader/lang/bg.json +++ b/www/core/components/fileuploader/lang/bg.json @@ -10,11 +10,11 @@ "errornoapp": "Нямате инсталирано приложение, което да извърши това действие.", "errorreadingfile": "Грешка при четенето на файла.", "errorwhileuploading": "Възникна грешка при качването на файла.", - "file": "Файл", + "file": "Качване на файлове", "fileuploaded": "Файлът е качен", "photoalbums": "Фотоалбуми", "readingfile": "Четене на файл", "uploadafile": "Качване на файл", - "uploading": "Качване", + "uploading": "Качване...", "video": "Видео" } \ No newline at end of file diff --git a/www/core/components/fileuploader/lang/da.json b/www/core/components/fileuploader/lang/da.json index 7b7c0c77636..3fe2280526b 100644 --- a/www/core/components/fileuploader/lang/da.json +++ b/www/core/components/fileuploader/lang/da.json @@ -9,7 +9,7 @@ "errorgettingimagealbum": "Fejl ved indhentning af billede fra album", "errormustbeonlinetoupload": "Du skal være online for at uploade filer.", "errornoapp": "Du har ikke installeret en app som kan udføre denne handling.", - "errorreadingfile": "Fejl under læsning af filen \"{{$a}}\"", + "errorreadingfile": "Fejl ved læsning af fil.", "errorwhileuploading": "En fejl opstod under upload af filen.", "file": "Fil", "fileuploaded": "Filen er uploadet.", @@ -17,6 +17,6 @@ "photoalbums": "Fotoalbum", "readingfile": "Læser fil", "uploadafile": "Upload en fil", - "uploading": "Uploader...", + "uploading": "Uploader", "video": "Video" } \ No newline at end of file diff --git a/www/core/components/fileuploader/lang/fa.json b/www/core/components/fileuploader/lang/fa.json index 02f6d7c8b77..31e7cb2c536 100644 --- a/www/core/components/fileuploader/lang/fa.json +++ b/www/core/components/fileuploader/lang/fa.json @@ -1,10 +1,11 @@ { + "addfiletext": "اضافه‌کردن فایل", "confirmuploadfile": "شما در آستانهٔ ارسال {{size}} هستید. آیا مطمئنید که می‌خواهید ادامه دهید؟", "confirmuploadunknownsize": "ما نتوانستیم حجم ارسال را محاسبه کنیم. آیا مطمئنید که می‌خواهید ادامه دهید؟", "errorcapturingaudio": "خطا در ضبط صدا", "errorcapturingvideo": "خطا در ضبط ویدئو", "errorreadingfile": "خطا در خواندن فایل «{{$a}}»", - "file": "فایل", + "file": "تحویل فایل", "fileuploaded": "فایل آپلود شده", "maxbytesfile": "فایل {{$a.file}} بسیار بزرگ است. بیشترین اندازه‌ای که می‌توانید ارسال کنید {{$a.size}} است.", "uploadafile": "قرار دادن یک فایل در سایت", diff --git a/www/core/components/fileuploader/lang/fr.json b/www/core/components/fileuploader/lang/fr.json index 68434825ec0..13eb0148fcf 100644 --- a/www/core/components/fileuploader/lang/fr.json +++ b/www/core/components/fileuploader/lang/fr.json @@ -15,7 +15,7 @@ "file": "Fichier", "fileuploaded": "Le fichier a été déposé.", "maxbytesfile": "Le fichier {{$a.file}} est trop gros. La taille maximale permise est de {{$a.size}}.", - "photoalbums": "Albums de photos", + "photoalbums": "Albums photos", "readingfile": "Lecture du fichier", "selectafile": "Choisir un fichier", "uploadafile": "Déposer un fichier", diff --git a/www/core/components/fileuploader/lang/he.json b/www/core/components/fileuploader/lang/he.json index 62479a48162..b6dda48ad1e 100644 --- a/www/core/components/fileuploader/lang/he.json +++ b/www/core/components/fileuploader/lang/he.json @@ -9,13 +9,13 @@ "errorgettingimagealbum": "שגיאה בטעינת תמונה מאלבום.", "errormustbeonlinetoupload": "עליך להיות מחובר/ת בכדי להעלות קבצים.", "errornoapp": "לא נמצא יישומון זמין לביצוע פעולה הזו.", - "errorreadingfile": "שגיאה בקריאת קובץ \"{{$a}}\"", + "errorreadingfile": "שגיאה בקריאת קובץ.", "errorwhileuploading": "התרחשה שגיאה בזמן הניסיון להעלות את הקובץ.", "file": "קובץ", "fileuploaded": "הקובץ הועלה בהצלחה.", "photoalbums": "אלבומי תמונות", "readingfile": "קורא קובץ", - "uploadafile": "העלאת קובץ", - "uploading": "מעלה את הקובץ...", + "uploadafile": "העלה קובץ", + "uploading": "מעלה קבצים", "video": "וידאו" } \ No newline at end of file diff --git a/www/core/components/fileuploader/lang/hu.json b/www/core/components/fileuploader/lang/hu.json index cf59fdef06f..a78f133d773 100644 --- a/www/core/components/fileuploader/lang/hu.json +++ b/www/core/components/fileuploader/lang/hu.json @@ -3,7 +3,7 @@ "errorcapturingaudio": "Hiba a hang rögzítélse közben.", "errorcapturingvideo": "Nem sikerült videofelvételt készíteni.", "errorreadingfile": "Hiba a(z) \"{{$a}}\" állomány olvasása közben", - "file": "Állomány", + "file": "Leadás állományban", "fileuploaded": "Fájl feltöltve", "maxbytesfile": "A(z) {{$a.file}} állomány túl nagy. A feltölthető maximális méret {{$a.size}}.", "uploadafile": "Egy állomány feltöltése", diff --git a/www/core/components/fileuploader/lang/ja.json b/www/core/components/fileuploader/lang/ja.json index afec789151e..86f29cfe14c 100644 --- a/www/core/components/fileuploader/lang/ja.json +++ b/www/core/components/fileuploader/lang/ja.json @@ -1,14 +1,14 @@ { - "addfiletext": "ファイルを追加する", + "addfiletext": "ファイル追加", "confirmuploadfile": "{{$a}}をアップロードしようとしています。続けますか?", "errorcapturingaudio": "音声キャプチャーのエラー", "errorcapturingvideo": "ビデオキャプチャーのエラー", - "errorreadingfile": "ファイル「 {{$a}} 」の読み取り中にエラーが発生しました。", + "errorreadingfile": "ファイル\"{{$a}}\"の読み取りエラー", "file": "ファイル", "fileuploaded": "アップロードしたファイル", "maxbytesfile": "ファイル {{$a.file}} は大きすぎます。あなたがアップロードできる最大サイズは {{$a.size}} です。", "readingfile": "ファイル読み取り", "uploadafile": "ファイルをアップロードする", - "uploading": "アップロード中 ...", + "uploading": "アップロード中", "video": "ビデオ" } \ No newline at end of file diff --git a/www/core/components/fileuploader/lang/pl.json b/www/core/components/fileuploader/lang/pl.json index 1f23867319a..e56bf5f0ccd 100644 --- a/www/core/components/fileuploader/lang/pl.json +++ b/www/core/components/fileuploader/lang/pl.json @@ -4,7 +4,7 @@ "errorcapturingaudio": "Błąd poczas nagrywania dźwięku", "errorcapturingvideo": "Błąd podczas przechwytywania wideo", "errorreadingfile": "Błąd podczas odczytu z pliku \"{{$a}}\"", - "file": "Plik", + "file": "Przesyłane pliki", "fileuploaded": "Plik wysłany", "maxbytesfile": "Plik {{$a.file}} jest za duży Maksymalny rozmiar pliku, który możesz przesłać, może wynosić {{$a.size}}.", "readingfile": "Odczytywanie pliku", diff --git a/www/core/components/fileuploader/lang/ro.json b/www/core/components/fileuploader/lang/ro.json index 934f0c9f150..74a44c21314 100644 --- a/www/core/components/fileuploader/lang/ro.json +++ b/www/core/components/fileuploader/lang/ro.json @@ -9,14 +9,14 @@ "errorgettingimagealbum": "Eroare la obținerea imaginii din album.", "errormustbeonlinetoupload": "Pentru a putea încărca fișiere trebuie să fiți conectat la o rețea de date.", "errornoapp": "Nu aveți instalată o aplicație dedicată realizării acestei operațiuni.", - "errorreadingfile": "Eroare la citirea fișierului.", + "errorreadingfile": "Eroare la citirea fişierului {{$a}}", "errorwhileuploading": "A apărut o eroare în timpul încărcării fișierului.", - "file": "Fișier", + "file": "Fişier", "fileuploaded": "Fișierul a fost încărcat cu succes.", "maxbytesfile": "Fișierul {{$a.file}} este prea mare. Dimensiunea maximă pe care o puteți încărca este {{$a.size}}.", "photoalbums": "Albume foto", "readingfile": "Se citește fișierul", - "uploadafile": "Încărcați un fișier", - "uploading": "Se încarcă", + "uploadafile": "Incarcă un fişier", + "uploading": "Se încarcă ...", "video": "Video" } \ No newline at end of file diff --git a/www/core/components/fileuploader/lang/sr-cr.json b/www/core/components/fileuploader/lang/sr-cr.json new file mode 100644 index 00000000000..74ec8641949 --- /dev/null +++ b/www/core/components/fileuploader/lang/sr-cr.json @@ -0,0 +1,25 @@ +{ + "addfiletext": "Додај датотеку", + "audio": "Аудио", + "camera": "Камера", + "confirmuploadfile": "Намеравате да отпремите {{size}}. Да ли сте сигурни да желите да наставите?", + "confirmuploadunknownsize": "Нисмо могли да израчунамо величину датотека за отпремање. Да ли сте сигурни да желите да наставите?", + "errorcapturingaudio": "Грешка приликом снимања аудио записа.", + "errorcapturingimage": "Грешка приликом снимања слике.", + "errorcapturingvideo": "Грешка приликом снимања видео записа.", + "errorgettingimagealbum": "Грешка приликом преузимања слике из албума.", + "errormustbeonlinetoupload": "Морате бити онлајн како бисте отпремили датотеке.", + "errornoapp": "Немате инсталирану апликацију која може да изведе ову акцију.", + "errorreadingfile": "Грешка приликом учитавања датотеке.", + "errorwhileuploading": "Дошло је до грешке приликом отпремања датотеке.", + "file": "Датотека", + "fileuploaded": "Датотека је успешно отпремљена.", + "maxbytesfile": "Датотека {{$a.file}} је превелика. Максимална величина коју можете да отпремите је {{$a.size}}.", + "photoalbums": "Фото албум", + "readingfile": "Учитавање датотеке", + "selectafile": "Изабери датотеку", + "uploadafile": "Отпреми датотеку", + "uploading": "Отпремање", + "uploadingperc": "Отпремање: {{$a}}%", + "video": "Видео" +} \ No newline at end of file diff --git a/www/core/components/fileuploader/lang/sr-lt.json b/www/core/components/fileuploader/lang/sr-lt.json new file mode 100644 index 00000000000..5da78d54b07 --- /dev/null +++ b/www/core/components/fileuploader/lang/sr-lt.json @@ -0,0 +1,25 @@ +{ + "addfiletext": "Dodaj datoteku", + "audio": "Audio", + "camera": "Kamera", + "confirmuploadfile": "Nameravate da otpremite {{size}}. Da li ste sigurni da želite da nastavite?", + "confirmuploadunknownsize": "Nismo mogli da izračunamo veličinu datoteka za otpremanje. Da li ste sigurni da želite da nastavite?", + "errorcapturingaudio": "Greška prilikom snimanja audio zapisa.", + "errorcapturingimage": "Greška prilikom snimanja slike.", + "errorcapturingvideo": "Greška prilikom snimanja video zapisa.", + "errorgettingimagealbum": "Greška prilikom preuzimanja slike iz albuma.", + "errormustbeonlinetoupload": "Morate biti onlajn kako biste otpremili datoteke.", + "errornoapp": "Nemate instaliranu aplikaciju koja može da izvede ovu akciju.", + "errorreadingfile": "Greška prilikom učitavanja datoteke.", + "errorwhileuploading": "Došlo je do greške prilikom otpremanja datoteke.", + "file": "Датотека", + "fileuploaded": "Datoteka je uspešno otpremljena.", + "maxbytesfile": "Datoteka {{$a.file}} je prevelika. Maksimalna veličina koju možete da otpremite je {{$a.size}}.", + "photoalbums": "Foto album", + "readingfile": "Učitavanje datoteke", + "selectafile": "Izaberi datoteku", + "uploadafile": "Otpremi datoteku", + "uploading": "Otpremanje", + "uploadingperc": "Otpremanje: {{$a}}%", + "video": "Video" +} \ No newline at end of file diff --git a/www/core/components/fileuploader/lang/tr.json b/www/core/components/fileuploader/lang/tr.json index 23b8bac2bd4..e08f35d4b08 100644 --- a/www/core/components/fileuploader/lang/tr.json +++ b/www/core/components/fileuploader/lang/tr.json @@ -3,9 +3,9 @@ "errorcapturingaudio": "Ses kayıt hatası", "errorcapturingvideo": "Video kayıt hatası", "errorreadingfile": "\"{{$a}}\" dosyasını okurken hata oluştu", - "file": "Dosya", + "file": "Dosya gönderimleri", "fileuploaded": "Dosya başarıyla yüklendi", - "maxbytesfile": "Dosya {{$a.file}} çok büyük. Yüklediğiniz maksimum boyutu {{$a.size}} olduğunu.", + "maxbytesfile": "{{$a.file}} dosyasının boyutu çok büyük. En fazla {{$a.size}} MB büyüklüğünde dosya yükleyebilirsiniz.", "uploadafile": "Bir dosya yükle", "uploading": "Yükleniyor", "video": "Video" diff --git a/www/core/components/fileuploader/lang/zh-cn.json b/www/core/components/fileuploader/lang/zh-cn.json index db4fec8b382..822f2a56862 100644 --- a/www/core/components/fileuploader/lang/zh-cn.json +++ b/www/core/components/fileuploader/lang/zh-cn.json @@ -4,7 +4,7 @@ "errorcapturingaudio": "捕捉音频时出错。", "errorcapturingvideo": "捕捉视频时出错。", "errorreadingfile": "在读取文件“{{$a}}”时发生错误", - "file": "文件", + "file": "文件提交", "fileuploaded": "文件已成功上传。", "maxbytesfile": "这个文件 {{$a.file}} 太大了。你可以上传的文件最大容量是 {{$a.size}}。", "readingfile": "Odczytywanie pliku", diff --git a/www/core/components/fileuploader/scss/styles.scss b/www/core/components/fileuploader/scss/styles.scss index d35c7e95330..f8da47e3e68 100644 --- a/www/core/components/fileuploader/scss/styles.scss +++ b/www/core/components/fileuploader/scss/styles.scss @@ -8,5 +8,6 @@ opacity: 0; outline: none; z-index: 100; + cursor: pointer; } } diff --git a/www/core/components/fileuploader/services/handlers.js b/www/core/components/fileuploader/services/handlers.js index 62226e64440..1cc6ea3e1d6 100644 --- a/www/core/components/fileuploader/services/handlers.js +++ b/www/core/components/fileuploader/services/handlers.js @@ -42,7 +42,7 @@ angular.module('mm.core.fileuploader') * @return {Boolean} True if handler is enabled, false otherwise. */ self.isEnabled = function() { - return true; + return $mmApp.isDevice(); }; /** @@ -87,7 +87,7 @@ angular.module('mm.core.fileuploader') * @return {Boolean} True if handler is enabled, false otherwise. */ self.isEnabled = function() { - return true; + return $mmApp.isDevice() || $mmApp.canGetUserMedia(); }; /** @@ -132,7 +132,7 @@ angular.module('mm.core.fileuploader') * @return {Boolean} True if handler is enabled, false otherwise. */ self.isEnabled = function() { - return true; + return $mmApp.isDevice() || ($mmApp.canGetUserMedia() && $mmApp.canRecordMedia()); }; /** @@ -177,7 +177,7 @@ angular.module('mm.core.fileuploader') * @return {Boolean} True if handler is enabled, false otherwise. */ self.isEnabled = function() { - return true; + return $mmApp.isDevice() || ($mmApp.canGetUserMedia() && $mmApp.canRecordMedia()); }; /** @@ -223,7 +223,7 @@ angular.module('mm.core.fileuploader') * @return {Boolean} True if handler is enabled, false otherwise. */ self.isEnabled = function() { - return ionic.Platform.isAndroid(); + return ionic.Platform.isAndroid() || !$mmApp.isDevice(); }; /** @@ -247,25 +247,25 @@ angular.module('mm.core.fileuploader') if (!uploadFileScope) { // Create a scope for the on change directive. uploadFileScope = $rootScope.$new(); + } - uploadFileScope.filePicked = function(evt) { - var input = evt.srcElement; - var file = input.files[0]; - input.value = ''; // Unset input. - if (!file) { - return; + uploadFileScope.filePicked = function(evt) { + var input = evt.srcElement; + var file = input.files[0]; + input.value = ''; // Unset input. + if (!file) { + return; + } + + // Upload the picked file. + $mmFileUploaderHelper.uploadFileObject(file, maxSize, upload, allowOffline).then(function(result) { + $mmFileUploaderHelper.fileUploaded(result); + }).catch(function(error) { + if (error) { + $mmUtil.showErrorModal(error); } - - // Upload the picked file. - $mmFileUploaderHelper.uploadFileObject(file, maxSize, upload, allowOffline).then(function(result) { - $mmFileUploaderHelper.fileUploaded(result); - }).catch(function(error) { - if (error) { - $mmUtil.showErrorModal(error); - } - }); - }; - } + }); + }; $compile(input)(uploadFileScope); diff --git a/www/core/components/fileuploader/services/helper.js b/www/core/components/fileuploader/services/helper.js index aea9ef476d5..8e3bdc60cd6 100644 --- a/www/core/components/fileuploader/services/helper.js +++ b/www/core/components/fileuploader/services/helper.js @@ -69,7 +69,8 @@ angular.module('mm.core.fileuploader') // Delete the local files from the tmp folder. files.forEach(function(file) { if (!file.offline && file.remove) { - file.remove(); + // Pass an empty function to prevent missing parameter error. + file.remove(function() {}); } }); }; @@ -431,7 +432,8 @@ angular.module('mm.core.fileuploader') return fn({limit: 1}).then(function(medias) { // We used limit 1, we only want 1 media. var media = medias[0], - path = media.localURL; + path = media.localURL || media.toURL(); + if (upload) { return uploadFile(true, path, maxSize, true, $mmFileUploader.uploadMedia, media); } else { @@ -756,9 +758,7 @@ angular.module('mm.core.fileuploader') }, function() { // User cancelled. Delete the file if needed. if (deleteAfterUpload) { - angular.forEach(paths, function(path) { - $mmFS.removeExternalFile(path); - }); + $mmFS.removeExternalFile(path); } return $q.reject(); }); diff --git a/www/core/components/grades/lang/ar.json b/www/core/components/grades/lang/ar.json index 006afcb0ff9..7d384426017 100644 --- a/www/core/components/grades/lang/ar.json +++ b/www/core/components/grades/lang/ar.json @@ -1,6 +1,6 @@ { "average": "متوسط", - "feedback": "تقرير", + "feedback": "اجابة تقييمية", "grade": "درجة", "grades": "درجات", "itemname": "اسم البند", diff --git a/www/core/components/grades/lang/bg.json b/www/core/components/grades/lang/bg.json index ad342e2276c..2f83353a5e8 100644 --- a/www/core/components/grades/lang/bg.json +++ b/www/core/components/grades/lang/bg.json @@ -1,7 +1,7 @@ { "average": "Средно", "contributiontocoursetotal": "Дял в общата оценка", - "feedback": "Обратна връзка", + "feedback": "Съобщение", "grade": "Оценка", "grades": "Оценки", "itemname": "Име на единица", diff --git a/www/core/components/grades/lang/ca.json b/www/core/components/grades/lang/ca.json index d83a599cc60..7848c0d6909 100644 --- a/www/core/components/grades/lang/ca.json +++ b/www/core/components/grades/lang/ca.json @@ -3,13 +3,13 @@ "badgrade": "La qualificació proporcionada no és vàlida", "contributiontocoursetotal": "Contribució al total del curs", "feedback": "Retroacció", - "grade": "Qualifica", + "grade": "Qualificació", "grades": "Qualificacions", "itemname": "Nom de l'element", "lettergrade": "Qualificació per lletres", "nooutcome": "Sense competències", "percentage": "Percentatge", "range": "Gamma", - "rank": "Rang", + "rank": "Posició", "weight": "Ponderació" } \ No newline at end of file diff --git a/www/core/components/grades/lang/cs.json b/www/core/components/grades/lang/cs.json index cd3f92e83b2..c81a87bd9eb 100644 --- a/www/core/components/grades/lang/cs.json +++ b/www/core/components/grades/lang/cs.json @@ -2,7 +2,7 @@ "average": "Průměr", "badgrade": "Poskytnutá známka není platná", "contributiontocoursetotal": "Podíl z celkové známky", - "feedback": "Komentář", + "feedback": "Hodnocení", "grade": "Známka", "grades": "Známky", "itemname": "Název položky", @@ -10,6 +10,6 @@ "nooutcome": "Bez očekávaných výstupů", "percentage": "Procentuální hodnota", "range": "Rozsah", - "rank": "Pořadí", + "rank": "Umístění", "weight": "Váha" } \ No newline at end of file diff --git a/www/core/components/grades/lang/da.json b/www/core/components/grades/lang/da.json index ce5cab367fe..517d42331d7 100644 --- a/www/core/components/grades/lang/da.json +++ b/www/core/components/grades/lang/da.json @@ -2,7 +2,7 @@ "average": "Gennemsnit", "badgrade": "Karakteren er ugyldig", "contributiontocoursetotal": "Bidrag til kursets total", - "feedback": "Tilbagemelding", + "feedback": "Feedback", "grade": "Karakter", "grades": "Karakterer", "itemname": "Elementnavn", @@ -10,6 +10,6 @@ "nooutcome": "Intet slutresultat", "percentage": "Procentdel", "range": "Opstilling", - "rank": "Rank", + "rank": "Opstil", "weight": "Vægt" } \ No newline at end of file diff --git a/www/core/components/grades/lang/de.json b/www/core/components/grades/lang/de.json index 1f965bf6662..49bc672f741 100644 --- a/www/core/components/grades/lang/de.json +++ b/www/core/components/grades/lang/de.json @@ -1,9 +1,9 @@ { - "average": "Mittelwert", + "average": "Durchschnitt", "badgrade": "Ungültige Bewertung", "contributiontocoursetotal": "Beiträge zum Kurs insgesamt", - "feedback": "Rückmeldung", - "grade": "Relative Bewertung", + "feedback": "Feedback", + "grade": "Bewertung", "grades": "Bewertungen", "itemname": "Name des Aspekts", "lettergrade": "Notenstufenbewertung", diff --git a/www/core/components/grades/lang/el.json b/www/core/components/grades/lang/el.json index 8192b0ab2e2..26376ac35e5 100644 --- a/www/core/components/grades/lang/el.json +++ b/www/core/components/grades/lang/el.json @@ -2,7 +2,7 @@ "average": "Μέσος όρος", "badgrade": "Ο βαθμός που δόθηκε δεν είναι έγκυρος", "contributiontocoursetotal": "Συνεισφορά στον τελικό βαθμό", - "feedback": "Ανάδραση", + "feedback": "Επανατροφοδότηση", "grade": "Βαθμός", "grades": "Βαθμοί", "itemname": "Όνομα στοιχείου", diff --git a/www/core/components/grades/lang/es-mx.json b/www/core/components/grades/lang/es-mx.json index 34e8b41f166..ca04dc39133 100644 --- a/www/core/components/grades/lang/es-mx.json +++ b/www/core/components/grades/lang/es-mx.json @@ -2,7 +2,7 @@ "average": "Promedio", "badgrade": "La calificación suministrada no es válida", "contributiontocoursetotal": "Contribución al total del curso", - "feedback": "Comentario de retroalimentación", + "feedback": "Retroalimentación", "grade": "Calificación", "grades": "Calificaciones", "itemname": "Nombre del ítem", diff --git a/www/core/components/grades/lang/es.json b/www/core/components/grades/lang/es.json index 164f2dd4f66..63344ded652 100644 --- a/www/core/components/grades/lang/es.json +++ b/www/core/components/grades/lang/es.json @@ -2,7 +2,7 @@ "average": "Promedio", "badgrade": "La calificación suministrada no es válida", "contributiontocoursetotal": "Aporta al total del curso", - "feedback": "Comentario", + "feedback": "Retroalimentación", "grade": "Calificación", "grades": "Calificaciones", "itemname": "Nombre del ítem", diff --git a/www/core/components/grades/lang/es_mx.json b/www/core/components/grades/lang/es_mx.json deleted file mode 100644 index fcf81895629..00000000000 --- a/www/core/components/grades/lang/es_mx.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "average": "Promedio", - "feedback": "Retroalimentación", - "grade": "Calificación", - "grades": "Calificaciones", - "itemname": "Nombre del ítem", - "lettergrade": "Calificación por letra", - "percentage": "Porcentaje", - "range": "Rango", - "rank": "Rango", - "weight": "Peso" -} \ No newline at end of file diff --git a/www/core/components/grades/lang/eu.json b/www/core/components/grades/lang/eu.json index f71b3afe9f7..1037527dadf 100644 --- a/www/core/components/grades/lang/eu.json +++ b/www/core/components/grades/lang/eu.json @@ -3,13 +3,13 @@ "badgrade": "Emandako kalifikazioak ez du balio", "contributiontocoursetotal": "Ikastaroaren denerako ekarpena", "feedback": "Feedbacka", - "grade": "Nota", + "grade": "Kalifikazioa", "grades": "Kalifikazioak", "itemname": "Elementuaren izena", "lettergrade": "Letren bidezko kalifikazioa", "nooutcome": "Ez dago ikas-emaitzarik", "percentage": "Portzentajea", "range": "Ibiltartea", - "rank": "Bitartea", + "rank": "Sailkapena", "weight": "Pisua" } \ No newline at end of file diff --git a/www/core/components/grades/lang/he.json b/www/core/components/grades/lang/he.json index f71923977d3..2093690bad2 100644 --- a/www/core/components/grades/lang/he.json +++ b/www/core/components/grades/lang/he.json @@ -1,15 +1,15 @@ { - "average": "ממוצע", + "average": "ממוצע (בקורס)", "badgrade": "הציון שנמסר איננו נאות", "contributiontocoursetotal": "ניקוד משוקלל, כתרומה לציון הסופי", - "feedback": "תגובות", - "grade": "ציונים", + "feedback": "משוב", + "grade": "ציון", "grades": "ציונים", "itemname": "שם הפריט", "lettergrade": "ציון אות", "nooutcome": "לא קיים מדד־הערכה", "percentage": "הניקוד כאחוז מהציון המירבי בפעילות", "range": "טווח", - "rank": "דרגה", + "rank": "דרוג יחסי", "weight": "משקל" } \ No newline at end of file diff --git a/www/core/components/grades/lang/it.json b/www/core/components/grades/lang/it.json index 8991bf5655c..dc227165d43 100644 --- a/www/core/components/grades/lang/it.json +++ b/www/core/components/grades/lang/it.json @@ -2,8 +2,8 @@ "average": "Media", "badgrade": "Il voto inserito non è valido", "contributiontocoursetotal": "Quota di contribuzione sul totale del corso", - "feedback": "Commento", - "grade": "Punteggio", + "feedback": "Feedback", + "grade": "Valutazione", "grades": "Valutazioni", "itemname": "Nome elemento", "lettergrade": "Graduatoria letterale", diff --git a/www/core/components/grades/lang/ja.json b/www/core/components/grades/lang/ja.json index 2bed54f329a..bfa3698fe22 100644 --- a/www/core/components/grades/lang/ja.json +++ b/www/core/components/grades/lang/ja.json @@ -3,7 +3,7 @@ "badgrade": "提供された評定は有効ではありません。", "contributiontocoursetotal": "コース合計への貢献", "feedback": "フィードバック", - "grade": "評点", + "grade": "評定", "grades": "評定", "itemname": "項目名", "lettergrade": "評定文字", diff --git a/www/core/components/grades/lang/lt.json b/www/core/components/grades/lang/lt.json index 80eb71c8e0b..686daab9d80 100644 --- a/www/core/components/grades/lang/lt.json +++ b/www/core/components/grades/lang/lt.json @@ -2,7 +2,7 @@ "average": "Vidurkis", "badgrade": "Pateiktas netinkamas įvertis", "contributiontocoursetotal": "Indėlis į kurso bendrą", - "feedback": "Atsiliepimas", + "feedback": "Grįžtamasis ryšys", "grade": "Įvertis", "grades": "Įverčiai", "itemname": "Elemento pavadinimas", diff --git a/www/core/components/grades/lang/nl.json b/www/core/components/grades/lang/nl.json index 4a3ec60edd4..a4266d2d6f4 100644 --- a/www/core/components/grades/lang/nl.json +++ b/www/core/components/grades/lang/nl.json @@ -3,13 +3,13 @@ "badgrade": "Beoordeling ongeldig", "contributiontocoursetotal": "Aandeel in cursustotaal", "feedback": "Feedback", - "grade": "Cijfer", + "grade": "Beoordeling", "grades": "Cijfers", "itemname": "Itemnaam", "lettergrade": "Letterbeoordeling", "nooutcome": "Geen competentie", "percentage": "Percentage", "range": "Marge", - "rank": "Rangschikking", + "rank": "Ranglijst", "weight": "Weging" } \ No newline at end of file diff --git a/www/core/components/grades/lang/pl.json b/www/core/components/grades/lang/pl.json index e0e72a5b70e..44e378ae1b1 100644 --- a/www/core/components/grades/lang/pl.json +++ b/www/core/components/grades/lang/pl.json @@ -4,12 +4,12 @@ "contributiontocoursetotal": "Udział w całym kursie", "feedback": "Informacja zwrotna", "grade": "Ocena", - "grades": "Oceny", + "grades": "Stopnie", "itemname": "Nazwa pozycji", "lettergrade": "Nazwy ocen", "nooutcome": "Brak efektu kształcenia", "percentage": "Procentowo", "range": "Zakres", - "rank": "Pozycja", + "rank": "Pozycja na tle grupy", "weight": "Waga" } \ No newline at end of file diff --git a/www/core/components/grades/lang/pt-br.json b/www/core/components/grades/lang/pt-br.json index 22749a08522..d489ce5db62 100644 --- a/www/core/components/grades/lang/pt-br.json +++ b/www/core/components/grades/lang/pt-br.json @@ -2,8 +2,8 @@ "average": "Média", "badgrade": "Nota fornecida é inválida", "contributiontocoursetotal": "Contribuição para o total do curso", - "feedback": "Comentários", - "grade": "Avaliação", + "feedback": "Feedback", + "grade": "Nota", "grades": "Notas", "itemname": "Nome do Item", "lettergrade": "Notas por letras", diff --git a/www/core/components/grades/lang/pt.json b/www/core/components/grades/lang/pt.json index 3dc103cd4b6..e0d486df8e3 100644 --- a/www/core/components/grades/lang/pt.json +++ b/www/core/components/grades/lang/pt.json @@ -2,14 +2,14 @@ "average": "Média", "badgrade": "A nota fornecida é inválida", "contributiontocoursetotal": "Contribuição para o total da disciplina", - "feedback": "Comentários", - "grade": "Avaliação", - "grades": "Pauta", + "feedback": "Feedback", + "grade": "Nota", + "grades": "Notas", "itemname": "Nome do item", "lettergrade": "Nota Alfabética", "nooutcome": "Nenhum resultado da aprendizagem", "percentage": "Percentagem", "range": "Intervalo", - "rank": "Posição", + "rank": "Posição relativa", "weight": "Peso" } \ No newline at end of file diff --git a/www/core/components/grades/lang/pt_br.json b/www/core/components/grades/lang/pt_br.json deleted file mode 100644 index 13ebd263418..00000000000 --- a/www/core/components/grades/lang/pt_br.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "average": "Média", - "contributiontocoursetotal": "Contribuição ao total do curso", - "feedback": "Feedback", - "grade": "Notas", - "grades": "Notas", - "itemname": "Item de nota", - "lettergrade": "Nota letra", - "percentage": "Porcentagem", - "range": "Range", - "rank": "Posição", - "weight": "Peso" -} \ No newline at end of file diff --git a/www/core/components/grades/lang/ro.json b/www/core/components/grades/lang/ro.json index 03c1080cff7..f0ab52efac5 100644 --- a/www/core/components/grades/lang/ro.json +++ b/www/core/components/grades/lang/ro.json @@ -1,9 +1,9 @@ { - "average": "Medie", + "average": "Media", "badgrade": "Nota furnizată nu este corectă", "contributiontocoursetotal": "Contribuția la totalul cursului", "feedback": "Feedback", - "grade": "Notează", + "grade": "Notă", "grades": "Note", "itemname": "Nume element", "lettergrade": "Notă sub formă de literă", diff --git a/www/core/components/grades/lang/ru.json b/www/core/components/grades/lang/ru.json index f1f6126713c..05c8c10d084 100644 --- a/www/core/components/grades/lang/ru.json +++ b/www/core/components/grades/lang/ru.json @@ -1,5 +1,5 @@ { - "average": "Средний", + "average": "Средняя оценка", "badgrade": "Указана некорректная оценка", "contributiontocoursetotal": "Вклад в итог курса", "feedback": "Отзыв", @@ -10,6 +10,6 @@ "nooutcome": "Нет показателя", "percentage": "Проценты", "range": "Диапазон", - "rank": "Ранг", + "rank": "Место", "weight": "Вес" } \ No newline at end of file diff --git a/www/core/components/grades/lang/sr-cr.json b/www/core/components/grades/lang/sr-cr.json new file mode 100644 index 00000000000..dba951d9477 --- /dev/null +++ b/www/core/components/grades/lang/sr-cr.json @@ -0,0 +1,15 @@ +{ + "average": "Просечно", + "badgrade": "Дата оцена је неисправна", + "contributiontocoursetotal": "Допринос укупној оцени на курсу", + "feedback": "Повратне информације", + "grade": "Оцена", + "grades": "Оцене", + "itemname": "Назив ставке", + "lettergrade": "Словна оцена", + "nooutcome": "Без исхода учења", + "percentage": "Проценат", + "range": "Опсег", + "rank": "Ранг", + "weight": "Пондер" +} \ No newline at end of file diff --git a/www/core/components/grades/lang/sr-lt.json b/www/core/components/grades/lang/sr-lt.json new file mode 100644 index 00000000000..88e41afc3cb --- /dev/null +++ b/www/core/components/grades/lang/sr-lt.json @@ -0,0 +1,15 @@ +{ + "average": "Prosečno", + "badgrade": "Data ocena je neispravna", + "contributiontocoursetotal": "Doprinos ukupnoj oceni na kursu", + "feedback": "Povratne informacije", + "grade": "Ocena", + "grades": "Ocene", + "itemname": "Naziv stavke", + "lettergrade": "Slovna ocena", + "nooutcome": "Bez ishoda učenja", + "percentage": "Procenat", + "range": "Opseg", + "rank": "Rang", + "weight": "Ponder" +} \ No newline at end of file diff --git a/www/core/components/grades/lang/sv.json b/www/core/components/grades/lang/sv.json index 45d3e21b56d..7593dadca0f 100644 --- a/www/core/components/grades/lang/sv.json +++ b/www/core/components/grades/lang/sv.json @@ -1,15 +1,15 @@ { - "average": "Medel", + "average": "Medelvärde", "badgrade": "Det betyg som har avgivits är ogiltigt", "contributiontocoursetotal": "Bidrag till totalen för kursen", "feedback": "Återkoppling", - "grade": "Betyg/omdöme", - "grades": "Betyg", + "grade": "Betyg", + "grades": "Betyg/omdömen", "itemname": "Namn på komponent", "lettergrade": "Bokstavsbetyg/omdöme", "nooutcome": "Inget resultat", "percentage": "Procenttal", "range": "Omfång", - "rank": "Rangordna", + "rank": "Ranking", "weight": "vikt" } \ No newline at end of file diff --git a/www/core/components/grades/lang/tr.json b/www/core/components/grades/lang/tr.json index b50d05f02ad..a604f01f390 100644 --- a/www/core/components/grades/lang/tr.json +++ b/www/core/components/grades/lang/tr.json @@ -2,14 +2,14 @@ "average": "Ortalama", "badgrade": "Sağlanan not geçersiz", "contributiontocoursetotal": "Ders toplamına katkısı", - "feedback": "Geri bildirim", - "grade": "Not", - "grades": "Notlar", + "feedback": "Geribildirim", + "grade": "Başarı notu", + "grades": "Başarı notları", "itemname": "Öge adı", "lettergrade": "Harf notu", "nooutcome": "Hedef yok", "percentage": "Yüzde", "range": "Fark", - "rank": "Sıra", + "rank": "sıra", "weight": "Ağırlık" } \ No newline at end of file diff --git a/www/core/components/grades/lang/uk.json b/www/core/components/grades/lang/uk.json index 90a3c3ea978..ae349f2a21c 100644 --- a/www/core/components/grades/lang/uk.json +++ b/www/core/components/grades/lang/uk.json @@ -1,15 +1,15 @@ { - "average": "Середнє", + "average": "Середня оцінка", "badgrade": "Проставлена оцінка - недопустима", "contributiontocoursetotal": "Внесок у підсумок курсу", - "feedback": "Відгук", + "feedback": "Коментар", "grade": "Оцінка", - "grades": "Журнал оцінок", + "grades": "Оцінки", "itemname": "Назва елементу", "lettergrade": "Буквена оцінка", "nooutcome": "Без результату", "percentage": "Відсоток", "range": "Інтервал", - "rank": "Розташувати в порядку", + "rank": "Порядок", "weight": "значимість" } \ No newline at end of file diff --git a/www/core/components/grades/lang/zh-cn.json b/www/core/components/grades/lang/zh-cn.json index 9a3d42259f1..acd9a162913 100644 --- a/www/core/components/grades/lang/zh-cn.json +++ b/www/core/components/grades/lang/zh-cn.json @@ -1,5 +1,5 @@ { - "average": "平均", + "average": "平均值", "badgrade": "提供的成绩不可用", "contributiontocoursetotal": "对课程的总贡献", "feedback": "反馈", @@ -10,6 +10,6 @@ "nooutcome": "无成果", "percentage": "百分比", "range": "范围", - "rank": "等级", + "rank": "排名", "weight": "权重" } \ No newline at end of file diff --git a/www/core/components/grades/lang/zh-tw.json b/www/core/components/grades/lang/zh-tw.json index ad4dc4b8ff6..e108db854ad 100644 --- a/www/core/components/grades/lang/zh-tw.json +++ b/www/core/components/grades/lang/zh-tw.json @@ -1,9 +1,9 @@ { - "average": "平均數", + "average": "平均", "badgrade": "提供的成績是無效的", "contributiontocoursetotal": "貢獻到課程總分", "feedback": "回饋", - "grade": "分數", + "grade": "成績", "grades": "成績", "itemname": "項目名稱", "lettergrade": "文字等第", diff --git a/www/core/components/grades/lang/zh_cn.json b/www/core/components/grades/lang/zh_cn.json deleted file mode 100644 index 83d3c3b88be..00000000000 --- a/www/core/components/grades/lang/zh_cn.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "average": "平均", - "contributiontocoursetotal": "贡献课程总数", - "feedback": "反馈", - "grade": "成绩", - "grades": "成绩", - "itemname": "评分项", - "lettergrade": "字母评分", - "percentage": "百分比", - "range": "范围", - "rank": "排名", - "weight": "权重" -} \ No newline at end of file diff --git a/www/core/components/grades/lang/zh_tw.json b/www/core/components/grades/lang/zh_tw.json deleted file mode 100644 index bd929c3fda5..00000000000 --- a/www/core/components/grades/lang/zh_tw.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "average": "平均", - "feedback": "回饋", - "grade": "成績", - "grades": "成績", - "itemname": "成績項名稱", - "lettergrade": "文字等第", - "percentage": "百分比", - "range": "範圍", - "rank": "排名", - "weight": "加權" -} \ No newline at end of file diff --git a/www/core/components/login/controllers/credentials.js b/www/core/components/login/controllers/credentials.js index 3ab1519ac05..2e697ea05f9 100644 --- a/www/core/components/login/controllers/credentials.js +++ b/www/core/components/login/controllers/credentials.js @@ -141,6 +141,11 @@ angular.module('mm.core.login') return; } + if (!$mmApp.isOnline()) { + $mmUtil.showErrorModal('mm.core.networkerrormsg', true); + return; + } + var modal = $mmUtil.showModalLoading(); // Start the authentication process. diff --git a/www/core/components/login/controllers/emailsignup.js b/www/core/components/login/controllers/emailsignup.js index 6821a34ca54..241a0b9c3f9 100644 --- a/www/core/components/login/controllers/emailsignup.js +++ b/www/core/components/login/controllers/emailsignup.js @@ -81,6 +81,7 @@ angular.module('mm.core.login') if (settings.country && !$scope.data.country) { $scope.data.country = settings.country; } + $scope.data.recaptcharesponse = ''; // Reset captcha. $scope.namefieldsErrors = {}; angular.forEach(settings.namefields, function(field) { @@ -123,10 +124,14 @@ angular.module('mm.core.login') }; // Request another captcha. - $scope.requestCaptcha = function() { + $scope.requestCaptcha = function(ignoreError) { var modal = $mmUtil.showModalLoading(); - $scope.data.recaptcharesponse = ''; - getSignupSettings().finally(function() { + getSignupSettings().catch(function(err) { + if (!ignoreError && err) { + $mmUtil.showErrorModal(err); + } + return $q.reject(); + }).finally(function() { modal.dismiss(); }); }; @@ -181,17 +186,14 @@ angular.module('mm.core.login') } // Error sending, request another capctha since the current one is probably invalid now. - $scope.requestCaptcha(); + $scope.requestCaptcha(true); } }); }).catch(function(error) { - if (error) { - $mmUtil.showErrorModal(error); - } else { - $mmUtil.showErrorModal('mm.login.usernotaddederror', true); - } + $mmUtil.showErrorModalDefault(error && error.error, 'mm.login.usernotaddederror', true); + // Error sending, request another capctha since the current one is probably invalid now. - $scope.requestCaptcha(); + $scope.requestCaptcha(true); }).finally(function() { modal.dismiss(); }); diff --git a/www/core/components/login/controllers/reconnect.js b/www/core/components/login/controllers/reconnect.js index f79b6380be2..74c82fe63ca 100644 --- a/www/core/components/login/controllers/reconnect.js +++ b/www/core/components/login/controllers/reconnect.js @@ -84,6 +84,11 @@ angular.module('mm.core.login') return; } + if (!$mmApp.isOnline()) { + $mmUtil.showErrorModal('mm.core.networkerrormsg', true); + return; + } + var modal = $mmUtil.showModalLoading(); // Start the authentication process. diff --git a/www/core/components/login/controllers/site.js b/www/core/components/login/controllers/site.js index a08b4c1af33..88dc90e90a5 100644 --- a/www/core/components/login/controllers/site.js +++ b/www/core/components/login/controllers/site.js @@ -35,6 +35,11 @@ angular.module('mm.core.login') return; } + if (!$mmApp.isOnline()) { + $mmUtil.showErrorModal('mm.core.networkerrormsg', true); + return; + } + var modal = $mmUtil.showModalLoading(), sitedata = $mmSitesManager.getDemoSiteData(url); diff --git a/www/core/components/login/controllers/sitepolicy.js b/www/core/components/login/controllers/sitepolicy.js index d6afcecb1dc..6b3df7f091e 100644 --- a/www/core/components/login/controllers/sitepolicy.js +++ b/www/core/components/login/controllers/sitepolicy.js @@ -56,7 +56,7 @@ angular.module('mm.core.login') $scope.policyLoaded = true; }); }).catch(function(error) { - $mmUtil.showErrorModalDefault(error, 'Error getting site policy.'); + $mmUtil.showErrorModalDefault(error && error.error, 'Error getting site policy.'); cancel(); }); } diff --git a/www/core/components/login/lang/ar.json b/www/core/components/login/lang/ar.json index e58f7ef0a9d..7dcb9e22afa 100644 --- a/www/core/components/login/lang/ar.json +++ b/www/core/components/login/lang/ar.json @@ -1,6 +1,6 @@ { "authenticating": "مصادقة", - "cancel": "إلغاء", + "cancel": "ألغي", "connect": "دخول", "connecttomoodle": "بيانات الدخول", "createaccount": "إنشاء حساب مشترك الجديد", @@ -17,7 +17,7 @@ "invalidemail": "عنوان البريد الإلكتروني غير صحيح", "invalidmoodleversion": "نسخة موودل غير صالحة. الحد الأدنى للنسخة المطلوبة هو:", "invalidsite": "رابط عنوان الموقع غير صالح.", - "invalidurl": "عنوان الإنترنت غير صحيح", + "invalidurl": "عنوان الأنترنت المدخل غير صحيح", "login": "دخول", "loginbutton": "دخول", "loginsteps": "مرحبا بك! يمكنك إنشاء حساب مشترك جديد في هذا الموقع خلال لحظات والاتصال الكامل بالمقررات الدراسية وذلك بتتبع الخطوات التالية:\n\n
    \n
  1. املأ نموذج حساب جديد.
  2. \n
  3. على الفور تصلك رسالة على عنوانك البريدي.
  4. \n
  5. قم بقراءة البريد واضغط على الرابطة الموجودة به.
  6. \n
  7. سيتم تأكيد اشتراكك ويسمح لك بالدخول.
  8. \n
  9. والآن قم باختيار المقرر الدراسي الذي ترغب المشاركة فيه.
  10. \n
  11. من الآن فصاعدا يمكنك الدخول عن طريق إدخال اسم المستخدم وكلمة المرور (في النموذج المقابل بهذه الصفحة) ، وتستطيع الاتصال الكامل المقرر الدراسي ، وتصل إلى أي مقرر دراسي تريد التسجيل به.
  12. \n
  13. إذا طلب منك ''مفتاح التسجيل'' - استخدم المفتاح الذي أعطاه لك المدرس. هذا سيجعلك ''تشارك'' في المقرر الدراسي.
  14. \n
  15. لا حظ أن كل مقرر دراسي قد يكون له أيضا \"مفتاح تسجيل\" ستحتاج إليه لاحقا.
  16. \n
", diff --git a/www/core/components/login/lang/bg.json b/www/core/components/login/lang/bg.json index 42351bce95a..c21497bd5f6 100644 --- a/www/core/components/login/lang/bg.json +++ b/www/core/components/login/lang/bg.json @@ -1,7 +1,7 @@ { "authenticating": "Удостоверяване", "cancel": "Отказване", - "connect": "Свързване!", + "connect": "Свързване", "connecttomoodle": "Свързване към Moodle", "createaccount": "Създаване на моята регистрация", "createuserandpass": "Изберете Вашето име и парола", @@ -27,7 +27,7 @@ "mobileservicesnotenabled": "Услугите от Moodle не са активирани на Вашия сайт. Моля, свържете се с администратор на Moodle, ако мислите, че мобилния достъп трябва да бъде разрешен.", "newaccount": "Нова потребителска регистрация", "notloggedin": "Трябва са сте влезли в сайта.", - "password": "Ключ за записване", + "password": "Парола", "passwordrequired": "Паролата е задължителна", "policyaccept": "Разбирам и съм съгласен", "policyagree": "Трябва да се съгласите с тези условия за ползване, за да продължите да ползвате сайта. Съгласен/на ли сте?", diff --git a/www/core/components/login/lang/ca.json b/www/core/components/login/lang/ca.json index d14a659e218..30577d6307d 100644 --- a/www/core/components/login/lang/ca.json +++ b/www/core/components/login/lang/ca.json @@ -28,7 +28,7 @@ "invalidmoodleversion": "La versió de Moodle no és vàlida. Cal com a mínim la versió 2.4.", "invalidsite": "L'URL del lloc no és vàlid.", "invalidtime": "L'hora no és vàlida", - "invalidurl": "L'URL no és vàlid", + "invalidurl": "L'URL que heu introduït no és vàlid", "invalidvaluemax": "El valor màxim és {{$a}}", "invalidvaluemin": "El valor mínim és {{$a}}", "localmobileunexpectedresponse": "Les característiques addicionals de Moodle Mobile han tornat una resposta inesperada, us heu d'autenticar fent servir el servei estàndard de Mobile.", @@ -44,7 +44,7 @@ "newaccount": "Nou compte", "newsitedescription": "Introduïu l'URL del vostre lloc Moodle. Tingueu en compte que podria no estar configurat per treballar amb aquesta aplicació.", "notloggedin": "Heu d'entrar al lloc.", - "password": "Clau d'inscripció", + "password": "Contrasenya", "passwordrequired": "Contrasenya obligatòria", "policyaccept": "Entès i conforme", "policyagree": "Heu d'acceptar la normativa abans d'entrar en aquest lloc. Hi esteu d'acord?", diff --git a/www/core/components/login/lang/cs.json b/www/core/components/login/lang/cs.json index 8b4a2c704cd..e6b11b3d959 100644 --- a/www/core/components/login/lang/cs.json +++ b/www/core/components/login/lang/cs.json @@ -1,7 +1,7 @@ { "auth_email": "Registrace na základě e-mailu", "authenticating": "Autentizace", - "cancel": "Přerušit", + "cancel": "Zrušit", "checksiteversion": "Zkontrolujte, zda web používá Moodle 2.4 nebo novější.", "confirmdeletesite": "Jste si jisti, že chcete smazat web {{sitename}}?", "connect": "Připojit!", @@ -19,7 +19,7 @@ "errorupdatesite": "Došlo k chybě při aktualizaci tokenu webu.", "firsttime": "Jste tady poprvé?", "getanothercaptcha": "Získat jiné CAPTCHA", - "help": "Nápověda", + "help": "Pomoc", "helpmelogin": "

Existuje mnoho tisíc webů Moodle po celém světě. Tato aplikace může připojit pouze ke stránkám Moodle, které povolily, mobilní přístup k aplikaci.

Pokud se nemůžete k Moodle připojit, pak je třeba kontaktovat správce web Moodle, kam se chcete připojit a požádat, aby přečetl http://docs.moodle.org/en/Mobile_app

Chcete-li otestovat aplikaci na Moodle demo webu jako učitel nebo student na pole Adresa stránky a klikněte na tlačítko Připojit .

", "instructions": "Pokyny", "invalidaccount": "Zkontrolujte si prosím své přihlašovací údaje nebo se obraťte na správce webu, aby zkontroloval nastavení.", @@ -28,7 +28,7 @@ "invalidmoodleversion": "Neplatná verze Moodle. Minimální potřebná verze je:", "invalidsite": "Adresa URL stránky je chybná", "invalidtime": "Neplatný čas", - "invalidurl": "Neplatná URL", + "invalidurl": "Použité URL není platné", "invalidvaluemax": "Maximální hodnota je {{$a}}", "invalidvaluemin": "Minimální hodnota je {{$a}}", "localmobileunexpectedresponse": "Kontrola rozšířených vlastností Moodle Mobile vrátil neočekávanou odezvu, budete ověřen pomocí standardních služeb mobilu .", @@ -44,7 +44,7 @@ "newaccount": "Nový účet", "newsitedescription": "Zadejte prosím adresu URL vašeho webu Moodle. Všimněte si, že nemusí být nakonfigurován pro práci s touto aplikací.", "notloggedin": "Musíte být přihlášeni.", - "password": "Sdílené heslo", + "password": "Heslo", "passwordrequired": "Je požadováno heslo", "policyaccept": "Rozumím a souhlasím", "policyagree": "Před dalším používáním těchto stránek musíte souhlasit s těmito pravidly. Souhlasíte s nimi?", diff --git a/www/core/components/login/lang/da.json b/www/core/components/login/lang/da.json index 71bccdcbe1d..ba85230503e 100644 --- a/www/core/components/login/lang/da.json +++ b/www/core/components/login/lang/da.json @@ -2,7 +2,7 @@ "authenticating": "Godkender", "cancel": "Annuller", "confirmdeletesite": "Er du sikker på at du ønsker at slette websiden {{sitename}}?", - "connect": "Forbind", + "connect": "Tilslut!", "connecttomoodle": "Tilslut til Moodle", "createaccount": "Opret ny profil", "createuserandpass": "Vælg brugernavn og adgangskode", @@ -21,7 +21,7 @@ "invalidemail": "Ugyldig e-mailadresse", "invalidmoodleversion": "Ugyldig Moodle version. Der kræves minimum 2.4.", "invalidsite": "Denne webadresse er ugyldig.", - "invalidurl": "Ugyldig URL", + "invalidurl": "Den URL, du har skrevet, er ikke korrekt", "localmobileunexpectedresponse": "Du har fået en uventet reaktion fra Moodle Mobile Additional Features, så du vil blive godkendt ved hjælp af standard Mobile service.", "login": "Log ind", "loginbutton": "Login", @@ -34,7 +34,7 @@ "newaccount": "Ny konto", "newsitedescription": "Skriv din Moodles webadresse. Bemærk at Moodle kan være konfigureret, så den ikke virker med denne app.", "notloggedin": "Du skal være logget på.", - "password": "Delt hemmelig streng", + "password": "Adgangskode", "passwordrequired": "Adgangskode kræves", "policyaccept": "Jeg forstår og er enig", "policyagree": "Du må acceptere disse retningslinjer for at benytte dette site.\nAccepterer du?", diff --git a/www/core/components/login/lang/de.json b/www/core/components/login/lang/de.json index e88b1eeed67..ca4835372f7 100644 --- a/www/core/components/login/lang/de.json +++ b/www/core/components/login/lang/de.json @@ -2,7 +2,7 @@ "auth_email": "E-Mail-Registrierung", "authenticating": "Authentifizieren ...", "cancel": "Abbrechen", - "checksiteversion": "Prüfen Sie, ob Ihre Website mindestens Moodle 2.4 verwendet.", + "checksiteversion": "Prüfen Sie, ob die Website mindestens Moodle 2.4 verwendet.", "confirmdeletesite": "Möchten Sie '{{sitename}}' wirklich aus der Liste löschen?", "connect": "Verbinden", "connecttomoodle": "Website verbinden", @@ -20,7 +20,7 @@ "firsttime": "Sind Sie zum ersten Mal auf dieser Webseite?", "getanothercaptcha": "Neues Captcha laden", "help": "Hilfe", - "helpmelogin": "

Die Moodle Mobile App funktioniert nur mit Websites, die speziell für den mobilen Zugriff freigegeben wurden.

\n

Alle Möglichkeiten finden Sie unter http://docs.moodle.org/de/Mobile_app.

\n


Wenn Sie die App mit einer Demo-Website testen möchten, tragen Sie bitte teacher oder student in das Feld URL der Website ein. Tippen Sie dann auf die Taste Verbinden.

", + "helpmelogin": "

Es gibt viele tausend Moodle-Websites auf der Welt. Die mobile App funktioniert nur mit Websites, für die der mobile Zugriff freigegeben wurde.

\n

Alle Möglichkeiten finden Sie unter http://docs.moodle.org/de/Mobile_app.

\n


Wenn Sie die App mit einer Demo-Website testen möchten, tragen Sie bitte teacher oder student in das Feld URL der Website ein. Tippen Sie dann auf die Taste Verbinden.

", "instructions": "Anleitung", "invalidaccount": "Prüfen Sie Ihre Anmeldedaten oder wenden Sie sich an den Administrator der Website.", "invaliddate": "Ungültiges Datum", @@ -28,7 +28,7 @@ "invalidmoodleversion": "Falsche Version. Mindestens Moodle 2.4 ist notwendig.", "invalidsite": "Die URL der Website ist ungültig.", "invalidtime": "Ungültige Zeitangabe", - "invalidurl": "Ungültige URL", + "invalidurl": "Die eingegebene URL ist nicht gültig.", "invalidvaluemax": "Der Maximalwert ist {{$a}}.", "invalidvaluemin": "Der Minimalwert ist {{$a}}.", "localmobileunexpectedresponse": "Die Verbindung zum Plugin 'Moodle Mobile - Zusatzfeatures' ist fehlgeschlagen. Sie werden über den standardmäßigen mobilen Webservice authentifiziert.", diff --git a/www/core/components/login/lang/el.json b/www/core/components/login/lang/el.json index cb0a2b6fbae..171e2d567ae 100644 --- a/www/core/components/login/lang/el.json +++ b/www/core/components/login/lang/el.json @@ -1,7 +1,7 @@ { "auth_email": "Email-based αυτο-εγγραφή", "authenticating": "Έλεγχος ταυτότητας", - "cancel": "Άκυρο", + "cancel": "Ακύρωση", "checksiteversion": "Ελέγξτε ποια έκδοση Moodle χρησιμοποιεί το site, Moodle 2.4 ή μετέπειτα έκδοση.", "confirmdeletesite": "Είστε σίγουροι ότι θέλετε να διαγράψετε το site {{sitename}};", "connect": "Σύνδεση!", @@ -14,30 +14,64 @@ "emailconfirmsent": "

Ένα email έχει σταλεί στη διεύθυνση σας {{$a}}

Περιέχει εύκολες οδηγίες για να ολοκληρώσετε την εγγραφή σας.

Εάν συνεχίσετε να έχετε δυσκολίες επικοινωνήστε με το διαχειριστή του site.

", "emailnotmatch": "Οι διευθύνσεις email δεν ταιριάζουν", "enterthewordsabove": "Enter the words above", + "erroraccesscontrolalloworigin": "Η κλήση πολλαπλών προελεύσεων (Cross-Origin call) που προσπαθείτε να εκτελέσετε έχει απορριφθεί. Παρακαλώ ελέγξτε https://docs.moodle.org/dev/Moodle_Mobile_development_using_Chrome_or_Chromium", "errordeletesite": "Παρουσιάστηκε σφάλμα κατά τη διάρκεια της διαγραφής του site. Δοκιμάστε ξανά αργότερα.", "errorupdatesite": "Παρουσιάστηκε σφάλμα κατά την ενημέρωση του site token.", "firsttime": "Είναι η πρώτη σας φορά εδώ;", "getanothercaptcha": "Πάρε ένα άλλο CAPTCHA", "help": "Βοήθεια", + "helpmelogin": "

Υπάρχουν χιλιάδες Moodle ιστότοποι σε όλο τον κόσμο. Αυτή η εφαρμογή μπορεί να συνδεθεί μόνο σε ιστότοπους Moodle που έχουν ενεργοποιήσει συγκεκριμένα την πρόσβαση σε εφαρμογές για κινητά.

Εάν δεν μπορείτε να συνδεθείτε στον ιστότοπό σας Moodle, πρέπει να επικοινωνήσετε με το διαχειριστή του Moodle ιστότοπου όπου θέλετε να συνδεθείτε και ζητήστε τους να διαβάσουν http://docs.moodle.org/en/Mobile_app

Για να δοκιμάσετε την εφαρμογή σε έναν δοκιμαστικό ιστότοπο Moodle δάσκαλος ή σπουδαστής στο πεδίο Διεύθυνση ιστοτόπου και κάντε κλικ στο κουμπί < .

", "instructions": "Οδηγίες", + "invalidaccount": "Ελέγξτε τα στοιχεία σύνδεσης ή ζητήστε από τον διαχειριστή του ιστότοπού σας να ελέγξει τη διαμόρφωση του ιστότοπου.", + "invaliddate": "Η ημερομηνία δεν είναι σωστή", "invalidemail": "Εσφαλμένη διεύθυνση ηλεκτρονικού ταχυδρομείου", - "invalidurl": "Το URL που εισαγάγατε δεν είναι έγκυρο", + "invalidmoodleversion": "Μη έγκυρη έκδοση Moodle. Η ελάχιστη απαιτούμενη έκδοση είναι η 2.4.", + "invalidsite": "Η διεύθυνση ιστότοπου δεν είναι έγκυρη.", + "invalidtime": "Μη έγκυρη ώρα", + "invalidurl": "Μη έγκυρο URL", + "invalidvaluemax": "Η μεγαλύτερη τιμή είναι {{$a}}", + "invalidvaluemin": "Η μικρότερη τιμή είναι {{$a}}", + "localmobileunexpectedresponse": "Ο έλεγχος επιπρόσθετων λειτουργιών τη εφαρμοργής για κινητά Moodle επέστρεψε μια απροσδόκητη απόκριση, θα πιστοποιηθείτε χρησιμοποιώντας την τυπική υπηρεσία κινητής τηλεφωνίας.", + "loggedoutssodescription": "Πρέπει να επαληθεύσετε ξανά τον έλεγχο ταυτότητας. Θα πρέπει να συνδεθείτε στον ιστότοπο σε ένα παράθυρο του προγράμματος περιήγησης.", "login": "Είσοδος", + "loginbutton": "Σύνδεση", + "logininsiterequired": "Θα πρέπει να συνδεθείτε στον ιστότοπο σε ένα παράθυρο του προγράμματος περιήγησης.", "loginsteps": "Γεια σας,\n\nΓια να έχετε πλήρη πρόσβαση σε κάποια μαθήματα θα χρειαστεί να δημιουργήσετε ένα νέο λογαριασμό, ακολουθώντας τα παρακάτω βήματα:\n
    \n
  1. Συμπληρώστε τη φόρμα Νέου λογαριασμού με τα δεδομένα σας.\n
  2. Ένα μήνυμα ηλεκτρονικού ταχυδρομείου θα αποσταλεί στη διεύθυνσή σας.\n
  3. Διαβάστε το μήνυμα και επιλέξτε τη διεύθυνση που περιέχει.\n
  4. Μετά την επιβεβαίωση του λογαριασμού σας, θα μπορείτε να συνδεθείτε στην ηλεκτρονική τάξη.\n
  5. Αφού έχετε συνδεθεί, μπορείτε να επιλέξτε το μάθημα στο οποίο θέλετε να εγγραφείτε. Αν σας ζητηθεί ένα \"κλειδί εγγραφής\" - χρησιμοποιήστε αυτό που σας έδωσε ο διδάσκοντάς σας.\n
  6. Από εδώ και στο εξής θα έχετε τη δυνατότητα να χρησιμοποιήσετε όλες τις δραστηριότητες και τις πηγές πληροφοριών του μαθήματος.\n
", "missingemail": "Λείπει η διεύθυνση ηλεκτρονικού ταχυδρομείου", "missingfirstname": "Λείπει το όνομα", "missinglastname": "Λείπει το επώνυμο", + "mobileservicesnotenabled": "Οι υπηρεσίες κινητής τηλεφωνίας δεν είναι ενεργοποιημένες στον ιστότοπό σας. Παρακαλούμε, επικοινωνήστε με τον διαχειριστή του ιστότοπου εάν πιστεύετε ότι η πρόσβαση στο κινητό θα πρέπει να είναι ενεργοποιημένη.", "newaccount": "Νέος λογαριασμός", - "password": "Κωδικός", + "newsitedescription": "Καταχωρίστε τη διεύθυνση URL του ιστότοπού σας Moodle. Σημειώστε ότι ενδέχεται να μην έχει ρυθμιστεί να λειτουργεί με αυτήν την εφαρμογή.", + "notloggedin": "Πρέπει να συνδεθείτε", + "password": "Κωδικός πρόσβασης", + "passwordrequired": "Απαιτείται κωδικός πρόσβασης", "policyaccept": "Καταλαβαίνω και συμφωνώ", "policyagree": "Πρέπει να συμφωνήσετε σε αυτήν την πολιτική για να συνεχίσετε στο ιστοχώρο. Συμφωνείτε;", "policyagreement": "Άδεια χρήσης του ιστοχώρου", "policyagreementclick": "Πατήστε εδώ για να διαβάσετε του όρους χρήσης", "potentialidps": "Συνδεθείτε χρησιμοποιώντας το λογαριασμό σας στο:", + "problemconnectingerror": "Παρουσιάστηκαν προβλήματα σύνδεσης", + "problemconnectingerrorcontinue": "Ελέγξτε ότι έχετε εισάγει σωστά τη διεύθυνση και προσπαθήστε ξανά.", + "profileinvaliddata": "Μη έγκυρη τιμή", + "recaptchachallengeimage": "Εικόνα reCAPTCHA", + "reconnect": "Επανασύνδεση", + "reconnectdescription": "Η σύνδεση με το λογαριασμό σας δεν είναι έγκυρη ή έχει λήξει, πρέπει να επανασυνδεθείτε με τον ιστότοπο.", + "reconnectssodescription": "Η σύνδεση με το λογαριασμό σας δεν είναι έγκυρη ή έχει λήξει, πρέπει να επανασυνδεθείτε με τον ιστότοπο. Θα πρέπει να συνδεθείτε στον ιστότοπο σε ένα παράθυρο του προγράμματος περιήγησης.", "security_question": "Ερώτηση ασφαλείας", "selectacountry": "Επιλέξτε μια χώρα", + "signupplugindisabled": "{{$a}} δεν έχει ενεργοποιηθεί.", + "siteaddress": "Διεύθυνση ιστότοπου", + "siteinmaintenance": "Ο ιστότοπός σας βρίσκεται σε λειτουργία συντήρησης", + "sitepolicynotagreederror": "Η πολιτική του ιστότοπου δεν έγινε δεκτή.", + "siteurl": "URL του ιστότοπου", + "siteurlrequired": "Το URL του ιστότοπου είναι απαραίτητο, π.χ. http://www.yourmoodlesite.abc or https://www.yourmoodlesite.efg", "startsignup": "Ξεκινήστε τώρα δημιουργώντας νέο λογαριασμό!", + "stillcantconnect": "Ακόμα δεν μπορείτε να συνδεθείτε;", "supplyinfo": "Παρακαλώ, δώστε κάποιες πληροφορίες σχετικές με τον εαυτό σας", "username": "Όνομα χρήστη", - "usernotaddederror": "Ο χρήστης \"{{$a}}\" δεν προστέθηκε - άγνωστο σφάλμα" + "usernamerequired": "Το όνομα χρήστη είναι απαραίτητο", + "usernotaddederror": "Ο χρήστης \"{{$a}}\" δεν προστέθηκε - άγνωστο σφάλμα", + "visitchangepassword": "Θέλετε να επισκεφτείτε τον ιστότοπο για να αλλάξετε τον κωδικό πρόσβασης;", + "webservicesnotenabled": "Οι υπηρεσίες Web δεν είναι ενεργοποιημένες στον ιστότοπό σας. Παρακαλούμε, επικοινωνήστε με τον διαχειριστή του δικτυακού σας τόπου για το Moodle εάν πιστεύετε ότι η πρόσβαση στο κινητό θα πρέπει να είναι ενεργοποιημένη." } \ No newline at end of file diff --git a/www/core/components/login/lang/es-mx.json b/www/core/components/login/lang/es-mx.json index 6bf776afc12..9533fe383b8 100644 --- a/www/core/components/login/lang/es-mx.json +++ b/www/core/components/login/lang/es-mx.json @@ -28,7 +28,7 @@ "invalidmoodleversion": "Versión de Moodle inválida. La versión mínima requerida es 2.4", "invalidsite": "La URL del sitio es inválida.", "invalidtime": "Hora inválida", - "invalidurl": "URL no válida", + "invalidurl": "La URL introducida no es válida", "invalidvaluemax": "El valor máximo es {{$a}}", "invalidvaluemin": "El valor mínimo es {{$a}}", "localmobileunexpectedresponse": "La revisión de las características Adicionales de Moodle Mobile regresó una respuesta inesperada; Usted será autenticado usando el servicio Mobile estándar.", @@ -44,13 +44,13 @@ "newaccount": "Nueva cuenta", "newsitedescription": "Por favor escriba la uRL de su sitio Moodle. Tome nota de que este podría no estar configurado para trabajar con esta app.", "notloggedin": "Usted necesita estar ingresado.", - "password": "Secreto Compartido", + "password": "Contraseña", "passwordrequired": "Contraseña obligatoria", "policyaccept": "Entiendo y estoy de acuerdo", "policyagree": "Usted deberá estar de acuerdo con estas condiciones antes de seguir usando este sitio. ¿Está de acuerdo?", "policyagreement": "Acuerdo con las Condiciones del Sitio", "policyagreementclick": "Haga clic aquí para leer el acuerdo con las condiciones del sitio", - "potentialidps": "¿Entra (se registra) habitualmente en otro sitio antes de llegar aquí?
Elija entre las opciones de la siguiente lista para entrar en su sitio habitual:", + "potentialidps": "Ingrese usando su cuenta en:", "problemconnectingerror": "Estamos teniendo dificultades para conectarnos", "problemconnectingerrorcontinue": "Revise dos veces que Usted haya ingresado la dirección correctamente e inténtelo nuevamente.", "profileinvaliddata": "Valor inválido", diff --git a/www/core/components/login/lang/es.json b/www/core/components/login/lang/es.json index 652d4db8fef..65a96778338 100644 --- a/www/core/components/login/lang/es.json +++ b/www/core/components/login/lang/es.json @@ -28,10 +28,11 @@ "invalidmoodleversion": "Versión de Moodle inválida. La versión mínima requerida es:", "invalidsite": "La URL del sitio es inválida.", "invalidtime": "Hora incorrecta", - "invalidurl": "URL no válida", + "invalidurl": "La URL introducida no es válida", "invalidvaluemax": "El valor máximo es {{$a}}", "invalidvaluemin": "El valor mínimo es {{$a}}", "localmobileunexpectedresponse": "Las características adicionales de Moodle Mobile han devuelto una respuesta inesperada, debe autenticarse utilizando el servicio estándar de Mobile.", + "loggedoutssodescription": "Tiene que autenticarse nuevamente. Necesita acceder al sitio en una ventana del navegador.", "login": "Acceder", "loginbutton": "Acceder", "logininsiterequired": "Para autentificarse en el sitio se ha de abrir una ventana de navegador.", @@ -43,7 +44,7 @@ "newaccount": "Nueva cuenta", "newsitedescription": "Introduzca la URL de su sitio Moodle. Tenga en cuenta que podría no estar configurado para trabajar con esta aplicación.", "notloggedin": "Ha de entrar al sitio.", - "password": "Clave de matriculación", + "password": "Contraseña", "passwordrequired": "Contraseña obligatoria", "policyaccept": "Entiendo y estoy de acuerdo", "policyagree": "Usted deberá estar de acuerdo con estas condiciones antes de seguir usando este sitio. ¿Está de acuerdo?", @@ -62,6 +63,7 @@ "signupplugindisabled": "{{$a}} no está habilitado", "siteaddress": "Dirección del sitio", "siteinmaintenance": "Su sitio está en modo mantenimiento", + "sitepolicynotagreederror": "No se aceptó la política del sitio.", "siteurl": "URL del sitio", "siteurlrequired": "La URL del sitio es obligatoria, por ejemplo http://www.yourmoodlesite.es o https://www.yourmoodlesite.org", "startsignup": "Crear nueva cuenta", diff --git a/www/core/components/login/lang/es_mx.json b/www/core/components/login/lang/es_mx.json deleted file mode 100644 index 2b074964071..00000000000 --- a/www/core/components/login/lang/es_mx.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "authenticating": "Autenticando", - "cancel": "Cancelar", - "connect": "Conectar", - "help": "Ayuda", - "helpmelogin": "

Existen varios miles de sitios Moodle en el mundo. Esta App solamente puede conectarse a sitios Moodle que hayan habilitado específicamente el acceso por Mobile App.

Si Usted no puede conectarse a su sitio Moodle, entonces Usted necesita contactar a un administrador de Moodle en el lugar en donde Usted quiere conectarse y pedirle que lea http://docs.moodle.org/en/Mobile_app

Para probar la App en un sitio Demo de Moodle escriba teacher o student en el campo de URL del sitio botón para Añadir.

", - "invalidaccount": "Por favor, verifique sus datos de acceso, o consulte con el administrador para revisar la configuración del sitio.", - "invalidmoodleversion": "Versión de Moodle inválida. La versión mínima requerida es:", - "invalidsite": "La URL del sitio es inválida.", - "login": "Ingresar", - "logininsiterequired": "Usted necesita ingresar al sitio con una ventana del navegador.", - "mobileservicesnotenabled": "Los servicios móviles no están habilitados en su sitio. Por favor, contacte a su administrador del sitio Moodle si Usted piensa que se debería habilitar el acceso por dispositivos móviles.", - "password": "Contraseña", - "passwordrequired": "Contraseña obligatoria", - "siteinmaintenance": "Su sitio está en modo de mantenimiento", - "siteurl": "URL del sitio", - "siteurlrequired": "La URL del sitio es obligatoria, por ejemplo http://www.yourmoodlesite.es o https://www.yourmoodlesite.org", - "username": "Nombre de usuario", - "usernamerequired": "Nombre de usuario obligatorio", - "webservicesnotenabled": "Los servicios web no están habilitados en su sitio. Por favor, contacte a su administrador del sitio Moodle si Usted piensa que se debería habilitar el acceso por dispositivos móviles." -} \ No newline at end of file diff --git a/www/core/components/login/lang/eu.json b/www/core/components/login/lang/eu.json index 61b1d730666..c2a9af12681 100644 --- a/www/core/components/login/lang/eu.json +++ b/www/core/components/login/lang/eu.json @@ -28,7 +28,7 @@ "invalidmoodleversion": "Moodle bertsio baliogabea. Gutxieneko bertsioa hurrengoa da:", "invalidsite": "Guneko URLa ez da zuzena", "invalidtime": "Ordu baliogabea", - "invalidurl": "URL baliogabea", + "invalidurl": "Sartu duzun URL-a ez da onargarria", "invalidvaluemax": "Gehieneko balioa {{$a}} da.", "invalidvaluemin": "Gutxieneko balioa {{$a}} da.", "localmobileunexpectedresponse": "Moodle Mobile-ko Funtzio Aurreratuen kontrolak ezusteko erantzuna eman du, Mobile zerbitzu estandarra erabilita autentifikatuko zaitugu.", @@ -44,7 +44,7 @@ "newaccount": "Kontu berria", "newsitedescription": "Sartu mesedez zure Moodle guneko URLa. Kontuan hartu app honekin funtzionatzeko gunea aurretik konfiguraturik egon behar dela.", "notloggedin": "Autentifikaturik egon behar duzu.", - "password": "Partekatutako sekretua", + "password": "Pasahitza", "passwordrequired": "Pasahitza behar da", "policyaccept": "Ulertu dut eta ados nago", "policyagree": "Web gune honetan jarraitu aurretik baldintzekin ados egon behar duzu. Ados al zaude?", diff --git a/www/core/components/login/lang/fa.json b/www/core/components/login/lang/fa.json index 742e9639285..e5cd574fd10 100644 --- a/www/core/components/login/lang/fa.json +++ b/www/core/components/login/lang/fa.json @@ -17,7 +17,7 @@ "invalidemail": "آدرس پست الکترونیک نامعتبر", "invalidmoodleversion": "این نسخه از برنامه سایت قابلیت اتصال به موبایل ندارد", "invalidsite": "نشانی سایت معتبر نیست", - "invalidurl": "آدرس نامعتبر", + "invalidurl": "آدرسی که وارد کرده‌اید معتبر نیست", "login": "ورود به سایت", "logininsiterequired": "لازم است به سایت از طریق مرورگر متصل گردید", "loginsteps": "برای داشتن دسترسی کامل به این سایت، پیش از هر چیز باید یک حساب کاربری بسازید.", diff --git a/www/core/components/login/lang/fr.json b/www/core/components/login/lang/fr.json index 091525791f0..c13712a0f07 100644 --- a/www/core/components/login/lang/fr.json +++ b/www/core/components/login/lang/fr.json @@ -28,7 +28,7 @@ "invalidmoodleversion": "Version de Moodle non valide. La version minimale requise est :", "invalidsite": "Cette URL n'est pas valide.", "invalidtime": "Temps non valide", - "invalidurl": "URL non valide", + "invalidurl": "L'URL que vous venez de saisir n'est pas valide", "invalidvaluemax": "La valeur maximale est {{$a}}", "invalidvaluemin": "La valeur minimale est {{$a}}", "localmobileunexpectedresponse": "La vérification des fonctionnalités additionnelles de Moodle Mobile a envoyé une réponse inattendue. Vous allez être connecté au moyen du service mobile standard.", @@ -44,7 +44,7 @@ "newaccount": "Nouveau compte", "newsitedescription": "Veuillez saisir l'URL de votre plateforme Moodle.", "notloggedin": "Vous devez être connecté.", - "password": "Secret partagé", + "password": "Mot de passe", "passwordrequired": "Mot de passe requis", "policyaccept": "Je comprends et je me déclare d'accord", "policyagree": "Vous devez accepter de vous conformer à ce règlement pour continuer à utiliser ce site. Acceptez-vous le règlement ?", diff --git a/www/core/components/login/lang/he.json b/www/core/components/login/lang/he.json index 08820ee166c..2c5cbdf946a 100644 --- a/www/core/components/login/lang/he.json +++ b/www/core/components/login/lang/he.json @@ -2,7 +2,7 @@ "authenticating": "מאמת נתונים", "cancel": "ביטול", "confirmdeletesite": "האם את/ה בטוח/ה שברצונך למחוק את האתר {{sitename}}?", - "connect": "חיבור", + "connect": "התחברות!", "connecttomoodle": "התחברות למוודל", "createaccount": "יצירת חשבון חדש", "createuserandpass": "הזנת שם־משתמש וסיסמה", @@ -20,7 +20,7 @@ "invalidemail": "כתובת דואר אלקטרוני לא תקפה", "invalidmoodleversion": "גרסת מוודל לא תקינה. נדרשת גרסה 2.4 ומעלה.", "invalidsite": "כתובת האתר אינה תקינה.", - "invalidurl": "URL לא חוקי", + "invalidurl": "כתובת ה-URL (אינטרנט) שהזנת כרגע לא תקפה.", "login": "התחברות", "loginbutton": "כניסה!", "logininsiterequired": "עליך להתחבר לאתר בחלון דפדפן.", @@ -32,7 +32,7 @@ "newaccount": "חשבון חדש", "newsitedescription": "יש להזין את כתובת אתר המוודל שלך. יש לשים לב כי יתכן והאתר אינו מוגדר לעבוד עם יישומון זו.", "notloggedin": "עליך להיות מחובר/ת", - "password": "סיסמה (secret)", + "password": "סיסמה", "passwordrequired": "דרושה סיסמה", "policyaccept": "אני מבין ומסכים", "policyagree": "הינך חייב לאשר את מדיניות זו על מנת להמשיך להשתמש באתר זה. האם אתה מסכים?", diff --git a/www/core/components/login/lang/hu.json b/www/core/components/login/lang/hu.json index c5c7c062990..03351032c9f 100644 --- a/www/core/components/login/lang/hu.json +++ b/www/core/components/login/lang/hu.json @@ -1,6 +1,6 @@ { "authenticating": "Hitelesítés", - "cancel": "Mégse", + "cancel": "Törlés", "connect": "Kapcsolódás", "createaccount": "Új felhasználói azonosítóm létrehozása", "createuserandpass": "Új felhasználónév és jelszó megadása", @@ -15,7 +15,7 @@ "invalidemail": "Érvénytelen e-mail cím", "invalidmoodleversion": "Érvénytelen Moodle-verzió. A minimális verziószám a 2.4.", "invalidsite": "A portál-URL nem érvényes.", - "invalidurl": "Érvénytelen URL", + "invalidurl": "A megadott URL nem érvényes", "login": "Belépés", "logininsiterequired": "A portálra böngészőablakban kell bejelentkeznie.", "loginsteps": "Ahhoz, hogy teljesen hozzáférjen a portálhoz, először új fiókot kell létrehoznia.", @@ -24,7 +24,7 @@ "missinglastname": "Hiányzó vezetéknév", "mobileservicesnotenabled": "Portálján a mobil szolgáltatások nincsenek engedélyezve. A mobil elérhetőség bekapcsolásához forduljon a rendszergazdához.", "newaccount": "Új fiók", - "password": "Megosztott titkos jel", + "password": "Jelszó", "passwordrequired": "Jelszó szükséges", "policyaccept": "Megértettem és elfogadom", "policyagree": "A portál használatához el kell fogadnia a feltételeket. Elfogadja őket?", diff --git a/www/core/components/login/lang/it.json b/www/core/components/login/lang/it.json index 7cec597a221..bc68e3db17c 100644 --- a/www/core/components/login/lang/it.json +++ b/www/core/components/login/lang/it.json @@ -21,7 +21,7 @@ "invalidemail": "Indirizzo email non valido", "invalidmoodleversion": "Versione di Moodle non valida. La versione minima richiesta:", "invalidsite": "L'URL del sito non è valida", - "invalidurl": "L'URL non è valido", + "invalidurl": "L'URL inserito non è valido", "localmobileunexpectedresponse": "Il controllo delle Moodle Mobile Additional Feature ha restituito una risposta inattesa, sarai autenticato tramite i servizi Mobile standard.", "login": "Login", "loginbutton": "Login!", diff --git a/www/core/components/login/lang/ja.json b/www/core/components/login/lang/ja.json index 6b0b86428d5..33dced4b80e 100644 --- a/www/core/components/login/lang/ja.json +++ b/www/core/components/login/lang/ja.json @@ -15,8 +15,9 @@ "invalidemail": "無効なメールアドレスです。", "invalidmoodleversion": "Moodleのバージョンが古すぎます。少なくともこれより新しいMoodleである必要があります:", "invalidsite": "サイトURLが正しくありません。", - "invalidurl": "無効なURLです。", + "invalidurl": "あなたが入力したURLは正しくありません。", "login": "ログイン", + "loginbutton": "ログイン", "logininsiterequired": "ブラウザウインドウからサイトにログインする必要があります。", "loginsteps": "このサイトにフルアクセスするため、あなたは最初にアカウントを作成する必要があります。", "missingemail": "メールアドレスが入力されていません。", @@ -24,7 +25,7 @@ "missinglastname": "姓が入力されていません。", "mobileservicesnotenabled": "あなたのサイトではモバイルサービスが有効になっていません。モバイルアクセスが必要と思うなら、あなたのMoodleサイト管理者にその相談をしてください。", "newaccount": "新しいアカウント", - "password": "共有秘密鍵", + "password": "パスワード", "passwordrequired": "パスワードがありません", "policyaccept": "私は内容を理解および同意します。", "policyagree": "このサイトを継続して利用するにはあなたは使用許諾に同意する必要があります。同意しますか?", diff --git a/www/core/components/login/lang/lt.json b/www/core/components/login/lang/lt.json index f5e96ef8b35..f1c04c57d49 100644 --- a/www/core/components/login/lang/lt.json +++ b/www/core/components/login/lang/lt.json @@ -19,7 +19,7 @@ "errorupdatesite": "Klaida atnaujinant svetainės kodą.", "firsttime": "Ar jūs čia pirmą kartą?", "getanothercaptcha": "Gauti kitą CAPTCHA", - "help": "Žinynas", + "help": "Pagalba", "helpmelogin": "

Visame pasaulyje Moodle svetainių yra labai daug. Ši programėlė gali prisijungti prie Moodle svetainių, turinčių specialią Moodle programėlių prieigą.

Jeigu negalite prisijungti, praneškite apie tai Moodle administratoriui ir paprašykite perskaityti http://docs.moodle.org/en/Mobile_app

Norėdami išbandyti programėlės demo versiją surinkite teacher (dėstytojui) ar student (besimokančiajam) Svetainės adreso lauke ir paspauskite Prisijungti mygtuką.

", "instructions": "Instrukcijos", "invalidaccount": "Prašome patikrinti prisijungimo duomenis arba paprašyti administratoriaus patikrinti svetainės nustatymus.", @@ -28,14 +28,14 @@ "invalidmoodleversion": "Negaliojanti Moodle versija. Turi būt ne senesnė nei 2.4.", "invalidsite": "URL adresas netinkamas.", "invalidtime": "Netinkamas laikas", - "invalidurl": "Klaidingas URL", + "invalidurl": "Jūsų ką tik įvestas URL yra neleistinas", "invalidvaluemax": "Didžiausia vertė {{$a}}", "invalidvaluemin": "Mažiausia vertė {{$a}}", "localmobileunexpectedresponse": "Moodle Mobilių Papildomų Funkcijų patikra gavo netikėtą atsakymą, būsite autentifikuojamas naudojant standartines mobilias paslaugas.", "login": "Prisijungti", "loginbutton": "Prisijungti", "logininsiterequired": "Prisijunkite prie svetainės naršyklės lange.", - "loginsteps": "Sveiki! Jei norite gauti visą prieigą prie kursų, turite šioje svetainėje sukurti savo paskyrą. Kiekvieni kursai taip pat gali turėti vienkartinius registracijos raktus, kurių reikės vėliau. Reikia atlikti tokius veiksmus:
  1. Užpildykite naujos paskyros formą, pateikdami savo informaciją.
  2. Jūsų el. pašto adresu bus iš karto išsiųstas el. laiškas.
  3. \n
  4. Perskaitykite el. laišką ir spustelėkite jame esantį saitą.
  5. \n
  6. Jūsų paskyra bus patvirtinta ir galėsite prisijungti.
  7. \n
  8. Tada pasirinkite kursus, kuriuose norite dalyvauti.
  9. \n
  10. Jei jūsų paprašys registracijos rakto, naudokite gautą iš dėstytojo. Taip įsiregistruosite į kursus.
  11. Dabar galėsite pasiekti visą kursų informacija. Nuo šiol jums tereikės įvesti asmeninį naudotojo vardą ir slaptažodį (šio puslapio formoje), kad prisijungtumėte ir pasiektumėte visus kursus, kuriuose įsiregistravote.
", + "loginsteps": "Jei norite gauti visą prieigą prie svetainės, turite pirmiausiai sukurti savo paskyrą.", "missingemail": "Nėra el. pašto adreso", "missingfirstname": "Nėra pavadinimo", "missinglastname": "Nėra pavardės", @@ -43,7 +43,7 @@ "newaccount": "Nauja paskyra", "newsitedescription": "Įveskite Moodle svetainės URL adresą. Atkreipkite dėmesį, kad gali būti nesukonfigūruotas dirbti su šia programėle.", "notloggedin": "Turite prisijungti", - "password": "Bendra paslaptis", + "password": "Slaptažodis", "passwordrequired": "Reikalingas slaptažodis", "policyaccept": "Suprantu ir sutinku", "policyagree": "Norėdami toliau naudotis šia svetaine, turite sutikti su šia strategija. Ar sutinkate?", diff --git a/www/core/components/login/lang/nl.json b/www/core/components/login/lang/nl.json index c0cf35dece7..d8dae79b1fe 100644 --- a/www/core/components/login/lang/nl.json +++ b/www/core/components/login/lang/nl.json @@ -28,7 +28,7 @@ "invalidmoodleversion": "Ongeldige Moodleversie. De vereiste minimumversie is:", "invalidsite": "Deze site-URL is niet geldig.", "invalidtime": "Ongeldige tijd", - "invalidurl": "Ongeldige url", + "invalidurl": "De URL die je net gaf is niet geldig", "invalidvaluemax": "De maximum waarde is {{$a}}", "invalidvaluemin": "De minimum waard eis {{$a}}", "localmobileunexpectedresponse": "Moodle Mobile Additional Features Check gaf een onverwacht antwoord. Je zult aanmelden via de standaard Mobile service.", @@ -44,7 +44,7 @@ "newaccount": "Nieuwe account", "newsitedescription": "Geef de URL van je Moodle site. Merk op dat die misschien niet geconfigureerd is om met deze app te werken.", "notloggedin": "Je moet ingelogd zijn.", - "password": "Gedeeld geheim", + "password": "Wachtwoord", "passwordrequired": "Wachtwoord vereist", "policyaccept": "Ik begrijp het en ga akkoord", "policyagree": "Je moet akkoord gaan met deze overeenkomst voor je verder kunt gaan met het gebruiken van deze site. Ga je akkoord?", diff --git a/www/core/components/login/lang/pl.json b/www/core/components/login/lang/pl.json index b4472737bff..3fbd9ef1040 100644 --- a/www/core/components/login/lang/pl.json +++ b/www/core/components/login/lang/pl.json @@ -15,7 +15,7 @@ "invalidemail": "Niewłaściwy adres e-mail", "invalidmoodleversion": "Nieprawidłowa wersja Moodle. Minimalna wymagana wersja to: ", "invalidsite": "Adres strony jest nieprawidłowy.", - "invalidurl": "Niepoprawny URL", + "invalidurl": "URL właśnie wprowadzony nie jest poprawny", "login": "Zaloguj się", "logininsiterequired": "Musisz się zalogować do strony w oknie przeglądarki.", "loginsteps": "Aby otrzymać pełny dostęp do kursów w tym serwisie, musisz najpierw utworzyć konto.", @@ -24,7 +24,7 @@ "missinglastname": "Pominięto nazwisko", "mobileservicesnotenabled": "Usługi mobile nie są włączone na twojej stronie.Skontaktuj się z administratorem strony Moodle jeżeli uważasz, że dostęp mobilny powinien być włączony.", "newaccount": "Nowe konto", - "password": "Wspólne tajne hasło", + "password": "Hasło", "passwordrequired": "Hasło wymagane", "policyaccept": "Rozumiem i zgadzam się", "policyagree": "Musisz zaakceptować te zasady, żeby używać strony. Czy zgadzasz się?", diff --git a/www/core/components/login/lang/pt-br.json b/www/core/components/login/lang/pt-br.json index e46b244e75a..5433d7bf34f 100644 --- a/www/core/components/login/lang/pt-br.json +++ b/www/core/components/login/lang/pt-br.json @@ -28,7 +28,7 @@ "invalidmoodleversion": "Versão do Moodle inválida. A versão mínima requerida é:", "invalidsite": "A URL do siteé inválida.", "invalidtime": "Tempo inválido", - "invalidurl": "Url inválida", + "invalidurl": "A URL inserida não é válida", "invalidvaluemax": "O valor máximo é {{$a}}", "invalidvaluemin": "O valor minimo é{{$a}}", "localmobileunexpectedresponse": "Verificação do Moodle Mobile Additional Features retornou uma resposta inesperada, você ira se autenticar usando o serviço Mobile padrão", @@ -44,7 +44,7 @@ "newaccount": "Cadastramento de novo usuário", "newsitedescription": "Por favor, digite a URL do seu site Moodle. Note que, pode ser que ele não esteja configurado para trabalhar com este app.", "notloggedin": "Você precisa estar logado.", - "password": "Segredo compartilhado", + "password": "Senha", "passwordrequired": "Senha necessária", "policyaccept": "Eu compreendo e concordo", "policyagree": "Para utilizar este site você precisa aceitar o acordo sobre a política de uso do site. Você aceita os termos deste acordo?", diff --git a/www/core/components/login/lang/pt.json b/www/core/components/login/lang/pt.json index 80424147ec3..e7d8c53e078 100644 --- a/www/core/components/login/lang/pt.json +++ b/www/core/components/login/lang/pt.json @@ -28,7 +28,7 @@ "invalidmoodleversion": "A versão do Moodle é inválida. É necessária a versão 2.4 ou superior.", "invalidsite": "O URL do site é inválido.", "invalidtime": "Hora inválida", - "invalidurl": "URL inválido", + "invalidurl": "O URL que introduziu não é válido", "invalidvaluemax": "O valor máximo é {{$a}}", "invalidvaluemin": "O valor mínimo é {{$a}}", "localmobileunexpectedresponse": "A verificação do Moodle Mobile Additional Features teve um erro inesperado, a ligação será feita através do serviço Mobile padrão.", @@ -44,7 +44,7 @@ "newaccount": "Nova conta", "newsitedescription": "Por favor, digite o URL do seu site Moodle. Note que o mesmo poderá não estar configurado para funcionar nesta aplicação.", "notloggedin": "Precisa de estar autenticado.", - "password": "Senha partilhada", + "password": "Senha", "passwordrequired": "Senha necessária", "policyaccept": "Compreendo e concordo", "policyagree": "Deverá aceitar este regulamento para poder proceder a utilizar este site. Aceita o regulamento?", @@ -69,7 +69,7 @@ "startsignup": "Criar nova conta", "stillcantconnect": "Continua com problemas na ligação?", "supplyinfo": "Insira alguma informação sobre si", - "username": "Nome de utilizador", + "username": "Utilizador", "usernamerequired": "É necessário o nome de utilizador", "usernotaddederror": "Utilizador não adicionado - erro.", "visitchangepassword": "Pretende visitar o site para alterar a senha?", diff --git a/www/core/components/login/lang/pt_br.json b/www/core/components/login/lang/pt_br.json deleted file mode 100644 index 0ea1899f488..00000000000 --- a/www/core/components/login/lang/pt_br.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "authenticating": "Autenticação", - "cancel": "Cancelar", - "connect": "Conectar", - "help": "Ajuda", - "helpmelogin": "

Existem milhares de sites usando Moodle no mundo. Este aplicativo somente pode conectar com um Moodle se este foi especialmente configurado para permitir o acesso móvel.

\nSe não conseguir se conectar com o seu Moodle, vai precisar entrar em contato com a administradora do seu Moodle e pedir ela acessar http://docs.moodle.org/en/Mobile_app

\n

Para testar o aplicativo em um site Moodle demo, digite teacher ou estudent no campo Usuário e clique no botão Adicionar.

", - "invalidaccount": "Por favor, verifique os detalhes de seu Usuário ou peça ao administrador do site para verificar a configuração do site.", - "invalidmoodleversion": "Versão do Moodle inválida. A versão mínima requerida é:", - "invalidsite": "A URL do siteé inválida.", - "login": "Acessar", - "logininsiterequired": "É preciso logar no site num navegador.", - "mobileservicesnotenabled": "Os serviços móveis não estão habilitados no seu Moodle. Por favor contate a administradora do seu Moodle se achar que o acesso móvel deveria estar habilitado", - "password": "Senha", - "passwordrequired": "Senha necessária", - "siteinmaintenance": "O site está em modo de manutenção", - "siteurl": "URL do site", - "siteurlrequired": "URL do site é obrigatória, por exemplo http://www.yourmoodlesite.abc ou https://www.yourmoodlesite.efg", - "username": "Nome de Usuário", - "usernamerequired": "Nome de usuário exigido", - "webservicesnotenabled": "Web Services não estão ativados em seu site. Por favor, contate a administradora do seu Moodle se você achar que o acesso móvel deve ser ativado." -} \ No newline at end of file diff --git a/www/core/components/login/lang/ro.json b/www/core/components/login/lang/ro.json index 7eac7e64d7d..3ee06d65b14 100644 --- a/www/core/components/login/lang/ro.json +++ b/www/core/components/login/lang/ro.json @@ -2,7 +2,7 @@ "authenticating": "Autentificare", "cancel": "Anulează", "confirmdeletesite": "Sunteți sigur că doriți sa ștergeți siteul {{sitename}}?", - "connect": "Conectare!", + "connect": "Conectează", "connecttomoodle": "Conectare la Moodle", "createaccount": "Creează noul meu cont", "createuserandpass": "Alege un nume de utilizator şi o parolă", @@ -21,7 +21,7 @@ "invalidemail": "Adresă de email incorectă", "invalidmoodleversion": "Versiunea Moodle este invalidă. Versiunea minimă este 2.4", "invalidsite": "Adresa URL este invalidă.", - "invalidurl": "URL incorect", + "invalidurl": "URL-ul pe care l-aţi introdus nu este corect", "localmobileunexpectedresponse": "Verificarea Moodle Mobile Additional Features a returnat un răspuns neașteptat. veți fi autentificat folosind serviciul standard.", "login": "Autentificare", "loginbutton": "Logat!", @@ -34,7 +34,7 @@ "newaccount": "Cont nou", "newsitedescription": "Introduceți adresa URL a siteului dumneavoastră, dar există posibilitatea ca acesta să nu fie configurat pentru a funcționa cu această aplicație.", "notloggedin": "Trebuie să fiți logat.", - "password": "Cheie înscriere", + "password": "Parolă", "passwordrequired": "Este necesară introducerea parolei", "policyaccept": "Înţeleg şi sunt de acord", "policyagree": "Pentru a continua să folosiţi acest site, trebuie să fiţi de acord cu termenii de utilizare specificaţi. Sunteţi de acord?", @@ -52,7 +52,7 @@ "siteurlrequired": "Este necesară adresa URL a siteului, de exemplu http://www.yourmoodlesite.abc sau https://www.yourmoodlesite.efg", "startsignup": "Creează cont", "supplyinfo": "Detalii suplimentare", - "username": "Utilizator", + "username": "Nume de utilizator", "usernamerequired": "Este necesar numele de utilizator", "usernotaddederror": "Utilizatorul nu a fost adăugat - eroare", "webservicesnotenabled": "Serviciul Web nu este activat pe siteul dumneavoastră. Va rugăm să contactați administratorul siteului dumneavoastră dacă considerați ca ar trebui activat accesul pentru mobil." diff --git a/www/core/components/login/lang/ru.json b/www/core/components/login/lang/ru.json index cb180bd40f9..549581702a7 100644 --- a/www/core/components/login/lang/ru.json +++ b/www/core/components/login/lang/ru.json @@ -1,6 +1,6 @@ { "authenticating": "Аутентификация", - "cancel": "Отмена", + "cancel": "Отменить", "confirmdeletesite": "Вы уверены, что хотите удалить сайт {{sitename}}?", "connect": "Подключено!", "connecttomoodle": "Подключение к Moodle", @@ -14,14 +14,14 @@ "errorupdatesite": "При обновлении ключа сайта произошла ошибка.", "firsttime": "Вы в первый раз на нашем сайте?", "getanothercaptcha": "Получить другой CAPTCHA (тест для различения людей и компьютеров)", - "help": "Справка", + "help": "Помощь", "helpmelogin": "

Во всем мире есть тысячи сайтов Moodle. Это приложение может подключаться только к тем сайтам Moodle, на которых разрешен доступ конкретному виду мобильного приложения.

Если Вы не можете подключиться к сайту Moodle, то необходимо связаться с администратором сайта, к которому Вы хотите подключиться, и попросить его прочитать http://docs.moodle.org/en/Mobile_app

Чтобы проверить приложение на демо-сайте Moodle, выберите учитель или студент,введите URL-адрес сайта в соответствующее поле и нажмите кнопку «Добавить».

", "instructions": "Инструкции", "invalidaccount": "Пожалуйста, проверьте свои регистрационные данные или обратитесь к администратору сайта, чтобы он проверил настройки сайта.", "invalidemail": "Некорректный формат адреса электронной почты", "invalidmoodleversion": "Неверная версия Moodle. Минимальная требуемая версия - 2.4.", "invalidsite": "URL-адрес сайта недействителен.", - "invalidurl": "Некорректный URL", + "invalidurl": "Вы указали некорректный адрес", "login": "Вход", "loginbutton": "Вход!", "logininsiterequired": "Вы должны войти на сайт в окне браузера.", @@ -33,7 +33,7 @@ "newaccount": "Новая учетная запись", "newsitedescription": "Пожалуйста, введите URL-адрес своего сайта Moodle. Учтите, что он может быть не настроен для работы с этим приложением.", "notloggedin": "Вы должны быть идентифицированы.", - "password": "Общий секретный ключ", + "password": "Пароль", "passwordrequired": "Требуется пароль", "policyaccept": "Я понял(а) и согласен(на)", "policyagree": "Чтобы продолжить работу с этим сайтом, Вы должны принять Пользовательское соглашение. Вы согласны?", diff --git a/www/core/components/login/lang/sr-cr.json b/www/core/components/login/lang/sr-cr.json new file mode 100644 index 00000000000..8cb06921b18 --- /dev/null +++ b/www/core/components/login/lang/sr-cr.json @@ -0,0 +1,77 @@ +{ + "auth_email": "Самостална регистрација на основу е-адресе", + "authenticating": "Провера идентитета", + "cancel": "Одустани", + "checksiteversion": "Проверите да ли ваш сајт користи Moodle 2.4 или новију верзију.", + "confirmdeletesite": "Да ли сте сигурни да желите да обришете сајт {{sitename}}?", + "connect": "Повежите се!", + "connecttomoodle": "Повежите се са Moodleom", + "contactyouradministrator": "Обратите се администратору вашег сајта за даљу помоћ.", + "contactyouradministratorissue": "Замолите администратора да провери следећи проблем: {{$a}}", + "createaccount": "Креирај мој нови кориснички налог", + "createuserandpass": "Изаберите своје корисничко име и лозинку за приступ систему", + "credentialsdescription": "За пријаву на систем унесите своје корисничко име и лозинку.", + "emailconfirmsent": "

Требало би да је послата порука на вашу е-адресу {{$a}}

Порука садржи једноставна упутства о даљем поступку регистрације.

Ако и даље имате проблема, обратите се администратору сајта.

", + "emailnotmatch": "Адресе е-поште се не поклапају", + "enterthewordsabove": "Унесите реч изнад", + "erroraccesscontrolalloworigin": "Cross-Origin позив који покушавате да изведете је одбијен. Молимо, проверите https://docs.moodle.org/dev/Moodle_Mobile_development_using_Chrome_or_Chromium", + "errordeletesite": "Дошло је до грешке приликом брисања овог сајта. Молим, покушајте поново.", + "errorupdatesite": "Дошло је до грешке приликом ажурирању токена сајта.", + "firsttime": "Да ли сте овде први пут?", + "getanothercaptcha": "Преузмите други CAPTCHА", + "help": "Помоћ", + "helpmelogin": "

Широм света постоји више хиљада Moodle сајтова. Ова апликација може се повезати само са Moodle сајтовима који су наменски омогућили приступ апликацијама за мобилне уређаје.

Ако не можете да се повежете са вашим Moodle сајтом потребно је да се обратите Moodle администратору сајта са којим желите да се повежете и да га замолите да прочитаhttp://docs.moodle.org/en/Mobile_app

За тестирање апликације на Moodle демо сајту унесите teacher или student у поље Адреса сајта и кликните на дугме Повежи се!.

", + "instructions": "Упутства", + "invalidaccount": "Проверите своје податке за пријаву или замолите вашег администратора да провери конфигурацију сајта.", + "invaliddate": "Неисправан датум", + "invalidemail": "Неисправна адреса електронске поште", + "invalidmoodleversion": "Неисправна Moodle верзија. Неопходна је, минимално, верзија 2.4.", + "invalidsite": "URL адреса сајт није исправна.", + "invalidtime": "Неисправно време", + "invalidurl": "Неисправан url", + "invalidvaluemax": "Максимална вредност је {{$a}}", + "invalidvaluemin": "Минимална вредност је {{$a}}", + "localmobileunexpectedresponse": "Провера Moodle Mobile додатних функционалности вратила је неочекиван одговор. Ваш идентитет биће проверен помоћу стандардног мобилнog сервиса.", + "loggedoutssodescription": "Морате поново да потврдите свој идентитет. Потребно је да се пријавите на сајт у прозору веб читача.", + "login": "Пријава", + "loginbutton": "Пријава", + "logininsiterequired": "Потребно је да се пријавите на сајт у прозору веб читача.", + "loginsteps": "Како бисте имали пуни приступ овом сајту морате креирати кориснички налог.", + "missingemail": "Недостаје адреса е-поште", + "missingfirstname": "Недостаје име", + "missinglastname": "Недостаје презиме", + "mobileservicesnotenabled": "Мобилни сервиси нису омогућени на вашем сајту. Обратите се администратору вашег Moodle сајта ако мислите да мобилни приступ треба да буде омогућен.", + "newaccount": "Нови кориснички налог", + "newsitedescription": "Унесите URL адресу вашег Moodle сајта. Имајте на уму да сајт можда није конфигурисан да ради са овом апликацијом.", + "notloggedin": "Морате бити пријављени.", + "password": "Лозинка", + "passwordrequired": "Неопходна је лозинка", + "policyaccept": "Разумем и пристајем", + "policyagree": "Да би сте наставили коришћење овог сајта морате се сложити са правилима коришћења. Да ли се слажете?", + "policyagreement": "Сагласност са правилником о коришћењу сајта", + "policyagreementclick": "Линк ка правилнику о коришћењу сајта", + "potentialidps": "Пријавите се користећи свој налог на:", + "problemconnectingerror": "Имамо проблема да се повежемо са", + "problemconnectingerrorcontinue": "Добро проверите да ли сте правилно унели адресу и покушајте поново.", + "profileinvaliddata": "Неисправна вредност", + "recaptchachallengeimage": "reCAPTCHA слика", + "reconnect": "Повежите се поново", + "reconnectdescription": "Ваш токен за проверу идентитета је неисправан или је истекао. Морате поново да успоставите везу са сајтом.", + "reconnectssodescription": "Ваш токен за проверу идентитета је неисправан или је истекао. Морате поново да успоставите везу са сајтом. Потребно је да се пријавите на сајт у прозору веб читача.", + "security_question": "Безбедносно питање", + "selectacountry": "Изабери државу", + "signupplugindisabled": "{{$a}} није омогућен.", + "siteaddress": "Адреса сајта", + "siteinmaintenance": "Ваш сајт је у режиму одржавања", + "sitepolicynotagreederror": "Сагласност са политиком сајта није потврђена.", + "siteurl": "URL адреса сајта", + "siteurlrequired": "Неопходна је URL адреса, нпр. http://www.yourmoodlesite.abc или https://www.yourmoodlesite.efg", + "startsignup": "Креирај нови налог", + "stillcantconnect": "Још увек не можете да се повежете?", + "supplyinfo": "Више детаља", + "username": "Корисничко име", + "usernamerequired": "Корисничко име је неопходно", + "usernotaddederror": "Корисник није додат - грешка", + "visitchangepassword": "Да ли желите да посетите сајт како бисте променили лозинку?", + "webservicesnotenabled": "Веб сервиси нису омогућени на вашем сајту. Обратите се администратору вашег Moodle сајта ако мислите да мобилни приступ треба да буде омогућен." +} \ No newline at end of file diff --git a/www/core/components/login/lang/sr-lt.json b/www/core/components/login/lang/sr-lt.json new file mode 100644 index 00000000000..337bb4983ae --- /dev/null +++ b/www/core/components/login/lang/sr-lt.json @@ -0,0 +1,77 @@ +{ + "auth_email": "Samostalna registracija na osnovu e-adrese", + "authenticating": "Provera identiteta", + "cancel": "Odustani", + "checksiteversion": "Proverite da li vaš sajt koristi Moodle 2.4 ili noviju verziju.", + "confirmdeletesite": "Da li ste sigurni da želite da obrišete sajt {{sitename}}?", + "connect": "Povežite se!", + "connecttomoodle": "Povežite se sa Moodleom", + "contactyouradministrator": "Obratite se administratoru vašeg sajta za dalju pomoć.", + "contactyouradministratorissue": "Zamolite administratora da proveri sledeći problem: {{$a}}", + "createaccount": "Kreiraj moj novi korisnički nalog", + "createuserandpass": "Izaberite svoje korisničko ime i lozinku za pristup sistemu", + "credentialsdescription": "Za prijavu na sistem unesite svoje korisničko ime i lozinku.", + "emailconfirmsent": "

Trebalo bi da je poslata poruka na vašu e-adresu {{$a}}

Poruka sadrži jednostavna uputstva o daljem postupku registracije.

Ako i dalje imate problema, obratite se administratoru sajta.

", + "emailnotmatch": "Adrese e-pošte se ne poklapaju", + "enterthewordsabove": "Unesite reč iznad", + "erroraccesscontrolalloworigin": "Cross-Origin poziv koji pokušavate da izvedete je odbijen. Molimo, proverite https://docs.moodle.org/dev/Moodle_Mobile_development_using_Chrome_or_Chromium", + "errordeletesite": "Došlo je do greške prilikom brisanja ovog sajta. Molim, pokušajte ponovo.", + "errorupdatesite": "Došlo je do greške prilikom ažuriranju tokena sajta.", + "firsttime": "Da li ste ovde prvi put?", + "getanothercaptcha": "Preuzmite drugi CAPTCHA", + "help": "Pomoć", + "helpmelogin": "

Širom sveta postoji više hiljada Moodle sajtova. Ova aplikacija može se povezati samo sa Moodle sajtovima koji su namenski omogućili pristup aplikacijama za mobilne uređaje.

Ako ne možete da se povežete sa vašim Moodle sajtom potrebno je da se obratite Moodle administratoru sajta sa kojim želite da se povežete i da ga zamolite da pročitahttp://docs.moodle.org/en/Mobile_app

Za testiranje aplikacije na Moodle demo sajtu unesite teacher ili student u polje Adresa sajta i kliknite na dugme Poveži se!.

", + "instructions": "Uputstva", + "invalidaccount": "Proverite svoje podatke za prijavu ili zamolite vašeg administratora da proveri konfiguraciju sajta.", + "invaliddate": "Neispravan datum", + "invalidemail": "Neispravna adresa elektronske pošte", + "invalidmoodleversion": "Neispravna Moodle verzija. Neophodna je, minimalno, verzija 2.4.", + "invalidsite": "URL adresa sajt nije ispravna.", + "invalidtime": "Neispravno vreme", + "invalidurl": "Neispravan url", + "invalidvaluemax": "Maksimalna vrednost je {{$a}}", + "invalidvaluemin": "Minimalna vrednost je {{$a}}", + "localmobileunexpectedresponse": "Provera Moodle Mobile dodatnih funkcionalnosti vratila je neočekivan odgovor. Vaš identitet biće proveren pomoću standardnog mobilnog servisa.", + "loggedoutssodescription": "Morate ponovo da potvrdite svoj identitet. Potrebno je da se prijavite na sajt u prozoru veb čitača.", + "login": "Prijava", + "loginbutton": "Prijava", + "logininsiterequired": "Potrebno je da se prijavite na sajt u prozoru veb čitača.", + "loginsteps": "Kako biste imali puni pristup ovom sajtu morate kreirati korisnički nalog.", + "missingemail": "Nedostaje adresa e-pošte", + "missingfirstname": "Nedostaje ime", + "missinglastname": "Nedostaje prezime", + "mobileservicesnotenabled": "Mobilni servisi nisu omogućeni na vašem sajtu. Obratite se administratoru vašeg Moodle sajta ako mislite da mobilni pristup treba da bude omogućen.", + "newaccount": "Novi korisnički nalog", + "newsitedescription": "Unesite URL adresu vašeg Moodle sajta. Imajte na umu da sajt možda nije konfigurisan da radi sa ovom aplikacijom.", + "notloggedin": "Morate biti prijavljeni.", + "password": "Lozinka", + "passwordrequired": "Neophodna je lozinka", + "policyaccept": "Razumem i pristajem", + "policyagree": "Da bi ste nastavili korišćenje ovog sajta morate se složiti sa pravilima korišćenja. Da li se slažete?", + "policyagreement": "Saglasnost sa pravilnikom o korišćenju sajta", + "policyagreementclick": "Link ka pravilniku o korišćenju sajta", + "potentialidps": "Prijavite se koristeći svoj nalog na:", + "problemconnectingerror": "Imamo problema da se povežemo sa", + "problemconnectingerrorcontinue": "Dobro proverite da li ste pravilno uneli adresu i pokušajte ponovo.", + "profileinvaliddata": "Neispravna vrednost", + "recaptchachallengeimage": "reCAPTCHA slika", + "reconnect": "Povežite se ponovo", + "reconnectdescription": "Vaš token za proveru identiteta je neispravan ili je istekao. Morate ponovo da uspostavite vezu sa sajtom.", + "reconnectssodescription": "Vaš token za proveru identiteta je neispravan ili je istekao. Morate ponovo da uspostavite vezu sa sajtom. Potrebno je da se prijavite na sajt u prozoru veb čitača.", + "security_question": "Bezbednosno pitanje", + "selectacountry": "Izaberi državu", + "signupplugindisabled": "{{$a}} nije omogućen.", + "siteaddress": "Adresa sajta", + "siteinmaintenance": "Vaš sajt je u režimu održavanja", + "sitepolicynotagreederror": "Saglasnost sa politikom sajta nije potvrđena.", + "siteurl": "URL adresa sajta", + "siteurlrequired": "Neophodna je URL adresa, npr. http://www.yourmoodlesite.abc ili https://www.yourmoodlesite.efg", + "startsignup": "Kreiraj novi nalog", + "stillcantconnect": "Još uvek ne možete da se povežete?", + "supplyinfo": "Više detalja", + "username": "Korisničko ime", + "usernamerequired": "Korisničko ime je neophodno", + "usernotaddederror": "Korisnik nije dodat - greška", + "visitchangepassword": "Da li želite da posetite sajt kako biste promenili lozinku?", + "webservicesnotenabled": "Veb servisi nisu omogućeni na vašem sajtu. Obratite se administratoru vašeg Moodle sajta ako mislite da mobilni pristup treba da bude omogućen." +} \ No newline at end of file diff --git a/www/core/components/login/lang/sv.json b/www/core/components/login/lang/sv.json index b4041bf5a3d..94336186f13 100644 --- a/www/core/components/login/lang/sv.json +++ b/www/core/components/login/lang/sv.json @@ -7,11 +7,11 @@ "createaccount": "Skapa mitt nya konto", "createuserandpass": "Skapa ett nytt användarnamn och lösenord för att logga in med.", "credentialsdescription": "Ange ditt användarnamn och lösenord för att logga på", - "emailconfirmsent": "

Vi har skickat ett e-postbrev som Du bör ha fått
till Din adress på {{$a}}

\n

Det innehåller enkla instruktioner som hjälper Dig
att fullfölja Din registrering.

\n

Om Du stöter på problem, är Du välkommen att
kontakta den som ansvarar för webbplatsen.

", + "emailconfirmsent": "

Vi har skickat ett e-postbrev som du bör ha fått
till din adress på {{$a}}

\n

Det innehåller enkla instruktioner som hjälper dig
att fullfölja din registrering.

\n

Om du stöter på problem, är du välkommen att
kontakta den som ansvarar för webbplatsen.

", "enterthewordsabove": "Mata in de ovanstående orden", "errordeletesite": "Ett fel inträffade vid borttagning av denna webbsida. Var god försök igen.", "errorupdatesite": "Ett fel inträffade vid uppdatering av webbplatsens token.", - "firsttime": "Är det första gången Du är här?", + "firsttime": "Är det första gången du är här?", "getanothercaptcha": "Skaffa en CAPTCHA till", "help": "Hjälp", "helpmelogin": "

För att logga in måste du kontrollera att: 1. Moodle webbplats är version 2.4 eller högre
2. Moodle administratören har aktiverat Mobil åtkomst

För att testa appen på en Moodle demo site skriv lärare eller elev i i fält för Användarnamn och klicka på Lägg till knapp . Besök Moodle webbplats för mer detaljerad Moodle information och hjälp. ", @@ -20,12 +20,12 @@ "invalidemail": "Ogiltig e-postadress", "invalidmoodleversion": "Ogiltig Moodle version. Lägsta version som krävs är", "invalidsite": "Den webbadress är ogiltig.", - "invalidurl": "Ogiltig url", + "invalidurl": "Den URL som du just matade in är inte giltig", "localmobileunexpectedresponse": "Kontrollen för Moodle mobila funktioner returnerade ett oväntat svar. Du kommer att autentiseras med mobila standard tjänsten.", "login": "Logga in", "loginbutton": "Logga In!", "logininsiterequired": "Du måste logga in på webbplatsen via en webbläsare", - "loginsteps": "Hej!\n
\nDu måste bl.a. skapa ett nytt användarkonto på denna webbplats för att få tillgång till de kurser som Du vill delta i. Varje individuell kurs kan också ha en engångsnyckel \"kursnyckel\". Den behöver Du dock inte förrän senare.\n Så här skapar Du Ditt konto:\n

    \n
  1. Fyll i formuläret på sidan \nNytt konto med de efterfrågade\nuppgifterna om Dig själv.
  2. \n
  3. Ett e-postmeddelande kommer därefter\nomedelbart att sändas till\nDin e-postadress.
  4. \n
  5. Läs din e-post, och klicka på webblänken som den innehåller.
  6. \n
  7. Ditt konto kommer därmed att bekräftas\noch Du kommer att loggas in.
  8. \n
  9. Nu kan Du välja vilken kurs Du\nvill delta i.
  10. \n
  11. Om Du måste ange en \"kursnyckel\" - så\nfår Du använda den som Din lärare har\ngivit Dig. Med den kan Du registrera\nDig på en sådan kurs som kräver det.
  12. \n
  13. Nu kan Du använda hela kursen.\nFrån och med nu behöver Du bara skriva\nin Ditt användarnamn och lösenord\n(i formuläret till vänster på denna sida)\nför att logga in och för att nå de kurser\nsom Du är registrerad på.
  14. \n
\nOBS! Genom att Du bekräftar kontot så samtycker\nDu till databehandling enligt Personuppgiftslagen.\nOm Du är osäker på vad det innebär så kan Du hitta\nmer information här: 'http://www.datainspektionen.se/lagar-och-regler/personuppgiftslagen/\n'\n\nLycka till!", + "loginsteps": "Hej!\n
\nDu måste bl.a. skapa ett nytt användarkonto på denna webbplats för att få tillgång till de kurser som du vill delta i. Varje individuell kurs kan också ha en engångsnyckel \"kursnyckel\". Den behöver du dock inte förrän senare.\n Så här skapar du ditt konto:\n
    \n
  1. Fyll i formuläret på sidan \nNytt konto med de efterfrågade\nuppgifterna om dig själv.
  2. \n
  3. Ett e-postmeddelande kommer därefter\nomedelbart att sändas till\ndin e-postadress.
  4. \n
  5. Läs din e-post, och klicka på webblänken som den innehåller.
  6. \n
  7. Ditt konto kommer därmed att bekräftas\noch du kommer att loggas in.
  8. \n
  9. Nu kan du välja vilken kurs du\nvill delta i.
  10. \n
  11. Om du måste ange en \"kursnyckel\" - så\nfår du använda den som din lärare har\ngivit dig. Med den kan du registrera\ndig på en sådan kurs som kräver det.
  12. \n
  13. Nu kan du använda hela kursen.\nFrån och med nu behöver du bara skriva\nin ditt användarnamn och lösenord\n(i formuläret till vänster på denna sida)\nför att logga in och för att nå de kurser\nsom du är registrerad på.
  14. \n
\nOBS! Genom att du bekräftar kontot så samtycker\ndu till databehandling enligt Personuppgiftslagen.\nOm du är osäker på vad det innebär så kan du hitta\nmer information här: 'http://www.datainspektionen.se/lagar-och-regler/personuppgiftslagen/\n'\n\nLycka till!", "missingemail": "E-postadress saknas", "missingfirstname": "Förnamn saknas", "missinglastname": "Efternamn saknas", @@ -36,7 +36,7 @@ "password": "Lösenord", "passwordrequired": "Lösenord krävs", "policyaccept": "Jag förstår och accepterar", - "policyagree": "Du måste acceptera denna policy för få fortsätta att använda denna webbplats. Accepterar Du denna policy?", + "policyagree": "Du måste acceptera denna policy för få fortsätta att använda denna webbplats. Accepterar du denna policy?", "policyagreement": "Avtal angående webbplatsens policy.", "policyagreementclick": "Klicka här för att läsa avtalet angående webbplatsens policy.", "potentialidps": "Logga in med ditt konto på:", diff --git a/www/core/components/login/lang/tr.json b/www/core/components/login/lang/tr.json index 46bf85328fd..e417e613e87 100644 --- a/www/core/components/login/lang/tr.json +++ b/www/core/components/login/lang/tr.json @@ -17,7 +17,7 @@ "invalidemail": "Geçersiz e-posta adresi", "invalidmoodleversion": "Geçersiz Moodle sürümü. Sitenizin Sürümünün şundan aşağı olmaması gerekir:", "invalidsite": "Bu site adresi geçersizdir.", - "invalidurl": "Geçersiz URL", + "invalidurl": "Girdiğiniz URL geçerli değil", "login": "Giriş yap", "logininsiterequired": "Bir tarayıcı penceresinde siteye giriş yapmanız gerekiyor.", "loginsteps": "Bu siteye tam erişim için önce bir hesap oluşturmalısınız.", diff --git a/www/core/components/login/lang/uk.json b/www/core/components/login/lang/uk.json index eb2ed868ac3..3288bf24510 100644 --- a/www/core/components/login/lang/uk.json +++ b/www/core/components/login/lang/uk.json @@ -1,11 +1,11 @@ { "auth_email": "Email на основі самостійної реєстрації", - "authenticating": "Аутинтифікація", + "authenticating": "Аутентифікація", "cancel": "Скасувати", "checksiteversion": "Переконайтеся, що ваш сайт використовує Moodle 2.4 або більш пізньої версії.", "confirmdeletesite": "Видалити сайт {{sitename}}?", "connect": "З'єднано!", - "connecttomoodle": "Відключитись до Moodle", + "connecttomoodle": "Підключитись до Moodle", "contactyouradministrator": "Зверніться до адміністратора сайту для подальшої допомоги.", "contactyouradministratorissue": "Будь ласка, зверніться до адміністратора, щоб перевірити наступне питання: {{$a}}", "createaccount": "Створити запис", @@ -14,21 +14,21 @@ "emailconfirmsent": "

Лист повинен бути відправлений на Вашу електронну адресу в {{$a}}

Він містить прості інструкції для завершення реєстрації.

Якщо ви продовжуєте зазнавати труднощів, зверніться до адміністратора сайту.

", "emailnotmatch": "Email не співпадають", "enterthewordsabove": "Введіть символи, які бачите вище", - "erroraccesscontrolalloworigin": "Cross-Origin дзвінок Ви намагаєтеся виконати відхилено. Будь ласка, перевірте https://docs.moodle.org/dev/Moodle_Mobile_development_using_Chrome_or_Chromium", + "erroraccesscontrolalloworigin": "Cross-Origin дзвінок був відхилений. Будь ласка, перевірте https://docs.moodle.org/dev/Moodle_Mobile_development_using_Chrome_or_Chromium", "errordeletesite": "Під час видалення цього сайту сталася помилка. Будь ласка спробуйте ще раз.", "errorupdatesite": "При оновленні токена сайту сталася помилка.", "firsttime": "Ви вперше на нашому сайті?", "getanothercaptcha": "Отримати інший варант", "help": "Допомога", - "helpmelogin": "

Є багато тисяч сайтів Moodle по всьому світу. Ця програма може підключатися тільки до сайтів Moodle, які спеціально з підтримкою мобільного доступу додатків.

Якщо ви не можете підключитися до вашого сайту Moodle, то вам необхідно звернутися до адміністратора Moodle в тому місці, де планується отримати доступ і попросіть їх прочитати http://docs.moodle.org/en/Mobile_app

Щоб перевірити додаток в типі Moodle демо сайті учитель або студент в адреса сайту поля і натисніть кнопку Підключення .

", + "helpmelogin": "

Є багато тисяч сайтів Moodle по всьому світу. Ця програма може підключатися тільки до сайтів Moodle, які є з підтримкою мобільного доступу додатків.

Якщо ви не можете підключитися до вашого сайту Moodle, то вам необхідно звернутися до адміністратора Moodle в тому місці, де планується отримати доступ і попросіть їх прочитати http://docs.moodle.org/en/Mobile_app

Щоб перевірити додаток на Moodle демо сайті в ролі вчителя або студента в полі адреса сайту і натисніть кнопку Підключення .

", "instructions": "Інструкції", "invalidaccount": "Будь ласка, перевірте ваші реєстраційні дані, або зверніться до адміністратора сайту, щоб перевірити конфігурацію сайту.", "invaliddate": "Невірна дата", "invalidemail": "Неправильний формат для ел.пошти", - "invalidmoodleversion": "Невірна версія Moodle. Мінімальна версія 2.4 потрібно.", + "invalidmoodleversion": "Невірна версія Moodle. Мінімальна версія 2.4.", "invalidsite": "URL сайту недійсний.", "invalidtime": "Невірний час", - "invalidurl": "Неправильний URL", + "invalidurl": "Введений вами URL неправильний", "invalidvaluemax": "Максимальне значення {{$a}}", "invalidvaluemin": "Мінімальне значення {{$a}}", "localmobileunexpectedresponse": "Moodle Mobile Additional Features при перевірці повернуло несподівану відповідь, ви будете проходити перевірку автентичності з використанням стандартного мобільного сервісу.", @@ -40,11 +40,11 @@ "missingemail": "Не вказано адресу електронної пошти", "missingfirstname": "Не вказано ім'я", "missinglastname": "Не вказано прізвище", - "mobileservicesnotenabled": "Мобільні послуги не включені в вашому сайті. Будь ласка, зверніться до адміністратора вашого Moodle сайт, якщо ви вважаєте, мобільний доступ повинен бути включений.", + "mobileservicesnotenabled": "Мобільні послуги не включені в вашому сайті. Будь ласка, зверніться до адміністратора вашого Moodle сайт, якщо ви вважаєте, що мобільний доступ повинен бути включений.", "newaccount": "Новий обліковий запис", - "newsitedescription": "Будь ласка, введіть адресу вашого сайту Moodle. Зверніть увагу, що це не може бути налаштоване для роботи з цим додатком.", + "newsitedescription": "Будь ласка, введіть адресу вашого сайту Moodle. Зверніть увагу, що це може бути не налаштоване для роботи з цим додатком.", "notloggedin": "Ви повинні увійти в систему.", - "password": "Відкритий ключ", + "password": "Пароль", "passwordrequired": "Пароль необхідний", "policyaccept": "Я розумію та погоджуюся", "policyagree": "Ви повинні погодитися з цими правилами для використання цього сайту. Ви згодні?", @@ -57,7 +57,7 @@ "recaptchachallengeimage": "виклик reCAPTCHA", "reconnect": "Повторне з'єднання", "reconnectdescription": "Ваш маркер аутентифікації недійсний або закінчився, ви повинні підключитися до сайту.", - "reconnectssodescription": "Ваш маркер аутентифікації недійсний або закінчився, ви повинні підключитися до сайту. Вам необхідно увійти на сайт у вікні браузера.", + "reconnectssodescription": "Ваш маркер аутентифікації недійсний або закінчився, ви повинні перепідключитися до сайту. Вам необхідно увійти на сайт у вікні браузера.", "security_question": "Контрольне питання", "selectacountry": "Країна", "signupplugindisabled": "{{$a}} не доступно.", @@ -67,11 +67,11 @@ "siteurl": "URL сайту", "siteurlrequired": "URL сайту повинно бути схоже на http://www.yourmoodlesite.abc or https://www.yourmoodlesite.efg", "startsignup": "Створити новий обліковий запис", - "stillcantconnect": "До сих пір не можу підключитися?", + "stillcantconnect": "До сих пір не можете підключитися?", "supplyinfo": "Більше інформації", - "username": "Ім’я входу", + "username": "Псевдо", "usernamerequired": "Ім'я користувача необхідне", "usernotaddederror": "Користувач не доданий - помилка", "visitchangepassword": "Ви хочете відвідати сайт, щоб змінити пароль?", - "webservicesnotenabled": "Веб-служба не включені в вашому сайті. Будь ласка, зверніться до адміністратора вашого Moodle сайт, якщо ви вважаєте, мобільний доступ повинен бути включений." + "webservicesnotenabled": "Веб-служба не включені в вашому сайті. Будь ласка, зверніться до адміністратора вашого Moodle сайту, якщо ви вважаєте, що мобільний доступ повинен бути включений." } \ No newline at end of file diff --git a/www/core/components/login/lang/zh-cn.json b/www/core/components/login/lang/zh-cn.json index 64f858f8e48..7c5cb7f013d 100644 --- a/www/core/components/login/lang/zh-cn.json +++ b/www/core/components/login/lang/zh-cn.json @@ -15,7 +15,7 @@ "invalidemail": "Email地址无效", "invalidmoodleversion": "无效的Moodle版本。最低版本要求是:", "invalidsite": "网站URL是无效的。", - "invalidurl": "无效的 网页地址", + "invalidurl": "您刚刚输入的 URL 不合法", "login": "登录", "logininsiterequired": "您需要在浏览器窗口中登录该站点。", "loginsteps": "为了能完全访问此网站,您首先需要创建一个帐户。", @@ -24,7 +24,7 @@ "missinglastname": "姓没填", "mobileservicesnotenabled": "您的站点没有启用移动服务,如果您觉得有必要开启移动接入功能,请与站点管理员联系。", "newaccount": "新帐号", - "password": "设置密码", + "password": "密码", "passwordrequired": "需要密码", "policyaccept": "我了解和同意了", "policyagree": "如要继续使用此站,您必须同意此协议。您同意么?", diff --git a/www/core/components/login/lang/zh-tw.json b/www/core/components/login/lang/zh-tw.json index bb2823d16de..110d8e28784 100644 --- a/www/core/components/login/lang/zh-tw.json +++ b/www/core/components/login/lang/zh-tw.json @@ -19,7 +19,7 @@ "errorupdatesite": "更新網站權杖時出錯.", "firsttime": "您第一次來訪嗎?", "getanothercaptcha": "換一個字詞", - "help": "輔助說明", + "help": "幫助", "helpmelogin": "

要登入前請確認:

1. Moodle 入口網站版本要是2.4或更高
2. Moodle 入口網站管理員有啟用手機存取.

想測試Moodle示範入口網站型態須輸入teacherstudentUsername 欄位並點選Add button.

Moodle文件網站有更詳細的資料及協助

", "instructions": "使用說明", "invalidaccount": "請檢查您的登人資料或請您的網站管理員檢查網站設定。", @@ -28,7 +28,7 @@ "invalidmoodleversion": "無效的Moodle版本。至少需要的版本為2.4", "invalidsite": "這網站網址無效.", "invalidtime": "無效的時間", - "invalidurl": "無效的URL網址", + "invalidurl": "輸入的網址無效", "invalidvaluemax": "最大值為 {{$a}}", "invalidvaluemin": "最小值為 {{$a}}", "localmobileunexpectedresponse": "Moodle行動其他功能檢查返回了無預期的回應, 您將使用標準行動服務進行身份驗證.", @@ -43,7 +43,7 @@ "newaccount": "新帳號", "newsitedescription": "請輸入您的Moodle平台網址. 注意平台需要先設定好才能使用這個應用程式.", "notloggedin": "你必須先登入", - "password": "共用密碼", + "password": "密碼", "passwordrequired": "需要密碼", "policyaccept": "我了解並且同意", "policyagree": "您必須同意這協議才能繼續使用這個網站。您同意嗎?", @@ -67,7 +67,7 @@ "startsignup": "申請一個新帳號", "stillcantconnect": "一直無法連線嗎?", "supplyinfo": "更多細節", - "username": "帳號", + "username": "用戶名稱", "usernamerequired": "需要帳號", "usernotaddederror": "無法新增用戶- 未知的錯誤", "visitchangepassword": "您需要去拜訪這個網站變更密碼嗎?", diff --git a/www/core/components/login/lang/zh_cn.json b/www/core/components/login/lang/zh_cn.json deleted file mode 100644 index f7c4ce0fbbf..00000000000 --- a/www/core/components/login/lang/zh_cn.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "authenticating": "验证中", - "cancel": "取消", - "connect": "连接", - "help": "帮助", - "helpmelogin": "

全世界有成千上万的Moodle站点。本APP只能连接那些启用移动APP接入功能的Moodle站点。

如果您无法连接该站点,请与相关站点管理员联系并请他们阅读以下文档http://docs.moodle.org/en/Mobile_app

想要在Moodle演示站点中测试本APP,请在站点URL栏中输入teacher或者student,并点击添加按钮

", - "invalidaccount": "请检查您的登录信息,或请您的网站管理员检查网站设置。", - "invalidmoodleversion": "无效的Moodle版本。最低版本要求是:", - "invalidsite": "网站URL是无效的。", - "login": "登录", - "logininsiterequired": "您需要在浏览器窗口中登录该站点。", - "mobileservicesnotenabled": "您的站点没有启用移动服务,如果您觉得有必要开启移动接入功能,请与站点管理员联系。", - "password": "密码", - "passwordrequired": "需要密码", - "siteinmaintenance": "您的站点正使用维护模式", - "siteurl": "站点 URL", - "siteurlrequired": "需要填写站点URL,比如http://www.yourmoodlesite.abc 或https://www.yourmoodlesite.efg", - "username": "用户名", - "usernamerequired": "用户名必填", - "webservicesnotenabled": "您的站点未开启网络服务。如果您觉得应当启用移动接入功能,请与站点管理员联系。" -} \ No newline at end of file diff --git a/www/core/components/login/lang/zh_tw.json b/www/core/components/login/lang/zh_tw.json deleted file mode 100644 index 4b4a2e8a1c9..00000000000 --- a/www/core/components/login/lang/zh_tw.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "authenticating": "認證中", - "cancel": "取消", - "connect": "連結", - "help": "協助", - "helpmelogin": "

要登入前請確認:

1. Moodle 入口網站版本要是2.4或更高
2. Moodle 入口網站管理員有啟用手機存取.

想測試Moodle示範入口網站型態須輸入teacherstudentUsername 欄位並點選Add button.

Moodle文件網站有更詳細的資料及協助

", - "invalidaccount": "請檢查您的登人資料或請您的網站管理員檢查網站設定。", - "invalidmoodleversion": "無效的Moodle版本。至少需要的版本是:", - "invalidsite": "這網站網址無效。", - "login": "登入", - "logininsiterequired": "您的Moodle網站強制您以系統瀏覽器開啟。將開啟新瀏覽器,並重新導向這Moodle網站。", - "mobileservicesnotenabled": "您的網站並未啟用行動服務。如果您想使用此功能,請連絡您的Moodle網站管理員。", - "password": "密碼", - "passwordrequired": "需要密碼", - "siteinmaintenance": "您的網站處於維護模式", - "siteurl": "網站網址", - "siteurlrequired": "需要網站網址,例如http://www.yourmoodle.tw", - "username": "帳號", - "usernamerequired": "需要帳號", - "webservicesnotenabled": "您的網站沒有啟用Web服務。如果您想用行動裝置連線,請聯繫您的Moodle網站管理員。" -} \ No newline at end of file diff --git a/www/core/components/login/main.js b/www/core/components/login/main.js index d4cac17104b..77987043fc8 100644 --- a/www/core/components/login/main.js +++ b/www/core/components/login/main.js @@ -30,6 +30,12 @@ angular.module('mm.core.login', []) onEnter: function($ionicHistory) { // Ensure that there is no history stack when getting here. $ionicHistory.clearHistory(); + }, + controller: function($scope) { + // Required for Electron app so the title doesn't change. + $scope.$on('$ionicView.afterEnter', function(ev) { + ev.stopPropagation(); + }); } }) @@ -357,6 +363,10 @@ angular.module('mm.core.login', []) // Authentication ongoing, probably duplicated request. return true; } + if ($mmApp.isDesktop()) { + // In desktop, make sure InAppBrowser is closed. + $mmUtil.closeInAppBrowser(true); + } // App opened using custom URL scheme. Probably an SSO authentication. $mmApp.startSSOAuthentication(); @@ -365,10 +375,9 @@ angular.module('mm.core.login', []) // Delete the sso scheme from the URL. url = url.replace(ssoScheme, ''); + // Some platforms like Windows add a slash at the end. Remove it. // Some sites add a # at the end of the URL. If it's there, remove it. - if (url.slice(-1) == '#') { - url = url.substring(0, url.length - 1); - } + url = url.replace(/\/?#?\/?$/, ''); // Decode from base64. try { diff --git a/www/core/components/login/scss/styles.scss b/www/core/components/login/scss/styles.scss index 78aa66c1561..18dad1af296 100644 --- a/www/core/components/login/scss/styles.scss +++ b/www/core/components/login/scss/styles.scss @@ -61,4 +61,9 @@ background: $white; border: 1px solid $item-default-border; } + + .mm-sitename, .mm-siteurl { + @if $mm-fixed-url { display: none; } + } } + diff --git a/www/core/components/login/templates/credentials.html b/www/core/components/login/templates/credentials.html index 053f7bb9865..74fff04f930 100644 --- a/www/core/components/login/templates/credentials.html +++ b/www/core/components/login/templates/credentials.html @@ -5,13 +5,13 @@
- + -

{{siteurl}}

+

{{siteurl}}

-

{{sitename}}

-

{{siteurl}}

+

{{sitename}}

+

{{siteurl}}

diff --git a/www/core/components/login/templates/init.html b/www/core/components/login/templates/init.html index eea30ac01a2..628fa135273 100644 --- a/www/core/components/login/templates/init.html +++ b/www/core/components/login/templates/init.html @@ -1,7 +1,7 @@ diff --git a/www/core/components/login/templates/reconnect.html b/www/core/components/login/templates/reconnect.html index d425a8cf33e..cd887e58af7 100644 --- a/www/core/components/login/templates/reconnect.html +++ b/www/core/components/login/templates/reconnect.html @@ -6,13 +6,13 @@ {{ 'mm.core.pictureof' | translate:{$a: site.fullname} }} - + -

{{siteurl}}

+

{{siteurl}}

-

{{sitename}}

-

{{siteurl}}

+

{{sitename}}

+

{{siteurl}}

{{ 'mm.login.reconnectdescription' | translate }}

diff --git a/www/core/components/login/templates/site.html b/www/core/components/login/templates/site.html index cc1310fd9c7..57abe516090 100644 --- a/www/core/components/login/templates/site.html +++ b/www/core/components/login/templates/site.html @@ -6,7 +6,7 @@
- +

{{ 'mm.login.newsitedescription' | translate }}

diff --git a/www/core/components/question/lang/ar.json b/www/core/components/question/lang/ar.json index b9b6af53575..f2bdf1cf476 100644 --- a/www/core/components/question/lang/ar.json +++ b/www/core/components/question/lang/ar.json @@ -1,14 +1,14 @@ { - "answer": "أجب", + "answer": "إجابة", "answersaved": "تم حفظ الإجابة", - "complete": "كامل", - "correct": "صح", - "feedback": "تقرير", - "incorrect": "خطاء", + "complete": "تم/كامل", + "correct": "صحيح/صح", + "feedback": "اجابة تقييمية", + "incorrect": "خطأ", "information": "معلومات", "invalidanswer": "إجابة غير مكتملة", - "notanswered": "لم تتم الأجابة بعد", - "notyetanswered": "لم يتم الاجابة بعد", + "notanswered": "لم يتم الاجابة عليه", + "notyetanswered": "لم يتم الاجابة عليه بعد", "partiallycorrect": "إجابة جزئية", "questionno": "سؤال {{$a}}", "requiresgrading": "يتطلب التصحيح", diff --git a/www/core/components/question/lang/bg.json b/www/core/components/question/lang/bg.json index f375fb3b363..332093fefd8 100644 --- a/www/core/components/question/lang/bg.json +++ b/www/core/components/question/lang/bg.json @@ -1,15 +1,15 @@ { "answer": "Отговор", "answersaved": "Отговорът съхранен", - "complete": "Завършен", - "correct": "Вярно", - "feedback": "Обратна връзка", + "complete": "Отговорен", + "correct": "Правилно", + "feedback": "Съобщение", "incorrect": "Неправилно", "information": "Информация", "invalidanswer": "Непълен отговор", - "notanswered": "Още няма отговори", - "notyetanswered": "Още без отговор", - "partiallycorrect": "Частично верен", + "notanswered": "Не е отговорен", + "notyetanswered": "Все още не е даден отговор", + "partiallycorrect": "Отчасти верен", "questionno": "Въпрос {{$a}}", "requiresgrading": "Изисква оценяване", "unknown": "Неизвестно" diff --git a/www/core/components/question/lang/ca.json b/www/core/components/question/lang/ca.json index e31c6bbe967..52bd86fd1d3 100644 --- a/www/core/components/question/lang/ca.json +++ b/www/core/components/question/lang/ca.json @@ -1,18 +1,18 @@ { "answer": "Resposta", "answersaved": "Resposta desada", - "complete": "Complet", - "correct": "Correcta", + "complete": "Completa", + "correct": "Correcte", "errorattachmentsnotsupported": "L'aplicació encara no admet l'adjunció de fitxers.", "errorinlinefilesnotsupported": "L'aplicació encara no és compatible amb l'edició de fitxers en línia.", "errorquestionnotsupported": "L'aplicació no accepta aquest tipus de pregunta: {{$a}}.", "feedback": "Retroacció", "howtodraganddrop": "Feu un toc per seleccionar i feu un toc de nou per deixar anar.", - "incorrect": "Incorrecta", + "incorrect": "Incorrecte", "information": "Informació", "invalidanswer": "Resposta no vàlida o incompleta", - "notanswered": "No contestada encara", - "notyetanswered": "Encara no s'ha contestat", + "notanswered": "No s'ha respost", + "notyetanswered": "No s'ha respost encara", "partiallycorrect": "Parcialment correcte", "questionmessage": "Pregunta {{$a}}: {{$b}}", "questionno": "Pregunta {{$a}}", diff --git a/www/core/components/question/lang/cs.json b/www/core/components/question/lang/cs.json index bbc66f32d73..f9f9a4b0557 100644 --- a/www/core/components/question/lang/cs.json +++ b/www/core/components/question/lang/cs.json @@ -1,19 +1,19 @@ { "answer": "Odpověď", "answersaved": "Odpověď uložena", - "complete": "Splněno", - "correct": "Správná odpověď", + "complete": "Hotovo", + "correct": "Správně", "errorattachmentsnotsupported": "Aplikace ještě nepodporuje připojování souborů k odpovědím.", "errorinlinefilesnotsupported": "Aplikace ještě nepodporuje úpravy vložených souborů.", "errorquestionnotsupported": "Tento typ úlohy není aplikací podporován: {{$a}}.", - "feedback": "Komentář", + "feedback": "Hodnocení", "howtodraganddrop": "Klepnutím vyberte potom klepněte na místo umístění.", - "incorrect": "Nesprávná odpověď", + "incorrect": "Nesprávně", "information": "Informace", "invalidanswer": "Neúplná odpověď", - "notanswered": "Dosud nezodpovězeno", + "notanswered": "Nezodpovězeno", "notyetanswered": "Dosud nezodpovězeno", - "partiallycorrect": "Částečně správná odpověď", + "partiallycorrect": "Částečně správně", "questionmessage": "Úloha {{$a}}: {{$b}}", "questionno": "Úloha {{$a}}", "requiresgrading": "Vyžaduje hodnocení", diff --git a/www/core/components/question/lang/da.json b/www/core/components/question/lang/da.json index 843f20d8b39..d2bbaa071f2 100644 --- a/www/core/components/question/lang/da.json +++ b/www/core/components/question/lang/da.json @@ -1,15 +1,15 @@ { "answer": "Svar", "answersaved": "Besvaret", - "complete": "Færdiggør", + "complete": "Gennemført", "correct": "Rigtigt", - "feedback": "Tilbagemelding", + "feedback": "Feedback", "incorrect": "Forkert", "information": "Information", "invalidanswer": "Ufuldstændigt svar", - "notanswered": "Ikke besvaret endnu", - "notyetanswered": "Endnu ikke besvaret", - "partiallycorrect": "Delvist rigtigt", + "notanswered": "Ikke besvaret", + "notyetanswered": "Ikke besvaret", + "partiallycorrect": "Delvis rigtigt", "questionno": "Spørgsmål {{$a}}", "requiresgrading": "Kræver bedømmelse", "unknown": "Ukendt" diff --git a/www/core/components/question/lang/de.json b/www/core/components/question/lang/de.json index 8e1a1ff2bc6..75ee149e500 100644 --- a/www/core/components/question/lang/de.json +++ b/www/core/components/question/lang/de.json @@ -1,18 +1,18 @@ { "answer": "Antwort", "answersaved": "Antwort gespeichert", - "complete": "Fertig", + "complete": "Vollständig", "correct": "Richtig", "errorattachmentsnotsupported": "Die App erlaubt keine Antworten mit Dateianhängen.", "errorinlinefilesnotsupported": "Die App unterstützt keine Bearbeitung von integrierten Dateien.", "errorquestionnotsupported": "Die App unterstützt diesen Fragetyp nicht: {{$a}}.", - "feedback": "Rückmeldung", + "feedback": "Feedback", "howtodraganddrop": "Tippen Sie zum Auswählen und tippen Sie noch einmal zum Ablegen.", "incorrect": "Falsch", "information": "Information", "invalidanswer": "Unvollständige Antwort", - "notanswered": "Nicht abgestimmt", - "notyetanswered": "unbeantwortet", + "notanswered": "Nicht beantwortet", + "notyetanswered": "Bisher nicht beantwortet", "partiallycorrect": "Teilweise richtig", "questionmessage": "Frage {{$a}}: {{$b}}", "questionno": "Frage {{$a}}", diff --git a/www/core/components/question/lang/el.json b/www/core/components/question/lang/el.json index 04bb3effa9e..b8f5de69e9c 100644 --- a/www/core/components/question/lang/el.json +++ b/www/core/components/question/lang/el.json @@ -3,12 +3,17 @@ "answersaved": "Η απάντηση αποθηκεύτηκε", "complete": "Ολοκλήρωση", "correct": "Σωστό", - "feedback": "Ανάδραση", + "errorattachmentsnotsupported": "Η εφαρμογή δεν υποστηρίζει ακόμα την προσάρτηση αρχείων σε απαντήσεις.", + "errorinlinefilesnotsupported": "Η εφαρμογή δεν υποστηρίζει ακόμα την επεξεργασία αρχείων.", + "errorquestionnotsupported": "Αυτός ο τύπος ερωτήματος δεν υποστηρίζεται από την εφαρμογή: {{$a}}.", + "feedback": "Επανατροφοδότηση", + "howtodraganddrop": "Πατήστε για να επιλέξετε και στη συνέχεια, πατήστε για να αφήσετε.", "incorrect": "Λάθος", "invalidanswer": "Ημιτελής απάντηση", - "notanswered": "Δεν απαντήθηκε ακόμα", + "notanswered": "Δεν απαντήθηκε", "notyetanswered": "Δεν έχει απαντηθεί ακόμα", "partiallycorrect": "Μερικώς σωστή", + "questionmessage": "Ερώτηση {{$a}}: {{$b}}", "questionno": "Ερώτηση {{$a}}", - "unknown": "Άγνωστο" + "unknown": "Δεν είναι δυνατός ο προσδιορισμός της κατάστασης" } \ No newline at end of file diff --git a/www/core/components/question/lang/es-mx.json b/www/core/components/question/lang/es-mx.json index c9008738aea..adeff045b27 100644 --- a/www/core/components/question/lang/es-mx.json +++ b/www/core/components/question/lang/es-mx.json @@ -1,19 +1,19 @@ { "answer": "Respuesta", "answersaved": "Respuesta guardada", - "complete": "Completado", - "correct": "Correcto", + "complete": "Completada", + "correct": "Correcta", "errorattachmentsnotsupported": "La aplicación todavía no soporta anexarle archivos a las respuestas.", "errorinlinefilesnotsupported": "La aplicación aun no soporta el editar archivos en-línea.", "errorquestionnotsupported": "Este tipo de pregunta no está soportada por la App: {{$a}}.", - "feedback": "Comentario de retroalimentación", + "feedback": "Retroalimentación", "howtodraganddrop": "Tocar para seleccionar y tocar para soltar", "incorrect": "Incorrecta", "information": "Información", "invalidanswer": "Respuesta incompleta", - "notanswered": "Sin contestar aún", - "notyetanswered": "Aún no se ha dado respuesta", - "partiallycorrect": "Parcialmente correcto", + "notanswered": "Sin contestar", + "notyetanswered": "Sin responder aún", + "partiallycorrect": "Parcialmente correcta", "questionmessage": "Pregunta {{$a}}: {{$b}}", "questionno": "Pregunta {{$a}}", "requiresgrading": "Requiere re-calificar", diff --git a/www/core/components/question/lang/es.json b/www/core/components/question/lang/es.json index d42f0b106e2..7ea9607d522 100644 --- a/www/core/components/question/lang/es.json +++ b/www/core/components/question/lang/es.json @@ -1,19 +1,19 @@ { "answer": "Respuesta", "answersaved": "Respuesta guardada", - "complete": "Completado", - "correct": "Correcto", + "complete": "Finalizado", + "correct": "Correcta", "errorattachmentsnotsupported": "La aplicación no soporta adjuntar archivos a respuestas todavía.", "errorinlinefilesnotsupported": "La aplicación aun no soporta el editar archivos en-línea.", "errorquestionnotsupported": "Este tipo de pregunta no está soportada por la aplicación: {{$a}}.", - "feedback": "Comentario", + "feedback": "Retroalimentación", "howtodraganddrop": "Tocar para seleccionar y tocar para soltar.", "incorrect": "Incorrecta", "information": "Información", "invalidanswer": "Respuesta incompleta", - "notanswered": "Sin contestar aún", - "notyetanswered": "Aún no se ha dado respuesta", - "partiallycorrect": "Parcialmente correcto", + "notanswered": "Sin contestar", + "notyetanswered": "Sin responder aún", + "partiallycorrect": "Parcialmente correcta", "questionmessage": "Pregunta {{$a}}: {{$b}}", "questionno": "Pregunta {{$a}}", "requiresgrading": "Requiere calificación", diff --git a/www/core/components/question/lang/eu.json b/www/core/components/question/lang/eu.json index d47acec2068..75d807d6c04 100644 --- a/www/core/components/question/lang/eu.json +++ b/www/core/components/question/lang/eu.json @@ -1,17 +1,17 @@ { - "answer": "Erantzun", + "answer": "Erantzuna", "answersaved": "Erantzuna gorde da", - "complete": "Osoa", + "complete": "Osatu", "correct": "Zuzena", "errorattachmentsnotsupported": "App-ak oraindik ez du erantzunei fitxategiak eranstea onartzen.", "errorinlinefilesnotsupported": "App-ak oraindik ez du fitxategien lerro-arteko edizioa onartzen.", "errorquestionnotsupported": "Galdera mota hau ez dago app-an onartuta: {{$a}}", "feedback": "Feedbacka", "howtodraganddrop": "Sakatu aukeratzeko eta ondoren sakatu ezabatzeko.", - "incorrect": "Ez zuzena", + "incorrect": "Okerra", "information": "Informazioa", "invalidanswer": "Erantzuna ez dago osorik", - "notanswered": "Oraindik erantzun gabe", + "notanswered": "Erantzun gabea", "notyetanswered": "Erantzun gabea", "partiallycorrect": "Zuzena zati batean", "questionmessage": "{{$a}} galdera: {{$b}}", diff --git a/www/core/components/question/lang/fa.json b/www/core/components/question/lang/fa.json index bf1d5eba5a2..64e56570cf2 100644 --- a/www/core/components/question/lang/fa.json +++ b/www/core/components/question/lang/fa.json @@ -1,15 +1,15 @@ { - "answer": "جواب", + "answer": "پاسخ", "answersaved": "پاسخ ذخیره شده", "complete": "کامل", - "correct": "صحیح", + "correct": "درست", "feedback": "بازخورد", "incorrect": "نادرست", "information": "توضیح", "invalidanswer": "پاسخ ناقص", - "notanswered": "هنوز پاسخ نداده‌اند", + "notanswered": "پاسخ داده نشده", "notyetanswered": "هنوز پاسخ داده نشده است", - "partiallycorrect": "نیمه درست", + "partiallycorrect": "پاسخ نیمه درست", "questionno": "سؤال {{$a}}", "requiresgrading": "نمره‌دهی لازم است", "unknown": "نامعلوم" diff --git a/www/core/components/question/lang/fr.json b/www/core/components/question/lang/fr.json index 53fa708cca6..1284a6a8d2a 100644 --- a/www/core/components/question/lang/fr.json +++ b/www/core/components/question/lang/fr.json @@ -1,7 +1,7 @@ { "answer": "Réponse", "answersaved": "Réponse enregistrée", - "complete": "Complet", + "complete": "Terminer", "correct": "Correct", "errorattachmentsnotsupported": "L'application ne permet pas encore d'annexer des fichiers aux réponses.", "errorinlinefilesnotsupported": "L'app ne permet pas encore la modification de fichiers en ligne.", @@ -11,7 +11,7 @@ "incorrect": "Incorrect", "information": "Description", "invalidanswer": "Réponse incomplète", - "notanswered": "Pas encore répondu", + "notanswered": "Non répondue", "notyetanswered": "Pas encore répondu", "partiallycorrect": "Partiellement correct", "questionmessage": "Question {{$a}} : {{$b}}", diff --git a/www/core/components/question/lang/he.json b/www/core/components/question/lang/he.json index 1761f82c521..2d12cd98d1f 100644 --- a/www/core/components/question/lang/he.json +++ b/www/core/components/question/lang/he.json @@ -2,14 +2,14 @@ "answer": "תשובה", "answersaved": "תשובה נשמרה", "complete": "הושלם", - "correct": "נכון", - "feedback": "תגובות", - "incorrect": "לא נכון", + "correct": "תקין", + "feedback": "משוב", + "incorrect": "שגוי", "information": "מידע", "invalidanswer": "תשובה שלא הושלמה", - "notanswered": "שאלה זו טרם נענתה", - "notyetanswered": "עדין לא ענו", - "partiallycorrect": "תשובה נכונה חלקית", + "notanswered": "לא נענה", + "notyetanswered": "שאלה זו טרם נענתה", + "partiallycorrect": "נכון באופן חלקי", "questionno": "שאלה {{$a}}", "requiresgrading": "נדרש מתן ציון", "unknown": "לא ידוע" diff --git a/www/core/components/question/lang/hu.json b/www/core/components/question/lang/hu.json index 649b1988ef4..04328cffde1 100644 --- a/www/core/components/question/lang/hu.json +++ b/www/core/components/question/lang/hu.json @@ -1,14 +1,14 @@ { "answer": "Válasz", "answersaved": "A válasz elmentve", - "complete": "Teljes", + "complete": "Kész", "correct": "Helyes", "feedback": "Visszajelzés", "incorrect": "Hibás", "information": "Információ", "invalidanswer": "Hiányos válasz", - "notanswered": "Még nincs válasz", - "notyetanswered": "Megválaszolatlan", + "notanswered": "Nincs rá válasz", + "notyetanswered": "Még nincs rá válasz", "partiallycorrect": "Részben helyes", "questionno": "{{$a}}. kérdés", "requiresgrading": "Pontozandó", diff --git a/www/core/components/question/lang/it.json b/www/core/components/question/lang/it.json index 364ddbf3b09..20bb79efc49 100644 --- a/www/core/components/question/lang/it.json +++ b/www/core/components/question/lang/it.json @@ -2,14 +2,14 @@ "answer": "Risposta", "answersaved": "Risposta salvata", "complete": "Completo", - "correct": "Giusto", - "feedback": "Commento", - "incorrect": "Sbagliato", + "correct": "Risposta corretta", + "feedback": "Feedback", + "incorrect": "Risposta errata", "information": "Informazione", "invalidanswer": "Risposta incompleta", - "notanswered": "Senza scelta", - "notyetanswered": "Senza risposta", - "partiallycorrect": "Parzialmente corretto", + "notanswered": "Risposta non data", + "notyetanswered": "Risposta non ancora data", + "partiallycorrect": "Parzialmente corretta", "questionmessage": "Domanda {{$a}}: {{$b}}", "questionno": "Domanda {{$a}}", "requiresgrading": "Richiede valutazione", diff --git a/www/core/components/question/lang/ja.json b/www/core/components/question/lang/ja.json index ecce8b3b1e0..83e300c2604 100644 --- a/www/core/components/question/lang/ja.json +++ b/www/core/components/question/lang/ja.json @@ -1,15 +1,15 @@ { - "answer": "回答", + "answer": "答え", "answersaved": "解答保存", - "complete": "詳細", + "complete": "完了", "correct": "正解", "feedback": "フィードバック", "howtodraganddrop": "選んだものをタッチして、あてはまる所にタッチして入れましょう。", "incorrect": "不正解", "information": "情報", "invalidanswer": "不完全な答え", - "notanswered": "未投票", - "notyetanswered": "未回答", + "notanswered": "未解答", + "notyetanswered": "未解答", "partiallycorrect": "部分的に正解", "questionmessage": "問題 {{$a}}: {{$b}}", "questionno": "問題 {{$a}}", diff --git a/www/core/components/question/lang/lt.json b/www/core/components/question/lang/lt.json index 4e598e09955..3a47ab0fc41 100644 --- a/www/core/components/question/lang/lt.json +++ b/www/core/components/question/lang/lt.json @@ -1,18 +1,18 @@ { - "answer": "Atsakyti", + "answer": "Atsakymas", "answersaved": "Atsakymas išsaugotas", - "complete": "Užbaigti", - "correct": "Teisingas", + "complete": "Baigta", + "correct": "Teisinga", "errorattachmentsnotsupported": "Programėlė nepalaiko pridėtų failų.", "errorinlinefilesnotsupported": "Programėlė nepalaiko redaguojamų failų", "errorquestionnotsupported": "Šis klausimo tipas programėlėje nepalaikomas: {{$a}}.", - "feedback": "Atsiliepimas", + "feedback": "Grįžtamasis ryšys", "howtodraganddrop": "Paspauskite pasirinkimui, tada perneškite.", - "incorrect": "Klaidinga", + "incorrect": "Neteisinga", "information": "Informacija", "invalidanswer": "Nepilnas atsakymas", - "notanswered": "Dar neatsakyta", - "notyetanswered": "Dar neatsakyta", + "notanswered": "Neatsakyta", + "notyetanswered": "Neatsakyta", "partiallycorrect": "Iš dalies teisingas", "questionmessage": "Klausimas {{$a}}: {{$b}}", "questionno": "Klausimas {{$a}}", diff --git a/www/core/components/question/lang/nl.json b/www/core/components/question/lang/nl.json index 18382e872c6..871c95b1c10 100644 --- a/www/core/components/question/lang/nl.json +++ b/www/core/components/question/lang/nl.json @@ -1,17 +1,17 @@ { "answer": "Antwoord", "answersaved": "Antwoord bewaard", - "complete": "Voltooid", + "complete": "Volledig", "correct": "Juist", "errorattachmentsnotsupported": "De applicatie ondersteunt nog geen blijlagen bij antwoorden.", "errorinlinefilesnotsupported": "Deze applicatie ondersteunt het inline bewerken van bestanden nog niet.", "errorquestionnotsupported": "Dit vraagtype wordt nog niet ondersteund door de app: {{$a}}.", "feedback": "Feedback", "howtodraganddrop": "Tik om te selecteren en tik om neer te zetten.", - "incorrect": "Niet juist", + "incorrect": "Fout", "information": "Informatie", "invalidanswer": "Onvolledig antwoord", - "notanswered": "Nog niet beantwoord", + "notanswered": "Niet beantwoord", "notyetanswered": "Nog niet beantwoord", "partiallycorrect": "Gedeeltelijk juist", "questionmessage": "Vraag {{$a}}: {{$b}}", diff --git a/www/core/components/question/lang/pl.json b/www/core/components/question/lang/pl.json index 6e060784dd2..1371ba6c9df 100644 --- a/www/core/components/question/lang/pl.json +++ b/www/core/components/question/lang/pl.json @@ -1,14 +1,14 @@ { - "answer": "Odpowiedz", + "answer": "Odpowiedź", "answersaved": "Odpowiedź zapisana", - "complete": "Pełna wersja", + "complete": "Zakończone", "correct": "Poprawnie", "feedback": "Informacja zwrotna", - "incorrect": "Niepoprawnie", + "incorrect": "Niepoprawny(a)", "information": "Informacja", "invalidanswer": "Niekompletna odpowiedź", - "notanswered": "Jeszcze nie udzielono odpowiedzi", - "notyetanswered": "Brak odpowiedzi", + "notanswered": "Nie udzielono odpowiedzi", + "notyetanswered": "Nie udzielono odpowiedzi", "partiallycorrect": "Częściowo poprawnie", "questionno": "Pytanie {{$a}}", "requiresgrading": "Wymaga oceny", diff --git a/www/core/components/question/lang/pt-br.json b/www/core/components/question/lang/pt-br.json index 4f7986546d1..99a33590a15 100644 --- a/www/core/components/question/lang/pt-br.json +++ b/www/core/components/question/lang/pt-br.json @@ -1,19 +1,19 @@ { "answer": "Resposta", "answersaved": "Resposta salva", - "complete": "Concluído", + "complete": "Completo", "correct": "Correto", "errorattachmentsnotsupported": "O aplicativo ainda não suporta anexar arquivos à resposta.", "errorinlinefilesnotsupported": "O aplicativo ainda não suporta a edição direta de arquivos.", "errorquestionnotsupported": "Esse tipo de questão não é suportada pelo aplicativo: {{$a}}.", - "feedback": "Comentários", + "feedback": "Feedback", "howtodraganddrop": "Toque para selecionar e então toque para soltar.", - "incorrect": "Errado", + "incorrect": "Incorreto", "information": "Informação", "invalidanswer": "Resposta incompleta", - "notanswered": "Nenhuma resposta", - "notyetanswered": "Ainda não respondeu", - "partiallycorrect": "Parcialmente correta", + "notanswered": "Não respondido", + "notyetanswered": "Ainda não respondida", + "partiallycorrect": "Parcialmente correto", "questionmessage": "Questão {{$a}}: {{$b}}", "questionno": "Questão {{$a}}", "requiresgrading": "Requer avaliação", diff --git a/www/core/components/question/lang/pt.json b/www/core/components/question/lang/pt.json index abe2dc4c3bd..f00329c4791 100644 --- a/www/core/components/question/lang/pt.json +++ b/www/core/components/question/lang/pt.json @@ -1,17 +1,17 @@ { "answer": "Resposta", "answersaved": "Resposta guardada", - "complete": "Completo", + "complete": "Respondida", "correct": "Correto", "errorattachmentsnotsupported": "A aplicação ainda não suporta anexar ficheiros a respostas.", "errorinlinefilesnotsupported": "A aplicação ainda não suporta a edição de ficheiros online.", "errorquestionnotsupported": "Este tipo de pergunta não é suportado pela aplicação: {{$a}}.", - "feedback": "Comentários", + "feedback": "Feedback", "howtodraganddrop": "Toque para selecionar e depois toque para largar.", "incorrect": "Incorreto", "information": "Informação", "invalidanswer": "Resposta incompleta", - "notanswered": "Ainda não respondeu", + "notanswered": "Não respondida", "notyetanswered": "Por responder", "partiallycorrect": "Parcialmente correto", "questionmessage": "Pergunta {{$a}}: {{$b}}", diff --git a/www/core/components/question/lang/ro.json b/www/core/components/question/lang/ro.json index a1bb7b725d9..f840f76f587 100644 --- a/www/core/components/question/lang/ro.json +++ b/www/core/components/question/lang/ro.json @@ -1,15 +1,15 @@ { - "answer": "Răspunde", + "answer": "Răspuns", "answersaved": "Răspuns salvat", - "complete": "Finalizează", + "complete": "Complet", "correct": "Corect", "feedback": "Feedback", "incorrect": "Incorect", "information": "Informații", "invalidanswer": "Răspuns incomplet", - "notanswered": "Nu a fost rezolvat încă", - "notyetanswered": "Incă nu s-a răspuns", - "partiallycorrect": "Parţial corect", + "notanswered": "Nu a primit răspuns", + "notyetanswered": "Nu a primit răspuns încă", + "partiallycorrect": "Parțial corect", "questionno": "Întrebare {{$a}}", "requiresgrading": "Trebuie să fie notată", "unknown": "Necunoscut" diff --git a/www/core/components/question/lang/ru.json b/www/core/components/question/lang/ru.json index 68d3259d734..fc2cd8ee320 100644 --- a/www/core/components/question/lang/ru.json +++ b/www/core/components/question/lang/ru.json @@ -1,15 +1,15 @@ { "answer": "Ответ", "answersaved": "Ответ сохранен", - "complete": "Завершено", + "complete": "Выполнен", "correct": "Верно", "feedback": "Отзыв", "incorrect": "Неверно", "information": "Информация", "invalidanswer": "Неполный ответ", - "notanswered": "Еще не ответили", + "notanswered": "Нет ответа", "notyetanswered": "Пока нет ответа", - "partiallycorrect": "Частично верно", + "partiallycorrect": "Частично правильный", "questionno": "Вопрос {{$a}}", "requiresgrading": "Требуется оценивание", "unknown": "неизвестно" diff --git a/www/core/components/question/lang/sr-cr.json b/www/core/components/question/lang/sr-cr.json new file mode 100644 index 00000000000..b541c6bb2fe --- /dev/null +++ b/www/core/components/question/lang/sr-cr.json @@ -0,0 +1,21 @@ +{ + "answer": "Одговор", + "answersaved": "Одговор је сачуван", + "complete": "Потпуно", + "correct": "Тачно", + "errorattachmentsnotsupported": "Апликација још увек не подржава могућност да се датотеке придруже уз одговоре.", + "errorinlinefilesnotsupported": "Апликација још увек не подржава уређивање унутар датотека.", + "errorquestionnotsupported": "Апликација не подржава овај тип питања: {{$a}}.", + "feedback": "Повратне информације", + "howtodraganddrop": "Додирните за избор, затим још једном за спуштање.", + "incorrect": "Нетачно", + "information": "Информација", + "invalidanswer": "Непотпун одговор", + "notanswered": "Још нису одговорили", + "notyetanswered": "Није још одговорено", + "partiallycorrect": "Делимично тачно", + "questionmessage": "Питање {{$a}}: {{$b}}", + "questionno": "Питање {{$a}}", + "requiresgrading": "Захтева оцењивање", + "unknown": "Није могуће утврдити статус" +} \ No newline at end of file diff --git a/www/core/components/question/lang/sr-lt.json b/www/core/components/question/lang/sr-lt.json new file mode 100644 index 00000000000..fe47446c308 --- /dev/null +++ b/www/core/components/question/lang/sr-lt.json @@ -0,0 +1,21 @@ +{ + "answer": "Odgovor", + "answersaved": "Odgovor je sačuvan", + "complete": "Potpuno", + "correct": "Tačno", + "errorattachmentsnotsupported": "Aplikacija još uvek ne podržava mogućnost da se datoteke pridruže uz odgovore.", + "errorinlinefilesnotsupported": "Aplikacija još uvek ne podržava uređivanje unutar datoteka.", + "errorquestionnotsupported": "Aplikacija ne podržava ovaj tip pitanja: {{$a}}.", + "feedback": "Povratne informacije", + "howtodraganddrop": "Dodirnite za izbor, zatim još jednom za spuštanje.", + "incorrect": "Netačno", + "information": "Informacija", + "invalidanswer": "Nepotpun odgovor", + "notanswered": "Još nisu odgovorili", + "notyetanswered": "Nije još odgovoreno", + "partiallycorrect": "Delimično tačno", + "questionmessage": "Pitanje {{$a}}: {{$b}}", + "questionno": "Pitanje {{$a}}", + "requiresgrading": "Zahteva ocenjivanje", + "unknown": "Nije moguće utvrditi status" +} \ No newline at end of file diff --git a/www/core/components/question/lang/sv.json b/www/core/components/question/lang/sv.json index c5026909e1f..9ef56c4f049 100644 --- a/www/core/components/question/lang/sv.json +++ b/www/core/components/question/lang/sv.json @@ -4,11 +4,11 @@ "complete": "Komplett", "correct": "Rätt", "feedback": "Återkoppling", - "incorrect": "Felaktigt", + "incorrect": "Felaktig", "information": "Information", "invalidanswer": "Ofullständigt svar", - "notanswered": "Inte ännu besvarad", - "notyetanswered": "Ännu inte besvarad", + "notanswered": "Ej besvarad", + "notyetanswered": "Inte besvarad än", "partiallycorrect": "Delvis korrekt", "questionno": "Fråga {{$a}}", "requiresgrading": "Kräver rättning", diff --git a/www/core/components/question/lang/tr.json b/www/core/components/question/lang/tr.json index 6de0e3edb23..08d1222bac0 100644 --- a/www/core/components/question/lang/tr.json +++ b/www/core/components/question/lang/tr.json @@ -1,14 +1,14 @@ { - "answer": "Yanıt", + "answer": "Cevap", "answersaved": "Cevap kaydedildi", - "complete": "Tamamlanmış", + "complete": "Tamamlandı", "correct": "Doğru", - "feedback": "Geri bildirim", + "feedback": "Geribildirim", "incorrect": "Yanlış", "information": "Bilgi", "invalidanswer": "Tamamlanmamış cevap", - "notanswered": "Henüz yanıtlanmadı", - "notyetanswered": "Henüz yanıtlanmamış", + "notanswered": "Cevaplanmadı", + "notyetanswered": "Henüz cevaplanmadı", "partiallycorrect": "Kısmen doğru", "questionno": "Soru {{$a}}", "requiresgrading": "Notlandırma gerekir", diff --git a/www/core/components/question/lang/uk.json b/www/core/components/question/lang/uk.json index 3ddcb4cabc4..f83c00f0b3f 100644 --- a/www/core/components/question/lang/uk.json +++ b/www/core/components/question/lang/uk.json @@ -5,13 +5,13 @@ "correct": "Правильно", "errorattachmentsnotsupported": "Додаток не підтримує прикріплення файлів відповідей", "errorinlinefilesnotsupported": "Додаток ще не підтримує редагування вбудованих файлів.", - "errorquestionnotsupported": "Цей тип питання не підтримує додатком: {{$a}}.", - "feedback": "Відгук", + "errorquestionnotsupported": "Цей тип питання не підтримується додатком: {{$a}}.", + "feedback": "Коментар", "howtodraganddrop": "Натисніть, щоб вибрати і перемістить.", "incorrect": "Неправильно", "information": "Інформація", "invalidanswer": "Неповна відповідь", - "notanswered": "Відповіді ще не було", + "notanswered": "Відповіді не було", "notyetanswered": "Відповіді ще не було", "partiallycorrect": "Частково правильно", "questionmessage": "Питання {{$a}}: {{$b}}", diff --git a/www/core/components/question/lang/zh-cn.json b/www/core/components/question/lang/zh-cn.json index b0c02c82632..5f50a21a566 100644 --- a/www/core/components/question/lang/zh-cn.json +++ b/www/core/components/question/lang/zh-cn.json @@ -1,14 +1,14 @@ { - "answer": "回答", + "answer": "答案", "answersaved": "答案已保存", - "complete": "完全", + "complete": "完成", "correct": "正确", "feedback": "反馈", - "incorrect": "错误", + "incorrect": "不正确", "information": "说明", "invalidanswer": "答案不完成", - "notanswered": "未答", - "notyetanswered": "仍未作答", + "notanswered": "未回答", + "notyetanswered": "还未回答", "partiallycorrect": "部分正确", "questionno": "题目{{$a}}", "requiresgrading": "需要评分", diff --git a/www/core/components/question/lang/zh-tw.json b/www/core/components/question/lang/zh-tw.json index 865bf62f773..f7fe56dce37 100644 --- a/www/core/components/question/lang/zh-tw.json +++ b/www/core/components/question/lang/zh-tw.json @@ -1,19 +1,19 @@ { - "answer": "回答", + "answer": "答案", "answersaved": "答案已儲存", - "complete": "完全", - "correct": "正確", + "complete": "完成", + "correct": "答對", "errorattachmentsnotsupported": "本應用程序尚不支援將檔案附加到答案.", "errorinlinefilesnotsupported": "該應用程序尚不支援線上檔案的編輯.", "errorquestionnotsupported": "該應用程式不支援此問題類型: {{$ a}}.", "feedback": "回饋", "howtodraganddrop": "點一下選擇, 然後再點一下刪除.", - "incorrect": "不正確", + "incorrect": "答錯", "information": "資訊", "invalidanswer": "不完整的答案", - "notanswered": "尚未回答", - "notyetanswered": "還沒被填答", - "partiallycorrect": "部分正確", + "notanswered": "沒被回答", + "notyetanswered": "尚未回答", + "partiallycorrect": "部分答對", "questionmessage": "問題 {{$a}}: {{$b}}", "questionno": "試題{{$a}}", "requiresgrading": "需要計分", diff --git a/www/core/components/settings/controllers/about.js b/www/core/components/settings/controllers/about.js index ec343459ea2..750f820d638 100644 --- a/www/core/components/settings/controllers/about.js +++ b/www/core/components/settings/controllers/about.js @@ -21,11 +21,11 @@ angular.module('mm.core.settings') * @ngdoc controller * @name mmSettingsAboutCtrl */ -.controller('mmSettingsAboutCtrl', function($scope, $translate, $window, $mmApp, $ionicPlatform, $mmLang, $mmFS, +.controller('mmSettingsAboutCtrl', function($scope, $window, $mmApp, $ionicPlatform, $mmLang, $mmFS, $mmLocalNotifications, mmCoreConfigConstants) { $scope.versionname = mmCoreConfigConstants.versionname; - $scope.appname = mmCoreConfigConstants.appname; + $scope.appname = $mmApp.isDesktop() ? mmCoreConfigConstants.desktopappname : mmCoreConfigConstants.appname; $scope.versioncode = mmCoreConfigConstants.versioncode; $scope.privacyPolicy = mmCoreConfigConstants.privacypolicy; diff --git a/www/core/components/settings/lang/ar.json b/www/core/components/settings/lang/ar.json index fae7dd88622..0f8555c7b08 100644 --- a/www/core/components/settings/lang/ar.json +++ b/www/core/components/settings/lang/ar.json @@ -6,25 +6,25 @@ "deviceinfo": "معلومات الجهاز", "deviceos": "نظام تشغيل الجهاز", "disableall": "تعطيل الإعلامات بشكل مؤقت", - "disabled": "مُعطِّل", + "disabled": "معطل", "enabledebugging": "تمكين التصحيح", "enabledownloadsection": "تفعيل تنزيل الأقسام", "enabledownloadsectiondescription": "عطل هذا الخيار لكي تسرع تحميل أقسام المنهج", "estimatedfreespace": "تقدير المساحة الحرة", - "general": "عام", + "general": "بيانات عامة", "language": "اللغة", "license": "رخصة", "localnotifavailable": "إشعارات محلية موجودة", "loggedin": "متواجد", "loggedoff": "غير موجود", - "settings": "إعدادات", + "settings": "الإعدادات", "sites": "المواقع", "spaceusage": "المساحة المستخدمة", "synchronization": "تزامن", "synchronizenow": "زامن الأن", "synchronizing": "يتم التزامن", "syncsettings": "إعدادات المزامنة", - "total": "مجموع", + "total": "المجموع", "versioncode": "رمز الإصدار", "versionname": "اسم الإصدار" } \ No newline at end of file diff --git a/www/core/components/settings/lang/bg.json b/www/core/components/settings/lang/bg.json index 9ac4a91d33b..4713f2eaf86 100644 --- a/www/core/components/settings/lang/bg.json +++ b/www/core/components/settings/lang/bg.json @@ -4,17 +4,17 @@ "currentlanguage": "Текущ език", "deletesitefiles": "Сигурни ли сте, че искате да изтриете изтеглените от този сайт файлове?", "disableall": "Временно отменяне на съобщенията", - "disabled": "Блокирано", + "disabled": "Забранено", "enabledebugging": "Позволяване на диагностициране", "errordeletesitefiles": "Грешка при изтриването на файловете на сайта.", "errorsyncsite": "Грешка при синхронизацията на данните от сайта. Моля проверете Вашата връзка към Интернет и опитайте пак.", "estimatedfreespace": "Пресметнато свободно пространство", - "general": "Общо", + "general": "General", "language": "Език", "license": "Лиценз", "loggedin": "Онлайн", "loggedoff": "Офлайн", - "settings": "Настройки на заданието", + "settings": "Настройки", "spaceusage": "Използване на пространство", "synchronization": "Синхронизиране", "synchronizing": "Синхронизиране", diff --git a/www/core/components/settings/lang/ca.json b/www/core/components/settings/lang/ca.json index 66977c70db9..a57b970ccac 100644 --- a/www/core/components/settings/lang/ca.json +++ b/www/core/components/settings/lang/ca.json @@ -18,7 +18,7 @@ "deviceos": "OS del dispositiu", "devicewebworkers": "És compatible amb Device Web Workers", "disableall": "Inhabilita les notificacions temporalment", - "disabled": "Inhabilitat", + "disabled": "La missatgeria està inhabilitada en aquest lloc", "displayformat": "Format de visualització", "enabledebugging": "Habilita la depuració", "enabledownloadsection": "Habilita la descàrrega de seccions", @@ -30,7 +30,7 @@ "errorsyncsite": "S'ha produït un error sincronitzant les dades del lloc, comproveu la vostra connexió a internet i torneu-ho provar.", "estimatedfreespace": "Espai lliure estimat", "filesystemroot": "Arrel del fitxer de sistema", - "general": "General", + "general": "Dades generals", "language": "Idioma", "license": "Llicència", "localnotifavailable": "Notificacions locals disponibles", @@ -42,7 +42,7 @@ "networkstatus": "Estat de la connexió a Internet", "privacypolicy": "Política de privadesa", "reportinbackground": "Informa dels errors automàticament", - "settings": "Configuració", + "settings": "Paràmetres", "sites": "Llocs", "spaceusage": "Utilització de l'espai", "storagetype": "Tipus d'emmagatzematge", diff --git a/www/core/components/settings/lang/cs.json b/www/core/components/settings/lang/cs.json index b9c0291c9ee..2d3d282ff2e 100644 --- a/www/core/components/settings/lang/cs.json +++ b/www/core/components/settings/lang/cs.json @@ -18,7 +18,7 @@ "deviceos": "OS zařízení", "devicewebworkers": "Podporovaný Web Workers zařízení", "disableall": "Zakázat upozornění", - "disabled": "Vypnuto", + "disabled": "Zakázáno", "displayformat": "Formát zobrazení", "enabledebugging": "Povolit ladící informace", "enabledownloadsection": "Povolit stahování sekcí", @@ -30,7 +30,7 @@ "errorsyncsite": "Chyba synchronizace dat stránek, zkontrolujte své připojení k internetu a zkuste to znovu.", "estimatedfreespace": "Odhadované volné místo", "filesystemroot": "Kořen souborového systému", - "general": "Obecná nastavení", + "general": "Obecně", "language": "Jazyk", "license": "Licence", "localnotifavailable": "Je dostupné lokání oznámení", @@ -43,7 +43,7 @@ "privacypolicy": "Zásady ochrany osobních údajů", "processorsettings": "Nastavení procesoru", "reportinbackground": "Zobrazovat chyby automaticky", - "settings": "Nastavení úkolu", + "settings": "Nastavení", "sites": "Stránky", "spaceusage": "Použitý prostor", "storagetype": "Typ paměti", diff --git a/www/core/components/settings/lang/da.json b/www/core/components/settings/lang/da.json index d2ec20f3074..1ac0fb41308 100644 --- a/www/core/components/settings/lang/da.json +++ b/www/core/components/settings/lang/da.json @@ -14,7 +14,7 @@ "deviceinfo": "Enhedsinfo", "deviceos": "Enheds operativsystem", "disableall": "Deaktiver notifikationer", - "disabled": "Beskedsystemet er deaktiveret", + "disabled": "Deaktiveret", "displayformat": "Vis format", "enabledebugging": "Aktiver fejlsøgning", "enablesyncwifi": "Tillad kun synkronisering når tilsluttet Wi-Fi", @@ -22,7 +22,7 @@ "errorsyncsite": "Fejl ved synkronisering. Kontroller din Internettilslutning og prøv igen.", "estimatedfreespace": "Beregnet ledig plads", "filesystemroot": "Filsystemets rod", - "general": "Generelt", + "general": "Generelle data", "language": "Sprog", "license": "Licens", "localnotifavailable": "Lokale meddelelser tilgængelige", @@ -32,8 +32,9 @@ "navigatorlanguage": "Navigatorsprog", "navigatoruseragent": "Navigator userAgent", "networkstatus": "Status for internetforbindelse", + "processorsettings": "Processorindstillinger", "reportinbackground": "Anmeld fejl automatisk", - "settings": "Opgaveindstillinger", + "settings": "Indstillinger", "sites": "Websteder", "spaceusage": "Pladsforbrug", "storagetype": "Lagertype", @@ -42,7 +43,7 @@ "synchronizing": "Synkroniserer", "syncsettings": "Indstilling for synkronisering", "syncsitesuccess": "Websidens data er synkroniseret og alle mellemlagre tømt", - "total": "Total", + "total": "Totalt", "versioncode": "Versionsnummer", "versionname": "Versionsnavn", "wificonnection": "WiFi-forbindelse" diff --git a/www/core/components/settings/lang/de.json b/www/core/components/settings/lang/de.json index dc12fbcf598..e02a3a9c1f1 100644 --- a/www/core/components/settings/lang/de.json +++ b/www/core/components/settings/lang/de.json @@ -1,10 +1,10 @@ { - "about": "Über diese App", + "about": "Über Moodle Mobile", "appready": "App nutzbar", "cacheexpirationtime": "Speicherdauer im Cache (Millisekunden)", "cannotsyncoffline": "Offline kann nicht synchronisiert werden.", - "cannotsyncwithoutwifi": "Die Daten wurden nicht synchronisiert, weil Ihre Einstellungen dies nur mit WLAN zulassen. Stellen Sie eine Verbindung zu einem WLAN her.", - "configuringnotifications": "Sie konfigurieren die Mitteilungen für '{{$a}}'.", + "cannotsyncwithoutwifi": "Die Daten wurden nicht synchronisiert, weil die Einstellungen dies nur mit WLAN zulassen. Stellen Sie eine WLAN-Verbindung her.", + "configuringnotifications": "Einstellungen für '{{$a}}'.", "cordovadevicemodel": "Cordova Device Model", "cordovadeviceosversion": "Cordova Device OS Version", "cordovadeviceplatform": "Cordova Device Platform", @@ -13,24 +13,24 @@ "credits": "Mitwirkende", "currentlanguage": "Eingestellte Sprache", "deletesitefiles": "Möchten Sie wirklich alle von der Website '{{sitename}}' geladenen Dateien löschen?", - "deletesitefilestitle": "Website-Dateien löschen", - "deviceinfo": "Geräteinfo", + "deletesitefilestitle": "Dateien löschen", + "deviceinfo": "Geräteinformationen", "deviceos": "Geräte-OS", "devicewebworkers": "Device Web Workers unterstützt", - "disableall": "Benachrichtungen ausschalten", - "disabled": "Deaktiviert", + "disableall": "Systemmitteilungen deaktivieren", + "disabled": "Die Mitteilungen sind für diese Website deaktiviert.", "displayformat": "Bildschirmformat", "enabledebugging": "Debugging aktivieren", "enabledownloadsection": "Herunterladen von Abschnitten aktivieren", - "enabledownloadsectiondescription": "Deaktivieren Sie diese Option, wenn das Laden von Kursabschnitten im Online-Modus zu lange dauert.", + "enabledownloadsectiondescription": "Deaktivieren Sie diese Option, wenn das Laden von Abschnitten im Online-Modus zu lange dauert.", "enablerichtexteditor": "Texteditor aktivieren", "enablerichtexteditordescription": "Wenn diese Option aktiviert ist, wird an passenden Stellen ein Texteditor angezeigt.", "enablesyncwifi": "Nur mit WLAN synchronierieren", - "errordeletesitefiles": "Fehler beim Löschen der Website-Dateien", + "errordeletesitefiles": "Fehler beim Löschen der Dateien", "errorsyncsite": "Fehler beim Synchronisieren der Website. Prüfen Sie die Verbindung und versuchen Sie es noch einmal.", "estimatedfreespace": "Noch verfügbarer Speicherplatz", "filesystemroot": "Dateisystem (root)", - "general": "Grundeinträge", + "general": "Allgemeines", "language": "Sprache", "license": "Lizenz", "localnotifavailable": "Lokale Mitteilungen verfügbar", @@ -40,7 +40,7 @@ "navigatorlanguage": "Browsersprache", "navigatoruseragent": "Browserkennung (userAgent)", "networkstatus": "Internetverbindung", - "privacypolicy": "Selbstständigkeitserklärung", + "privacypolicy": "Datenschutzerklärung", "processorsettings": "Verarbeitungseinstellungen", "reportinbackground": "Fehler automatisch senden", "settings": "Einstellungen", @@ -52,7 +52,7 @@ "synchronizing": "Synchronisieren ...", "syncsettings": "Synchronisieren", "syncsitesuccess": "Die Daten wurden synchronisiert.", - "total": "Insgesamt", + "total": "Gesamt", "versioncode": "Versionscode", "versionname": "Versionsname", "wificonnection": "WLAN-Verbindung" diff --git a/www/core/components/settings/lang/el.json b/www/core/components/settings/lang/el.json index ded142e065b..bb83893b28f 100644 --- a/www/core/components/settings/lang/el.json +++ b/www/core/components/settings/lang/el.json @@ -1,13 +1,58 @@ { + "about": "Σχετικά", + "appready": "Η εφαρμογή είναι έτοιμη", + "cacheexpirationtime": "Χρόνος λήξης της προσωρινής μνήμης (miliseconds)", + "cannotsyncoffline": "Δεν είναι δυνατός ο συγχρονισμός εκτός σύνδεσης.", + "cannotsyncwithoutwifi": "Δεν μπορεί να γίνει συγχρονισμός, επειδή οι τρέχουσες ρυθμίσεις επιτρέπουν μόνο συγχρονισμό όταν είστε συνδεδεμένοι με Wi-Fi. Συνδεθείτε με ένα δίκτυο Wi-Fi.", + "configuringnotifications": "Ρυθμίζετε τις '{{$a}}' ειδοποιήσεις.", + "cordovadevicemodel": "Μοντέλο συσκευής Cordova", + "cordovadeviceosversion": "Cordova έκδοση συσκευής OS", + "cordovadeviceplatform": "Πλατφόρμα συσκευής Cordova", + "cordovadeviceuuid": "Cordova Device uuid", + "cordovaversion": "Έκδοση Cordova", + "credits": "Credits", "currentlanguage": "Επιλεγμένη γλώσσα", + "deletesitefiles": "Είστε βέβαιοι ότι θέλετε να διαγράψετε τα ληφθέντα αρχεία από τον ιστότοπο '{{sitename}}';", + "deletesitefilestitle": "Διαγραφή αρχείων ιστότοπου", + "deviceinfo": "Πληροφορίες συσκευές", + "deviceos": "Λειτουργικό σύστημα συσκευής", + "devicewebworkers": "Υποστηρίζονται οι συσκευές Web Workers", "disableall": "Προσωρινή απενεργοποίηση ειδοποιήσεων", - "disabled": "Ανενεργό", - "general": "Γενικά", + "disabled": "Απενεργοποιημένο", + "displayformat": "Μορφή εμφάνισης", + "enabledebugging": "Ενεργοποίηση εντοπισμού σφαλμάτων", + "enabledownloadsection": "Ενεργοποιήστε τις ενότητες λήψης", + "enabledownloadsectiondescription": "Απενεργοποιήστε αυτήν την επιλογή για να επιταχύνετε τη φόρτωση των τμημάτων του μαθήματος.", + "enablerichtexteditor": "Ενεργοποιήστε τον επεξεργαστή εμπλουτισμένου κειμένου", + "enablerichtexteditordescription": "Εάν είναι ενεργοποιημένη, θα εμφανιστεί ένας επεξεργαστής εμπλουτισμένου κειμένου στα μέρη που το επιτρέπουν.", + "enablesyncwifi": "Να επιτρέπεται ο συγχρονισμός μόνο όταν είστε συνδεδεμένοι μέσω Wifi", + "errordeletesitefiles": "Σφάλμα κατά τη διαγραφή αρχείων ιστότοπου.", + "errorsyncsite": "Παρουσιάστηκε σφάλμα κατά το συγχρονισμό των δεδομένων ιστότοπου, ελέγξτε τη σύνδεση στο διαδίκτυο και δοκιμάστε ξανά.", + "estimatedfreespace": "Εκτιμώμενος ελεύθερος χώρος", + "filesystemroot": "Σύστημα αρχείων root", + "general": "Γενικά δεδομένα", "language": "Γλώσσα", "license": "Άδεια GPL", + "localnotifavailable": "Διαθέσιμες τοπικές ειδοποιήσεις", + "locationhref": "Webview URL", "loggedin": "Συνδεδεμένος", "loggedoff": "Μη συνδεδεμένος", + "navigatorlanguage": "Γλώσσα πλοήγησης", + "navigatoruseragent": "Navigator userAgent", + "networkstatus": "Κατάσταση σύνδεσης στο Internet", + "privacypolicy": "Πολιτική απορρήτου", + "reportinbackground": "Αυτόματη αναφορά σφαλμάτων", "settings": "Ρυθμίσεις", "sites": "Δικτυακοί τόποι", - "total": "Συνολικά" + "spaceusage": "Χρήση χώρου", + "storagetype": "Τύπος αποθήκευσης", + "synchronization": "Συγχρονισμός", + "synchronizenow": "Συγχρονίστε τώρα", + "synchronizing": "Γίνεται συγχρονισμός", + "syncsettings": "Ρυθμίσεις συγχρονισμού", + "syncsitesuccess": "Τα δεδομένα ιστότοπου συγχρονίστηκαν και όλες οι προσωρινές μνήμες ακυρώθηκαν.", + "total": "Συνολικό", + "versioncode": "Κωδικός έκδοσης", + "versionname": "Όνομα έκδοσης", + "wificonnection": "Σύνδεση WiFi" } \ No newline at end of file diff --git a/www/core/components/settings/lang/es-mx.json b/www/core/components/settings/lang/es-mx.json index 970bc7fb067..44e2c3879b8 100644 --- a/www/core/components/settings/lang/es-mx.json +++ b/www/core/components/settings/lang/es-mx.json @@ -18,7 +18,7 @@ "deviceos": "Sistema Operativo del dispositivo", "devicewebworkers": "Trabajadores Web del Dispositivo soportados", "disableall": "Deshabilitar notificaciones", - "disabled": "Deshabilitado", + "disabled": "La mensajería está deshabilitada en este sitio", "displayformat": "Mostrar formato", "enabledebugging": "Activar modo depuración (debug)", "enabledownloadsection": "Habilitar descargar secciones", @@ -30,7 +30,7 @@ "errorsyncsite": "Error al sincronizarlos datos del sitio; por favor revise su conexión de Internet e inténtelo de nuevo.", "estimatedfreespace": "Espacio libre estimado", "filesystemroot": "Raíz del sistema-de-archivos", - "general": "General", + "general": "Datos generales", "language": "Idioma", "license": "Licencia", "localnotifavailable": "Notificaciones locales disponibles", @@ -43,7 +43,7 @@ "privacypolicy": "Política de privacidad", "processorsettings": "Configuraciones de procesador", "reportinbackground": "Reportar errores automáticamente", - "settings": "Configuración", + "settings": "Parámetros de la tarea", "sites": "Sitios", "spaceusage": "Espacio", "storagetype": "Tipo de almacenamiento", diff --git a/www/core/components/settings/lang/es.json b/www/core/components/settings/lang/es.json index f26bc88eda5..7d88421e720 100644 --- a/www/core/components/settings/lang/es.json +++ b/www/core/components/settings/lang/es.json @@ -18,7 +18,7 @@ "deviceos": "OS del dispositivo", "devicewebworkers": "Soporta Device Web Workers", "disableall": "Desactivar temporalmente las notificaciones", - "disabled": "Deshabilitado", + "disabled": "Desactivado", "displayformat": "Formato de visualización", "enabledebugging": "Activar modo debug", "enabledownloadsection": "Habilitar la descarga de secciones", @@ -30,7 +30,7 @@ "errorsyncsite": "Se ha producido un error sincronizando los datos del sitio, por favor compruebe su conexión a internet y pruebe de nuevo.", "estimatedfreespace": "Espacio libre (estimado)", "filesystemroot": "Raíz del sistema de archivos", - "general": "General", + "general": "Datos generales", "language": "Idioma", "license": "Licencia", "localnotifavailable": "Notificaciones locales disponibles", @@ -40,9 +40,10 @@ "navigatorlanguage": "Lenguaje del navegador", "navigatoruseragent": "Agente de usuario del navegador", "networkstatus": "Estado de la conexión a internet", + "privacypolicy": "Política de privacidad.", "processorsettings": "Ajustes de procesador", "reportinbackground": "Informar de los errores automáticamente", - "settings": "Configuración", + "settings": "Parámetros de la tarea", "sites": "Sitios", "spaceusage": "Espacio", "storagetype": "Tipo de almacenamiento", diff --git a/www/core/components/settings/lang/es_mx.json b/www/core/components/settings/lang/es_mx.json deleted file mode 100644 index 5d713111ec6..00000000000 --- a/www/core/components/settings/lang/es_mx.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "about": "Acerca", - "cacheexpirationtime": "Tiempo de caducidad del caché (mili segundos)", - "deletesitefiles": "¿Está seguro de que desea borrar todos los archivos descargados de este sitio?", - "development": "Desarrollo", - "enabledebugging": "Activar modo depuración (debug)", - "estimatedfreespace": "Espacio libre (estimado)", - "general": "General", - "language": "Idioma", - "license": "Licencia", - "settings": "Ajustes", - "spaceusage": "Espacio", - "success": "Éxito", - "total": "Total" -} \ No newline at end of file diff --git a/www/core/components/settings/lang/eu.json b/www/core/components/settings/lang/eu.json index 15413f586dc..c63efde543b 100644 --- a/www/core/components/settings/lang/eu.json +++ b/www/core/components/settings/lang/eu.json @@ -18,7 +18,7 @@ "deviceos": "Gailuaren SEa", "devicewebworkers": "Device Web Workers onartuak", "disableall": "Desgaitu jakinarazpenak", - "disabled": "Mezularitza desgaituta dago gune honetan", + "disabled": "Desgaituta", "displayformat": "Erakusteko modua", "enabledebugging": "Gaitu arazketa", "enabledownloadsection": "Gaitu gaien deskarga", @@ -30,20 +30,20 @@ "errorsyncsite": "Errorea guneko datuak sinkronizatzean, mesedez egiaztatu zure interneterako konexioa eta saiatu berriz.", "estimatedfreespace": "Estimatutako leku librea", "filesystemroot": "Fitxategi-sistemaren jatorria", - "general": "Orokorra", + "general": "Datu orokorrak", "language": "Hizkuntza", "license": "Lizentzia", "localnotifavailable": "Jakinarazpen lokalak eskuragarri", "locationhref": "Webview URLa", "loggedin": "Online", - "loggedoff": "Ez dago online", + "loggedoff": "Lineaz kanpo", "navigatorlanguage": "Nabigatzailearen hizkuntza", "navigatoruseragent": "Nabigatzailearen userAgent-a", "networkstatus": "Internet konexioaren egoera", "privacypolicy": "Pribatutasun politika.", "processorsettings": "Prozesadorearen ezarpenak", "reportinbackground": "Erroreak automatikoki jakinarazi", - "settings": "Zereginaren ezarpenak", + "settings": "Ezarpenak", "sites": "Guneak", "spaceusage": "Lekuaren erabilera", "storagetype": "Biltegi mota", diff --git a/www/core/components/settings/lang/fa.json b/www/core/components/settings/lang/fa.json index b0048cdfb24..338c8808fb7 100644 --- a/www/core/components/settings/lang/fa.json +++ b/www/core/components/settings/lang/fa.json @@ -9,14 +9,14 @@ "deviceinfo": "اطلاعات دستگاه", "deviceos": "سیستم‌عامل دستگاه", "disableall": "غیرفعال‌کردن اطلاعیه‌ها", - "disabled": "غیر فعال", + "disabled": "غیر فعال شده است", "enabledebugging": "فعالسازی اشکالزدایی", "enabledownloadsection": "فعال‌کردن دریافت قسمت‌ها", "enabledownloadsectiondescription": "برای سریع‌تر شدن بارگیری قسمت‌های درس این گزینه را غیرفعال کنید.", "enablerichtexteditor": "فعال‌کردن ویرایشگر متنی پیشرفته", "enablerichtexteditordescription": "اگر فعال باشد، در جاهایی که ممکن باشد یک ویرایشگر متنی پیشرفته نمایش داده خواهد شد.", "estimatedfreespace": "فضای آزاد تخمینی", - "general": "عمومی", + "general": "داده‌های کلی", "language": "زبان", "license": "اجازه‌نامه", "loggedin": "هنگام بودن در سایت", @@ -24,7 +24,7 @@ "privacypolicy": "خط مشی حفظ حریم خصوصی", "processorsettings": "تنظیمات پردازشگر", "reportinbackground": "گزارش خطاها به‌صورت خودکار", - "settings": "تنظیمات تکلیف", + "settings": "تنظیمات", "sites": "سایت‌ها", "spaceusage": "فضای مورد استفاده", "synchronization": "هماهنگسازی", diff --git a/www/core/components/settings/lang/fr.json b/www/core/components/settings/lang/fr.json index 5346109b332..81af1469a83 100644 --- a/www/core/components/settings/lang/fr.json +++ b/www/core/components/settings/lang/fr.json @@ -18,7 +18,7 @@ "deviceos": "Système d'exploitation de l'appareil", "devicewebworkers": "Web workers supportés", "disableall": "Désactiver les notifications", - "disabled": "Désactivée", + "disabled": "Désactivé", "displayformat": "Format d'affichage", "enabledebugging": "Activer débogage", "enabledownloadsection": "Activer le téléchargement des sections", @@ -30,20 +30,20 @@ "errorsyncsite": "Erreur de synchronisation des données. Veuillez vérifier votre connexion internet et essayer plus tard.", "estimatedfreespace": "Espace libre estimé", "filesystemroot": "Racine du système de fichiers", - "general": "Général", + "general": "Généralités", "language": "Langue", "license": "Licence", "localnotifavailable": "Notifications locales disponibles", "locationhref": "URL webview", - "loggedin": "Connectés :", - "loggedoff": "Hors ligne", + "loggedin": "En ligne", + "loggedoff": "Hors ligne", "navigatorlanguage": "Langue du navigateur", "navigatoruseragent": "UserAgent du navigateur", "networkstatus": "Statut de la connexion internet", "privacypolicy": "Politique de confidentialité", "processorsettings": "Réglage du processus d'envoi de messages", "reportinbackground": "Annoncer les erreurs automatiquement", - "settings": "Paramètres", + "settings": "Réglages", "sites": "Sites", "spaceusage": "Espace utilisé", "storagetype": "Type de stockage", diff --git a/www/core/components/settings/lang/he.json b/www/core/components/settings/lang/he.json index 85b2267e3b5..4b431f585e1 100644 --- a/www/core/components/settings/lang/he.json +++ b/www/core/components/settings/lang/he.json @@ -8,28 +8,28 @@ "deviceinfo": "מידע אודות המכשיר", "deviceos": "מערכת הפעלה של המכשיר", "disableall": "הודעות־מערכת כבויות זמנית", - "disabled": "לא זמין", + "disabled": "כבוי", "displayformat": "תבנית תצוגה", "enabledebugging": "הפעל ניפוי שגיאות", "errordeletesitefiles": "שגיאה במחיקת קבצי האתר.", "errorsyncsite": "שגיאה בסנכרון מידע האתר, אנא בדוק את החיבור לרשת האינטרנט ונסה שוב.", "estimatedfreespace": "אומדן מקום פנוי", - "general": "כללי", + "general": "נתונים כללים", "language": "שפת ממשק", - "license": "רשיון", + "license": "רישיון:", "localnotifavailable": "התראות מקומיות זמינות", "loggedin": "מקוון", "loggedoff": "לא מקוון", "networkstatus": "מצב חיבור לרשת האינטרנט", "reportinbackground": "דיווח על שגיאות באופן אוטומטי", - "settings": "הגדרות המטלה", + "settings": "הגדרות", "sites": "אתרים", "spaceusage": "זיכרון בשימוש", "synchronization": "סינכרון", "synchronizenow": "סינכרון עכשיו", "synchronizing": "מסנכרן", "syncsitesuccess": "מידע האתר סונכרן וכל זיכרון המטמון אופס.", - "total": "סך הכל", + "total": "כולל", "versioncode": "קוד גרסה", "versionname": "שם גרסה", "wificonnection": "חיבור אלחוטי" diff --git a/www/core/components/settings/lang/hu.json b/www/core/components/settings/lang/hu.json index 3def7a650fc..dabf3467e9f 100644 --- a/www/core/components/settings/lang/hu.json +++ b/www/core/components/settings/lang/hu.json @@ -4,16 +4,16 @@ "currentlanguage": "Aktuális nyelv", "deletesitefiles": "Biztosan törli a portálról a letöltött fájlokat?", "disableall": "Értesítésekkikapcsolása", - "disabled": "Ezen a portálon az üzenetküldés ki van kapcsolva", + "disabled": "Kikapcsolva", "enabledebugging": "Hibakeresés bekapcsolása", "estimatedfreespace": "Becsült szabad tárhely", - "general": "Általános", + "general": "Általános adatok", "language": "Nyelv", - "license": "Licenc", + "license": "Engedély:", "loggedin": "Bejelentkezve:", "loggedoff": "Kijelentkezve", "processorsettings": "Feldolgozó beállításai", - "settings": "Feladat beállításai", + "settings": "Beállítások", "sites": "Portálok", "spaceusage": "Tárhelyhasználat", "synchronization": "Szinkronizálás", diff --git a/www/core/components/settings/lang/it.json b/www/core/components/settings/lang/it.json index 72440991f47..e659bf2f70e 100644 --- a/www/core/components/settings/lang/it.json +++ b/www/core/components/settings/lang/it.json @@ -15,7 +15,7 @@ "deviceos": "SO del dispositivo", "devicewebworkers": "Dispositivi Web Worker supportati", "disableall": "Disabilita le notifiche", - "disabled": "In questo sito il messaging è disabilitato", + "disabled": "Disabilitato", "displayformat": "Formato di visualizzazione", "enabledebugging": "Abilita debugging", "enabledownloadsection": "Abilita scaricamento sezioni", @@ -24,7 +24,7 @@ "errorsyncsite": "Si è verificato un errore durante la sincronizzazione dei dati dal sito. Per favore verifica la connessione internet e riprova.", "estimatedfreespace": "Spazio libero stimato", "filesystemroot": "Root del filesystem", - "general": "Generale", + "general": "Dati generali", "language": "Lingua", "license": "Licenza", "localnotifavailable": "Notifiche locali disponibili", @@ -36,7 +36,7 @@ "networkstatus": "Stato della connessione internet", "processorsettings": "Impostazioni gestore", "reportinbackground": "Invia errori automaticamente", - "settings": "Impostazioni compito", + "settings": "Impostazioni", "sites": "Siti", "spaceusage": "Spazio utilizzato", "storagetype": "Tipo di storage", diff --git a/www/core/components/settings/lang/ja.json b/www/core/components/settings/lang/ja.json index b410de256b4..d5905770aad 100644 --- a/www/core/components/settings/lang/ja.json +++ b/www/core/components/settings/lang/ja.json @@ -4,16 +4,16 @@ "currentlanguage": "現在の言語", "deletesitefiles": "本当にこのサイトからダウンロードしたファイルを消去しますか?", "disableall": "通知を無効にする", - "disabled": "無効", + "disabled": "このサイトではメッセージングが無効にされています。", "enabledebugging": "デバッグを有効にする", "estimatedfreespace": "概算の空き容量", - "general": "一般", + "general": "一般設定", "language": "言語設定", "license": "ライセンス", "loggedin": "オンライン", "loggedoff": "オフライン", "processorsettings": "プロセッサ設定", - "settings": "課題設定", + "settings": "設定", "sites": "サイト", "spaceusage": "保存領域使用量", "synchronization": "同期", diff --git a/www/core/components/settings/lang/lt.json b/www/core/components/settings/lang/lt.json index d2474dd8a26..79f4bc7a512 100644 --- a/www/core/components/settings/lang/lt.json +++ b/www/core/components/settings/lang/lt.json @@ -18,7 +18,7 @@ "deviceos": "Įrenginio OS", "devicewebworkers": "Įrenginio palaikymas", "disableall": "Išjungti pranešimus", - "disabled": "Išjungtas", + "disabled": "Išjungta", "displayformat": "Rodyti formatą", "enabledebugging": "Leisti derinti", "enabledownloadsection": "Įgalinti sekciją parsiuntimą", @@ -30,7 +30,7 @@ "errorsyncsite": "Klaida sinchronizuojant svetainės duomenis, prašome patikrinti interneto ryšį ir pabandyti dar kartą.", "estimatedfreespace": "Laisva vieta", "filesystemroot": "Failų sistema pradžia", - "general": "Bendra", + "general": "Bendrieji duomenys", "language": "Kalba", "license": "Licencija", "localnotifavailable": "Prieinami vietos pranešimai", @@ -42,7 +42,7 @@ "networkstatus": "Interneto ryšio būsena", "processorsettings": "Procesoriaus nustatymai", "reportinbackground": "Automatiškai pranešti apie klaidas", - "settings": "Užduoties nuostatos", + "settings": "Parametrai", "sites": "Svetainės", "spaceusage": "Vietos naudojimas", "storagetype": "Atminties tipas", diff --git a/www/core/components/settings/lang/nl.json b/www/core/components/settings/lang/nl.json index 622189c6fe3..19bfb28d023 100644 --- a/www/core/components/settings/lang/nl.json +++ b/www/core/components/settings/lang/nl.json @@ -18,7 +18,7 @@ "deviceos": "Toestel OS", "devicewebworkers": "Ondersteunde Device Web Workers", "disableall": "Berichten uitschakelen", - "disabled": "De berichtenservice is uitgeschakeld op deze site", + "disabled": "Uitgeschakeld", "displayformat": "Schermformaat", "enabledebugging": "Foutopsporing inschakelen", "enabledownloadsection": "Downloadsecties inschakelen", @@ -30,7 +30,7 @@ "errorsyncsite": "Fout bij het synchroniseren van sitegegevens. Controleer je internetverbinding en probeer opnieuw.", "estimatedfreespace": "Geschatte vrije ruimte", "filesystemroot": "Root bestandssysteem", - "general": "Algemeen", + "general": "Algemene gegevens", "language": "Taal", "license": "Licentie", "localnotifavailable": "Lokale meldingen beschikbaar", @@ -43,7 +43,7 @@ "privacypolicy": "Privacy-beleid", "processorsettings": "Processor instellingen", "reportinbackground": "Fouten automatisch rapporteren", - "settings": "Opdracht instellingen", + "settings": "Instellingen", "sites": "Sites", "spaceusage": "Gebruikte ruimte", "storagetype": "Opslagtype", diff --git a/www/core/components/settings/lang/pl.json b/www/core/components/settings/lang/pl.json index 3fcc31d278d..dcb9cd0ddb3 100644 --- a/www/core/components/settings/lang/pl.json +++ b/www/core/components/settings/lang/pl.json @@ -3,17 +3,17 @@ "cacheexpirationtime": "Czas wygasania pamięci podręcznej (milisekundy)", "currentlanguage": "Aktualny język", "deletesitefiles": "Czy na pewno chcesz usunąć pliki pobrane z tej strony?", - "disableall": "Tymczasowo wyłącz powiadomienia", - "disabled": "Wyłączony", + "disableall": "Wyłącz powiadomienia", + "disabled": "Wyłączone", "enabledebugging": "Włącz debugowanie", "estimatedfreespace": "Szacowana wolna przestrzeń", - "general": "Ogólne", + "general": "Dane ogólne", "language": "Język", "license": "Licencja", "loggedin": "On-line", "loggedoff": "Nie zalogowany", - "settings": "Ustawienia zadania", + "settings": "Ustawienia", "sites": "Serwisy", "spaceusage": "Użyta przestrzeń", - "total": "Razem" + "total": "Ogólnie" } \ No newline at end of file diff --git a/www/core/components/settings/lang/pt-br.json b/www/core/components/settings/lang/pt-br.json index adf77cf5dfd..28da97a0787 100644 --- a/www/core/components/settings/lang/pt-br.json +++ b/www/core/components/settings/lang/pt-br.json @@ -18,7 +18,7 @@ "deviceos": "Dispositivo OS", "devicewebworkers": "Device Web Workers suportados", "disableall": "Desabilitar notificações", - "disabled": "Desativar", + "disabled": "Desabilitado", "displayformat": "Formato de exibição", "enabledebugging": "Ativar a depuração", "enabledownloadsection": "Ativar seções de download", @@ -30,7 +30,7 @@ "errorsyncsite": "Erro ao sincronizar os dados do site, por favor verifique sua conexão de internet e tente novamente.", "estimatedfreespace": "Espaço livre estimado", "filesystemroot": "Raiz do sistema de arquivos", - "general": "Geral", + "general": "Dados Gerais", "language": "Idioma", "license": "Licença", "localnotifavailable": "Notificações locais disponíveis", @@ -41,8 +41,9 @@ "navigatoruseragent": "Navegador userAgent", "networkstatus": "O status da conexão Internet", "privacypolicy": "Política de privacidade", + "processorsettings": "Configurações do processador", "reportinbackground": "Relatar erros automaticamente", - "settings": "Configurações da tarefa", + "settings": "Configurações", "sites": "Sites", "spaceusage": "Uso do espaço", "storagetype": "Tipo de armazenamento", diff --git a/www/core/components/settings/lang/pt.json b/www/core/components/settings/lang/pt.json index c9a0b3b0f7f..80e93eb0408 100644 --- a/www/core/components/settings/lang/pt.json +++ b/www/core/components/settings/lang/pt.json @@ -18,7 +18,7 @@ "deviceos": "Dispositivo OS", "devicewebworkers": "Device Web Workers suportados", "disableall": "Desativar notificações", - "disabled": "Desativar", + "disabled": "Desativado", "displayformat": "Formato de visualização", "enabledebugging": "Ativar a depuração", "enabledownloadsection": "Ativar secções de transferência", @@ -30,7 +30,7 @@ "errorsyncsite": "Erro ao sincronizar os dados do site, por favor verifique a sua ligação à internet e tente novamente.", "estimatedfreespace": "Espaço livre estimado", "filesystemroot": "Raíz do sistema de ficheiros", - "general": "Geral", + "general": "Dados gerais", "language": "Idioma", "license": "Licença", "localnotifavailable": "Notificações locais disponíveis", @@ -43,7 +43,7 @@ "privacypolicy": "Politica de privacidade", "processorsettings": "Configurações do processador", "reportinbackground": "Reportar erros automaticamente", - "settings": "Configurações", + "settings": "Configurações do trabalho", "sites": "Sites", "spaceusage": "Utilização do espaço", "storagetype": "Tipo de armazenamento", diff --git a/www/core/components/settings/lang/pt_br.json b/www/core/components/settings/lang/pt_br.json deleted file mode 100644 index e5f10026fb4..00000000000 --- a/www/core/components/settings/lang/pt_br.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "about": "Sobre", - "cacheexpirationtime": "Tempo de expiração do cache (milisegundos)", - "deletesitefiles": "Tem certeza que deseja deletar os arquivos baixados a partir deste site?", - "development": "Desenvolvimento", - "enabledebugging": "Ativar a depuração", - "estimatedfreespace": "Espaço livre estimado", - "general": "Geral", - "language": "Idioma", - "license": "Licença", - "settings": "Configurações", - "spaceusage": "Uso do espaço", - "success": "Sucesso", - "total": "Total" -} \ No newline at end of file diff --git a/www/core/components/settings/lang/ro.json b/www/core/components/settings/lang/ro.json index fb34938dfd3..c241401f584 100644 --- a/www/core/components/settings/lang/ro.json +++ b/www/core/components/settings/lang/ro.json @@ -15,7 +15,7 @@ "deviceos": "Sistemul de operare al dispozitivului", "devicewebworkers": "Web Workers este suportat pe dispozitiv", "disableall": "Dezactivați temporar notificările", - "disabled": "Schimbul de mesaje este dezactivat pe acest site", + "disabled": "Dezactivat", "displayformat": "Dimensiunea ecranului", "enabledebugging": "Activați modulul de depanare", "enabledownloadsection": "Activați secțiunile pentru descărcare", @@ -25,9 +25,9 @@ "errorsyncsite": "A apărut o eroare la sincronizarea datelor de pe site, verificați conexiunea la internet și încercați din nou.", "estimatedfreespace": "Spațiu liber estimat", "filesystemroot": "Rădăcina sistemului de fișiere", - "general": "General", + "general": "Informaţii generale", "language": "Limba", - "license": "Licenţă", + "license": "Licență", "localnotifavailable": "Notificările locale sunt disponibile", "locationhref": "URL", "loggedin": "On-line", @@ -36,7 +36,7 @@ "navigatoruseragent": "Navigator userAgent", "networkstatus": "Starea conexiunii la Internet", "reportinbackground": "Erorile se raportează automat", - "settings": "Setările sarcinii de lucru", + "settings": "Setări", "sites": "Site-uri", "spaceusage": "Spațiu utilizat", "storagetype": "Tipul stocării", diff --git a/www/core/components/settings/lang/ru.json b/www/core/components/settings/lang/ru.json index 28769d7118a..21d2ac333cf 100644 --- a/www/core/components/settings/lang/ru.json +++ b/www/core/components/settings/lang/ru.json @@ -6,8 +6,8 @@ "currentlanguage": "Выбранный язык", "deletesitefiles": "Вы уверены, что хотите удалить файлы, скачанные с сайта «{{sitename}}»?", "deletesitefilestitle": "Удалить файлы сайта", - "disableall": "Временно отключить уведомления", - "disabled": "Выключить", + "disableall": "Отключить уведомления", + "disabled": "Отключено", "enabledebugging": "Включить отладку", "enabledownloadsection": "Показать материалы, доступные для скачивания", "enablerichtexteditor": "Включить текстовый редактор", @@ -16,18 +16,19 @@ "errordeletesitefiles": "Ошибка при удалении файлов сайта", "errorsyncsite": "Ошибка синхронизации данных сайта. Проверьте интернет-соединение и повторите попытку.", "estimatedfreespace": "Ориентировочное свободное место", - "general": "Основные", + "general": "Общие", "language": "Язык", - "license": "Лицензия", + "license": "Лицензия:", "loggedin": "На сайте", "loggedoff": "Вне сайта", + "processorsettings": "Настройки способа доставки сообщений", "reportinbackground": "Автоматически оповещать об ошибках", - "settings": "Параметры задания", + "settings": "Настройки", "sites": "Сайты", "spaceusage": "Используемое пространство", "synchronization": "Синхронизация", "synchronizing": "Синхронизация", "syncsettings": "Настройки синхронизации", "syncsitesuccess": "Данные синхронизации сайта и все кэши недействительны.", - "total": "Итог" + "total": "Итого" } \ No newline at end of file diff --git a/www/core/components/settings/lang/sr-cr.json b/www/core/components/settings/lang/sr-cr.json new file mode 100644 index 00000000000..e7f83e5471d --- /dev/null +++ b/www/core/components/settings/lang/sr-cr.json @@ -0,0 +1,59 @@ +{ + "about": "О апликацији", + "appready": "Апликација спремна", + "cacheexpirationtime": "Време истека кеша (милисекунде)", + "cannotsyncoffline": "Офлајн синхронизација није могућа.", + "cannotsyncwithoutwifi": "Синхронизација није могућа зато што тренутна подешавања дозвољавају синхронизацију само када постоји веза са Wi-Fi мрежом. Повежите се на Wi-Fi мрежу.", + "configuringnotifications": "Конфигуришете '{{$a}}' обавештења.", + "cordovadevicemodel": "Модел Cordova уређаја", + "cordovadeviceosversion": "Верзија оперативног система Cordova уређаја", + "cordovadeviceplatform": "Платформа Cordova уређаја", + "cordovadeviceuuid": "UUID Cordova уређаја", + "cordovaversion": "Cordova верзија", + "credits": "Заслуге", + "currentlanguage": "Тренутно важећи језик", + "deletesitefiles": "Да ли сте сигурни да желите да обришете преузете датотеке са сајта '{{sitename}}'?", + "deletesitefilestitle": "Обриши датотеке сајта", + "deviceinfo": "Информације о уређају", + "deviceos": "Оперативни систем уређаја", + "devicewebworkers": "Web Workers уређаји подржани", + "disableall": "Онемогући обавештења", + "disabled": "Онемогућено", + "displayformat": "Формат приказа", + "enabledebugging": "Омогући отклањање грешака", + "enabledownloadsection": "Омогући преузимање секција.", + "enabledownloadsectiondescription": "Онемогућите ову опцију како бисте убрзали учитавање секција курса.", + "enablerichtexteditor": "Омогући обогаћени едитор текста", + "enablerichtexteditordescription": "Ако је ова опција укључена обогаћени едитор текста биће приказан на местима која то дозвољавају.", + "enablesyncwifi": "Дозволите синхронизацију само када сте повезани на Wi-Fi мрежу.", + "errordeletesitefiles": "Грешка приликом брисања датотека сајта.", + "errorsyncsite": "Грешка приликом синхронизације података сајта. Молимо, проверите вашу интернет везу и покушајте поново.", + "estimatedfreespace": "Процењени слободан простора", + "filesystemroot": "Основни директоријум система датотека", + "general": "Опште", + "language": "Језик", + "license": "Лиценца", + "localnotifavailable": "Локална обавештења доступна", + "locationhref": "Webview URL адреса", + "loggedin": "Онлајн", + "loggedoff": "Офлајн", + "navigatorlanguage": "Језик навигатора", + "navigatoruseragent": "Кориснички агент навигатора", + "networkstatus": "Статус инернет везе", + "privacypolicy": "Политика приватности", + "processorsettings": "Подешавања процесора", + "reportinbackground": "Пријави грешке аутоматски", + "settings": "Подешавања", + "sites": "Сајтови", + "spaceusage": "Искориштеност простора", + "storagetype": "Тип складишта", + "synchronization": "Синхронизација", + "synchronizenow": "Синхронизуј сада", + "synchronizing": "Синхронизовање", + "syncsettings": "Подешавања синхронизације", + "syncsitesuccess": "Подаци сајтa су синхронизовани и сав кеш је поништен.", + "total": "Укупно", + "versioncode": "Верзија кôда", + "versionname": "Назив верзије", + "wificonnection": "WiFi веза" +} \ No newline at end of file diff --git a/www/core/components/settings/lang/sr-lt.json b/www/core/components/settings/lang/sr-lt.json new file mode 100644 index 00000000000..d3fb7c76e35 --- /dev/null +++ b/www/core/components/settings/lang/sr-lt.json @@ -0,0 +1,59 @@ +{ + "about": "O aplikaciji", + "appready": "Aplikacija spremna", + "cacheexpirationtime": "Vreme isteka keša (milisekunde)", + "cannotsyncoffline": "Oflajn sinhronizacija nije moguća.", + "cannotsyncwithoutwifi": "Sinhronizacija nije moguća zato što trenutna podešavanja dozvoljavaju sinhronizaciju samo kada postoji veza sa Wi-Fi mrežom. Povežite se na Wi-Fi mrežu.", + "configuringnotifications": "Konfigurišete '{{$a}}' obaveštenja.", + "cordovadevicemodel": "Model Cordova uređaja", + "cordovadeviceosversion": "Verzija operativnog sistema Cordova uređaja", + "cordovadeviceplatform": "Platforma Cordova uređaja", + "cordovadeviceuuid": "UUID Cordova uređaja", + "cordovaversion": "Cordova verzija", + "credits": "Zasluge", + "currentlanguage": "Trenutno važeći jezik", + "deletesitefiles": "Da li ste sigurni da želite da obrišete preuzete datoteke sa sajta '{{sitename}}'?", + "deletesitefilestitle": "Obriši datoteke sajta", + "deviceinfo": "Informacija o uređaju", + "deviceos": "Operativni sistem uređaja", + "devicewebworkers": "Web Workers uređaji podržani", + "disableall": "Onemogući obaveštenja", + "disabled": "Onemogućeno", + "displayformat": "Format prikaza", + "enabledebugging": "Omogući otklanjanje grešaka", + "enabledownloadsection": "Omogući preuzimanje sekcija.", + "enabledownloadsectiondescription": "Onemogućite ovu opciju kako biste ubrzali učitavanje sekcija kursa.", + "enablerichtexteditor": "Omogući obogaćeni editor teksta", + "enablerichtexteditordescription": "Ako je ova opcija uključena obogaćeni editor teksta biće prikazan na mestima koja to dozvoljavaju.", + "enablesyncwifi": "Dozvolite sinhronizaciju samo kada ste povezani na Wi-Fi mrežu.", + "errordeletesitefiles": "Greška prilikom brisanja datoteka sajta.", + "errorsyncsite": "Greška prilikom sinhronizacije podataka sajta. Molimo, proverite vašu internet vezu i pokušajte ponovo.", + "estimatedfreespace": "Procenjeni slobodan prostora", + "filesystemroot": "Osnovni direktorijum sistema datoteka", + "general": "Opšte", + "language": "Jezik", + "license": "Licenca", + "localnotifavailable": "Lokalna obaveštenja dostupna", + "locationhref": "Webview URL adresa", + "loggedin": "Onlajn", + "loggedoff": "Oflajn", + "navigatorlanguage": "Jezik navigatora", + "navigatoruseragent": "Korisnički agent navigatora", + "networkstatus": "Status inernet veze", + "privacypolicy": "Politika privatnosti", + "processorsettings": "Podešavanja procesora", + "reportinbackground": "Prijavi greške automatski", + "settings": "Podešavanja", + "sites": "Sajtovi", + "spaceusage": "Iskorištenost prostora", + "storagetype": "Tip skladišta", + "synchronization": "Sinhronizacija", + "synchronizenow": "Sinhronizuj sada", + "synchronizing": "Sinhronizovanje", + "syncsettings": "Podešavanja sinhronizacije", + "syncsitesuccess": "Podaci sajta su sinhronizovani i sav keš je poništen.", + "total": "Ukupno", + "versioncode": "Verzija kôda", + "versionname": "Naziv verzije", + "wificonnection": "WiFi veza" +} \ No newline at end of file diff --git a/www/core/components/settings/lang/sv.json b/www/core/components/settings/lang/sv.json index 6e667ace444..9daf57979e3 100644 --- a/www/core/components/settings/lang/sv.json +++ b/www/core/components/settings/lang/sv.json @@ -14,8 +14,8 @@ "deviceinfo": "Info mobil enhet", "deviceos": "Mobil enhet operativsystem", "devicewebworkers": "Enheten stödjer Web Workers", - "disableall": "Tillfälligt inaktivera meddelanden", - "disabled": "Avaktiverat", + "disableall": "Tillfälligt inaktivera notiser", + "disabled": "Avaktiverad", "displayformat": "Visningsformat", "enabledebugging": "Aktivera felsökning", "enabledownloadsection": "Aktivera hämtning sektioner", @@ -25,7 +25,7 @@ "errorsyncsite": "Fel vid synkronisering. Kontrollera din Internetanslutning och försök igen", "estimatedfreespace": "Beräknad ledigt utrymme", "filesystemroot": "Filsystem root", - "general": "Allmänt", + "general": "Allmänna data", "language": "Språk", "license": "Licens", "localnotifavailable": "Lokala meddelanden tillgängliga", @@ -36,7 +36,7 @@ "navigatoruseragent": "", "networkstatus": "Status för Internetanslutning", "reportinbackground": "Rapportera fel per automatik", - "settings": "Inställningar för inlämningsuppgift", + "settings": "Inställningar", "sites": "Webbplatser", "spaceusage": "Utrymmesanvändning", "storagetype": "Lagringstyp", @@ -45,7 +45,7 @@ "synchronizing": "Synkronisera", "syncsettings": "Synkronisation inställningar", "syncsitesuccess": "Webbsidedata synkroniserades och alla cachar ogiltigförklarades", - "total": "Totalt", + "total": "Summa", "versioncode": "Version kod", "versionname": "Version namn", "wificonnection": "WiFi-anslutning" diff --git a/www/core/components/settings/lang/tr.json b/www/core/components/settings/lang/tr.json index c6f1ea3ec9b..efbef267550 100644 --- a/www/core/components/settings/lang/tr.json +++ b/www/core/components/settings/lang/tr.json @@ -4,16 +4,16 @@ "currentlanguage": "Geçerli dil", "deletesitefiles": "Bu siteden indirdiğiniz dosyaları silmek istediğinizden eminmisiniz?", "disableall": "Bildirimleri devre dışı bırak", - "disabled": "Devre dışı bırakıldı", + "disabled": "Mesajlaşma bu sitede etkinleştirilmemiş", "enabledebugging": "Hata ayıklamayı etkinleştir", "estimatedfreespace": "Tahmini boş alan", - "general": "Genel", + "general": "Genel veri", "language": "Dil", "license": "Lisans", "loggedin": "Çevrimiçi", "loggedoff": "Çevrim içi değil", "processorsettings": "İşlemci ayarları", - "settings": "Ödev ayarları", + "settings": "Ayarlar", "sites": "Siteler", "spaceusage": "Kullanılan alan", "synchronization": "Eşitleme", diff --git a/www/core/components/settings/lang/uk.json b/www/core/components/settings/lang/uk.json index b918ac439dc..52526da3482 100644 --- a/www/core/components/settings/lang/uk.json +++ b/www/core/components/settings/lang/uk.json @@ -1,11 +1,11 @@ { - "about": "Про", + "about": "Про додаток", "appready": "Додаток готовий", "cacheexpirationtime": "Час закінчення кеша (мілісекунди)", "cannotsyncoffline": "Неможливо синхронізувати в автономному режимі.", - "cannotsyncwithoutwifi": "Неможливо синхронізувати, так як поточні настройки тільки дозволяють синхронізувати при підключенні до Wi-Fi. Підключіться до мережі Wi-Fi.", - "configuringnotifications": "Ви налаштовуєте '{{$a}}' повідомлення.", - "cordovadevicemodel": "Модель пристрою Кордова", + "cannotsyncwithoutwifi": "Неможливо синхронізувати, так як поточні налаштування тільки дозволяють синхронізуватись при підключенні до Wi-Fi. Підключіться до мережі Wi-Fi.", + "configuringnotifications": "Ви налаштовуєте '{{$a}}' сповіщення.", + "cordovadevicemodel": "Модель пристрою Cordova", "cordovadeviceosversion": "Cordova Device OS version", "cordovadeviceplatform": "Cordova Device platform", "cordovadeviceuuid": "Cordova Device uuid", @@ -18,31 +18,31 @@ "deviceos": "ОС пристрою", "devicewebworkers": "Device Web Workers підтримується", "disableall": "Тимчасово заборонити повідомлення", - "disabled": "Повідомлення заборонені на цьому сайті", + "disabled": "Відключено", "displayformat": "Формат відображення", "enabledebugging": "Включити відладку", "enabledownloadsection": "Увімкнути секцію завантаження", "enabledownloadsectiondescription": "Вимкніть цей параметр, щоб прискорити завантаження курсу секцій.", "enablerichtexteditor": "Включити редактор тексту", - "enablerichtexteditordescription": "Якщо цей параметр включений, розширений текстовий редактор буде показаний в тих місцях, які дозволяють їй.", - "enablesyncwifi": "Дозволити синхронізацію тільки тоді, коли на Wi-Fi", + "enablerichtexteditordescription": "Якщо цей параметр включений, розширений текстовий редактор буде показаний в тих місцях, які дозволяють це.", + "enablesyncwifi": "Тільки Wi-Fi синхронізація", "errordeletesitefiles": "Помилка видалення файлів сайту", "errorsyncsite": "Помилка синхронізації даних сайту, будь ласка, перевірте підключення до Інтернету і спробуйте ще раз.", "estimatedfreespace": "Розрахунковий вільний простір", "filesystemroot": "Коренева файлова система", - "general": "Основне", + "general": "Загальний", "language": "Мова інтерфейсу", "license": "Ліцензія", - "localnotifavailable": "Локальні сповіщення доступні", + "localnotifavailable": "Доступні локальні сповіщення", "locationhref": "Webview URL", "loggedin": "В мережі", "loggedoff": "Поза мережею", "navigatorlanguage": "Мова навігації", - "navigatoruseragent": "Navigator userAgent", - "networkstatus": "Статут інтернет з'єднання", + "navigatoruseragent": "Навігаційний userAgent", + "networkstatus": "Статус інтернет з'єднання", "privacypolicy": "Політика конфіденційності", "reportinbackground": "Відправляти помилки автоматично", - "settings": "Параметри завдання", + "settings": "Налаштування", "sites": "Сайти", "spaceusage": "Використане місце", "storagetype": "Тип сховища", @@ -51,7 +51,7 @@ "synchronizing": "Синхронізація", "syncsettings": "Налаштування синхронізації", "syncsitesuccess": "Дані сайту синхронізовані і всі кеші визнані недійсними.", - "total": "Підсумок", + "total": "Всього", "versioncode": "Версія коду", "versionname": "Ім'я версії", "wificonnection": "WiFi з'єднання" diff --git a/www/core/components/settings/lang/zh-cn.json b/www/core/components/settings/lang/zh-cn.json index 0ae3d4ba30e..01c03d8e577 100644 --- a/www/core/components/settings/lang/zh-cn.json +++ b/www/core/components/settings/lang/zh-cn.json @@ -4,17 +4,17 @@ "currentlanguage": "当前语言", "deletesitefiles": "您确定要删除从本站下载的文件?", "disableall": "临时禁用通知", - "disabled": "禁用", + "disabled": "不显示", "enabledebugging": "启用调试功能", "estimatedfreespace": "估计的可用空间", - "general": "常规项", + "general": "一般", "language": "语言", - "license": "许可证", + "license": "证书", "loggedin": "在线", "loggedoff": "离线", - "settings": "作业设置", + "settings": "设置", "sites": "网站", "spaceusage": "空间使用情况", "synchronization": "同步", - "total": "总计" + "total": "总分" } \ No newline at end of file diff --git a/www/core/components/settings/lang/zh-tw.json b/www/core/components/settings/lang/zh-tw.json index d63c5c6e165..0c793832389 100644 --- a/www/core/components/settings/lang/zh-tw.json +++ b/www/core/components/settings/lang/zh-tw.json @@ -18,7 +18,7 @@ "deviceos": "裝置作業系統", "devicewebworkers": "裝置網路工作站已支援", "disableall": "暫時關閉通知", - "disabled": "已關閉", + "disabled": "關閉", "displayformat": "顯示格式", "enabledebugging": "啟用除錯", "enabledownloadsection": "啟用下載區塊", @@ -30,9 +30,9 @@ "errorsyncsite": "同步網站資料時出錯, 請檢查您的網際網路連線, 然後重試.", "estimatedfreespace": "估計剩餘空間", "filesystemroot": "檔案系統根目錄", - "general": "一般", + "general": "一般的", "language": "語言", - "license": "授權條款", + "license": "授權方式", "localnotifavailable": "提供本端通知", "locationhref": "Webview網址", "loggedin": "線上", @@ -42,7 +42,7 @@ "networkstatus": "網際網路連線狀況", "processorsettings": "處理器的各項設定", "reportinbackground": "報表錯誤自動回報", - "settings": "作業設定", + "settings": "設定", "sites": "網站", "spaceusage": "使用空間", "storagetype": "儲存類型", @@ -51,7 +51,7 @@ "synchronizing": "同步中", "syncsettings": "同步設定", "syncsitesuccess": "網站資料同步與快取都無效", - "total": "總共", + "total": "總分", "versioncode": "版本碼", "versionname": "版本名稱", "wificonnection": "WiFi連線" diff --git a/www/core/components/settings/lang/zh_cn.json b/www/core/components/settings/lang/zh_cn.json deleted file mode 100644 index 77ecdafdca6..00000000000 --- a/www/core/components/settings/lang/zh_cn.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "about": "关于", - "cacheexpirationtime": "缓存过期时间(毫秒)", - "deletesitefiles": "您确定要删除从本站下载的文件?", - "development": "开发", - "enabledebugging": "启用调试功能", - "estimatedfreespace": "估计的可用空间", - "general": "常规", - "language": "语言", - "license": "许可", - "settings": "设置", - "spaceusage": "空间使用情况", - "success": "成功", - "total": "总共" -} \ No newline at end of file diff --git a/www/core/components/settings/lang/zh_tw.json b/www/core/components/settings/lang/zh_tw.json deleted file mode 100644 index 47eb50a9521..00000000000 --- a/www/core/components/settings/lang/zh_tw.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "about": "關於", - "cacheexpirationtime": "快取到期時間(毫秒)", - "deletesitefiles": "您確定您想由此位置刪除已下載檔案?", - "development": "開發", - "enabledebugging": "啟用除錯", - "estimatedfreespace": "估計尚餘空間", - "general": "一般", - "language": "語言", - "license": "授權", - "settings": "設定", - "spaceusage": "使用空間", - "success": "成功", - "total": "總計" -} \ No newline at end of file diff --git a/www/core/components/sharedfiles/lang/ar.json b/www/core/components/sharedfiles/lang/ar.json index 9f9e759ba0b..e56fb17f780 100644 --- a/www/core/components/sharedfiles/lang/ar.json +++ b/www/core/components/sharedfiles/lang/ar.json @@ -1,4 +1,4 @@ { - "rename": "تغيير الاسم", + "rename": "إعادة تسمية", "replace": "استبدال" } \ No newline at end of file diff --git a/www/core/components/sharedfiles/lang/de.json b/www/core/components/sharedfiles/lang/de.json index f682d1fb09c..0284aaba1ae 100644 --- a/www/core/components/sharedfiles/lang/de.json +++ b/www/core/components/sharedfiles/lang/de.json @@ -2,10 +2,10 @@ "chooseaccountstorefile": "Wählen Sie ein Nutzerkonto, um die Datei dort zu speichern.", "chooseactionrepeatedfile": "Eine Datei mit diesem Namen existiert bereits. Möchten Sie die vorhandene Datei ersetzen oder möchten Sie sie umbenennen in '{{$a}}'?", "errorreceivefilenosites": "Keine Websites gespeichert. Fügen Sie zuerst eine Website hinzu, bevor Sie eine Datei über die App freigeben.", - "nosharedfiles": "Keine freigegebenen Dateien für diese Website", - "nosharedfilestoupload": "Sie haben noch keine Dateien zum Hochladen freigegeben. Wenn Sie eine Datei aus einer anderen App hochladen möchten, suchen Sie diese Datei und tippen Sie auf die Taste 'Öffnen in'.", + "nosharedfiles": "Keine geteilten Dateien für diese Website", + "nosharedfilestoupload": "Sie haben hier noch keine Datei zum Hochladen. Wenn Sie eine Datei aus einer anderen App hochladen möchten, suchen Sie diese Datei und tippen Sie auf die Taste 'Öffnen in'.", "rename": "Umbenennen", "replace": "Ersetzen", - "sharedfiles": "Freigegebene Dateien", - "successstorefile": "Die Datei wurde gespeichert. Sie können die Datei verwenden, um Sie in 'Meine Dateien' hochzuladen oder bei Aktivitäten anzuhängen." + "sharedfiles": "Geteilte Dateien", + "successstorefile": "Die Datei wurde gespeichert. Sie können die Datei in den Bereich 'Meine Dateien' hochladen oder bei Aktivitäten anhängen." } \ No newline at end of file diff --git a/www/core/components/sharedfiles/lang/el.json b/www/core/components/sharedfiles/lang/el.json index 581cf18441d..d6eef40792d 100644 --- a/www/core/components/sharedfiles/lang/el.json +++ b/www/core/components/sharedfiles/lang/el.json @@ -1,4 +1,11 @@ { + "chooseaccountstorefile": "Επιλέξτε ένα λογαριασμό για να αποθηκεύσετε το αρχείο.", + "chooseactionrepeatedfile": "Υπάρχει ήδη ένα αρχείο με αυτό το όνομα. Θέλετε να αντικαταστήσετε το υπάρχον αρχείο ή να το μετονομάσετε σε \"{{$a}}\";", + "errorreceivefilenosites": "Δεν υπάρχουν αποθηκευμένες τοποθεσίες. Προσθέστε έναν ιστότοπο προτού μοιραστείτε ένα αρχείο με την εφαρμογή.", + "nosharedfiles": "Δεν υπάρχουν αποθηκευμένα αρχεία σε αυτόν τον ιστότοπο.", + "nosharedfilestoupload": "Δεν έχετε αρχεία για μεταφόρτωση εδώ. Αν θέλετε να μεταφορτώσετε ένα αρχείο από άλλη εφαρμογή, εντοπίστε το αρχείο και κάντε κλικ στο κουμπί \"Άνοιγμα σε\".", "rename": "Μετονομασία", - "replace": "Αντικατάσταση" + "replace": "Αντικατάσταση", + "sharedfiles": "Κοινόχρηστα αρχεία", + "successstorefile": "Το αρχείο αποθηκεύτηκε με επιτυχία. Τώρα μπορείτε να επιλέξετε αυτό το αρχείο για να το ανεβάσετε στα ιδιωτικά αρχεία σας ή να το επισυνάψετε σε ορισμένες δραστηριότητες." } \ No newline at end of file diff --git a/www/core/components/sharedfiles/lang/fr.json b/www/core/components/sharedfiles/lang/fr.json index 39b85fbf055..27784aa42fb 100644 --- a/www/core/components/sharedfiles/lang/fr.json +++ b/www/core/components/sharedfiles/lang/fr.json @@ -2,7 +2,7 @@ "chooseaccountstorefile": "Veuillez choisir un compte dans lequel enregistrer le fichier.", "chooseactionrepeatedfile": "Un fichier de ce nom existe déjà. Voulez-vous remplacer le fichier existant ou le renommer en « {{$a}} »?", "errorreceivefilenosites": "Aucun site n'est enregistré. Veuillez ajouter un site avant de partager un site avec l'app.", - "nosharedfiles": "Il n'y a pas de fichier partagés sur ce site.", + "nosharedfiles": "Il n'y a pas de fichier partagé sur ce site.", "nosharedfilestoupload": "Il n'y a pas de fichier à déposer ici. Si vous voulez déposer un fichier à partir d'une autre app, localiser le fichier et tapoter « Ouvrir dans ».", "rename": "Renommer", "replace": "Remplacer", diff --git a/www/core/components/sharedfiles/lang/it.json b/www/core/components/sharedfiles/lang/it.json index 875611dd996..81869805f8b 100644 --- a/www/core/components/sharedfiles/lang/it.json +++ b/www/core/components/sharedfiles/lang/it.json @@ -1,5 +1,5 @@ { - "rename": "Rinomina", + "rename": "Cambia il nome", "replace": "Sostituisci", "sharedfiles": "File condivisi" } \ No newline at end of file diff --git a/www/core/components/sharedfiles/lang/sr-cr.json b/www/core/components/sharedfiles/lang/sr-cr.json new file mode 100644 index 00000000000..3b9b852cf35 --- /dev/null +++ b/www/core/components/sharedfiles/lang/sr-cr.json @@ -0,0 +1,11 @@ +{ + "chooseaccountstorefile": "Изаберите налог за чување датотеке.", + "chooseactionrepeatedfile": "Већ постоји датотека са овим називом. Да ли желите да замените постојећу датотеку или да јој назив промените у \"{{$a}}\"?", + "errorreceivefilenosites": "Не постоје меморисани сајтови. Молимо, додајте сајт пре него што покушате да поделите датотеке са апликацијом.", + "nosharedfiles": "Не постоје дељене датотеке које се налазе на овом сајту.", + "nosharedfilestoupload": "Овде немате датотеке које можете да отпремите. Ако желите да отпремите датотеку из друге апликације, пронађите ту датотеку и кликните на дугме 'Отвори у'.", + "rename": "Промени назив", + "replace": "Замени", + "sharedfiles": "Дељене датотеке", + "successstorefile": "Датотека је успешно сачувана. Сада можете да изаберете ову датотеку да бисте је отпремили међу своје приватне датотеке или је придружили некој активности." +} \ No newline at end of file diff --git a/www/core/components/sharedfiles/lang/sr-lt.json b/www/core/components/sharedfiles/lang/sr-lt.json new file mode 100644 index 00000000000..796ef026796 --- /dev/null +++ b/www/core/components/sharedfiles/lang/sr-lt.json @@ -0,0 +1,11 @@ +{ + "chooseaccountstorefile": "Izaberite nalog za čuvanje datoteke.", + "chooseactionrepeatedfile": "Već postoji datoteka sa ovim nazivom. Da li želite da zamenite postojeću datoteku ili da joj naziv promenite u \"{{$a}}\"?", + "errorreceivefilenosites": "Ne postoje memorisani sajtovi. Molimo, dodajte sajt pre nego što pokušate da podelite datoteke sa aplikacijom.", + "nosharedfiles": "Ne postoje deljene datoteke koje se nalaze na ovom sajtu.", + "nosharedfilestoupload": "Ovde nemate datoteke koje možete da otpremite. Ako želite da otpremite datoteku iz druge aplikacije, pronađite tu datoteku i kliknite na dugme 'Otvori u'.", + "rename": "Promeni naziv", + "replace": "Zameni", + "sharedfiles": "Deljene datoteke", + "successstorefile": "Datoteka je uspešno sačuvana. Sada možete da izaberete ovu datoteku da biste je otpremili među svoje privatne datoteke ili je pridružili nekoj aktivnosti." +} \ No newline at end of file diff --git a/www/core/components/sharedfiles/lang/sv.json b/www/core/components/sharedfiles/lang/sv.json index 117af22281c..aa1e826c0b2 100644 --- a/www/core/components/sharedfiles/lang/sv.json +++ b/www/core/components/sharedfiles/lang/sv.json @@ -1,4 +1,4 @@ { - "rename": "Döp om", + "rename": "Ändra namn", "replace": "Byt ut" } \ No newline at end of file diff --git a/www/core/components/sidemenu/controllers/menu.js b/www/core/components/sidemenu/controllers/menu.js index 3edc382bd8c..c6cff4db0e0 100644 --- a/www/core/components/sidemenu/controllers/menu.js +++ b/www/core/components/sidemenu/controllers/menu.js @@ -67,6 +67,11 @@ angular.module('mm.core.sidemenu') } }); + // Required for Electron app so the title doesn't change. + $scope.$on('$ionicView.afterEnter', function(ev) { + ev.stopPropagation(); + }); + $scope.$on('$destroy', function() { if (langObserver && langObserver.off) { langObserver.off(); diff --git a/www/core/components/sidemenu/lang/ar.json b/www/core/components/sidemenu/lang/ar.json index 79a0f6adb0d..79c72d2c731 100644 --- a/www/core/components/sidemenu/lang/ar.json +++ b/www/core/components/sidemenu/lang/ar.json @@ -2,7 +2,7 @@ "appsettings": "إعدادات التطبيق", "changesite": "الخروج", "help": "مساعدة", - "logout": "خروج", - "mycourses": "مقرراتي الدراسية", + "logout": "الخروج", + "mycourses": "مقرراتي", "website": "الموقع" } \ No newline at end of file diff --git a/www/core/components/sidemenu/lang/de.json b/www/core/components/sidemenu/lang/de.json index 0ed4e3b6221..4f3285f040c 100644 --- a/www/core/components/sidemenu/lang/de.json +++ b/www/core/components/sidemenu/lang/de.json @@ -5,5 +5,5 @@ "logout": "Abmelden", "mycourses": "Meine Kurse", "togglemenu": "Menü umschalten", - "website": "Website" + "website": "Website im Browser" } \ No newline at end of file diff --git a/www/core/components/sidemenu/lang/el.json b/www/core/components/sidemenu/lang/el.json index 46aa4595112..2e0168f9e01 100644 --- a/www/core/components/sidemenu/lang/el.json +++ b/www/core/components/sidemenu/lang/el.json @@ -1,5 +1,9 @@ { + "appsettings": "Ρυθμίσεις εφαρμογής", + "changesite": "Αλλαγή ιστότοπου", "help": "Βοήθεια", - "logout": "Έξοδος", - "mycourses": "Τα μαθήματά μου" + "logout": "Αποσύνδεση", + "mycourses": "Τα μαθήματά μου", + "togglemenu": "Αλλαγή μενού", + "website": "Ιστότοπος" } \ No newline at end of file diff --git a/www/core/components/sidemenu/lang/es_mx.json b/www/core/components/sidemenu/lang/es_mx.json deleted file mode 100644 index eebe619eeba..00000000000 --- a/www/core/components/sidemenu/lang/es_mx.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "help": "Ayuda", - "changesite": "Salir", - "mycourses": "Mis cursos", - "website": "Página web" -} \ No newline at end of file diff --git a/www/core/components/sidemenu/lang/fa.json b/www/core/components/sidemenu/lang/fa.json index 7d4184a0d64..34bdcc7018f 100644 --- a/www/core/components/sidemenu/lang/fa.json +++ b/www/core/components/sidemenu/lang/fa.json @@ -1,8 +1,8 @@ { "appsettings": "تنظیمات برنامه", "changesite": "خروج", - "help": "راهنما", - "logout": "خروج", + "help": "راهنمایی", + "logout": "خروج از سایت", "mycourses": "درس‌های من", "website": "پایگاه اینترنتی" } \ No newline at end of file diff --git a/www/core/components/sidemenu/lang/pl.json b/www/core/components/sidemenu/lang/pl.json index db5b40a15cd..dc57d0910b1 100644 --- a/www/core/components/sidemenu/lang/pl.json +++ b/www/core/components/sidemenu/lang/pl.json @@ -1,7 +1,7 @@ { "changesite": "Wyloguj", "help": "Pomoc", - "logout": "Wyloguj", + "logout": "Wyloguj się", "mycourses": "Moje kursy", "website": "Witryna" } \ No newline at end of file diff --git a/www/core/components/sidemenu/lang/pt_br.json b/www/core/components/sidemenu/lang/pt_br.json deleted file mode 100644 index 63423de66e4..00000000000 --- a/www/core/components/sidemenu/lang/pt_br.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "help": "Ajuda", - "changesite": "Sair", - "mycourses": "Meus cursos", - "website": "Site" -} \ No newline at end of file diff --git a/www/core/components/sidemenu/lang/ro.json b/www/core/components/sidemenu/lang/ro.json index ea5d1d106e0..1c5f17d9e01 100644 --- a/www/core/components/sidemenu/lang/ro.json +++ b/www/core/components/sidemenu/lang/ro.json @@ -2,7 +2,7 @@ "appsettings": "Setările aplicației", "changesite": "Schimbați siteul", "help": "Ajutor", - "logout": "Schimbați siteul", + "logout": "Ieşire", "mycourses": "Cursurile mele", "togglemenu": "Meniul pentru comutare", "website": "Website" diff --git a/www/core/components/sidemenu/lang/sr-cr.json b/www/core/components/sidemenu/lang/sr-cr.json new file mode 100644 index 00000000000..8323e0aa5bd --- /dev/null +++ b/www/core/components/sidemenu/lang/sr-cr.json @@ -0,0 +1,9 @@ +{ + "appsettings": "Подешавања апликације", + "changesite": "Промени сајт", + "help": "Помоћ", + "logout": "Одјава", + "mycourses": "Моји курсеви", + "togglemenu": "Укључи/искључи мени", + "website": "Веб сајт" +} \ No newline at end of file diff --git a/www/core/components/sidemenu/lang/sr-lt.json b/www/core/components/sidemenu/lang/sr-lt.json new file mode 100644 index 00000000000..aa6e18a3722 --- /dev/null +++ b/www/core/components/sidemenu/lang/sr-lt.json @@ -0,0 +1,9 @@ +{ + "appsettings": "Podešavanja aplikacije", + "changesite": "Promeni sajt", + "help": "Pomoć", + "logout": "Odjava", + "mycourses": "Moji kursevi", + "togglemenu": "Uključi/isključi meni", + "website": "Veb sajt" +} \ No newline at end of file diff --git a/www/core/components/sidemenu/lang/zh_cn.json b/www/core/components/sidemenu/lang/zh_cn.json deleted file mode 100644 index d1edbf326e5..00000000000 --- a/www/core/components/sidemenu/lang/zh_cn.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "help": "帮助", - "changesite": "注销", - "mycourses": "我的课程", - "website": "网站" -} \ No newline at end of file diff --git a/www/core/components/sidemenu/lang/zh_tw.json b/www/core/components/sidemenu/lang/zh_tw.json deleted file mode 100644 index 6d6578b1638..00000000000 --- a/www/core/components/sidemenu/lang/zh_tw.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "help": "協助", - "changesite": "登出", - "mycourses": "我的課程", - "website": "網站" -} \ No newline at end of file diff --git a/www/core/components/sidemenu/scss/styles.scss b/www/core/components/sidemenu/scss/styles.scss index 5c03857bccd..bb3c1b5f97a 100644 --- a/www/core/components/sidemenu/scss/styles.scss +++ b/www/core/components/sidemenu/scss/styles.scss @@ -1,9 +1,3 @@ -// Variables. -$bar-side-menu-height: 80px !default; -$bar-side-menu-color: $bar-content-bg !default; -$bar-side-menu-border-color: $bar-content-border !default; -$bar-side-menu-text-color: $bar-content-text !default; - // Bar styles .bar-side-menu { @include bar-style($bar-side-menu-color, $bar-side-menu-border-color, $bar-side-menu-text-color); @@ -15,7 +9,8 @@ $bar-side-menu-text-color: $bar-content-text !default; .item-avatar { margin-top: 0px !important; // MOBILE-959: Added to fix side menu header in iOS. h2, - p { + p, + .icon { color: $bar-side-menu-text-color; } } @@ -30,3 +25,18 @@ $bar-side-menu-text-color: $bar-content-text !default; right: 16px; } } + +ion-side-menu li .item, +ion-side-menu li.item { + border-color: $bar-side-menu-item-border-color; + background-color: $bar-side-menu-item-background-color; + color: $bar-side-menu-item-text-color; + + .icon { + color: $bar-side-menu-item-icon-color; + } +} + +ion-side-menu li.item.item-divider { + background-color: $bar-side-menu-item-divider-color; +} \ No newline at end of file diff --git a/www/core/components/sidemenu/templates/menu.html b/www/core/components/sidemenu/templates/menu.html index f7acee79e28..3118087551f 100644 --- a/www/core/components/sidemenu/templates/menu.html +++ b/www/core/components/sidemenu/templates/menu.html @@ -40,7 +40,7 @@

{{siteinfo.fullname}}

  • - + {{item.label}} diff --git a/www/core/components/user/lang/ar.json b/www/core/components/user/lang/ar.json index ee88dd1fe2f..a22b70dffda 100644 --- a/www/core/components/user/lang/ar.json +++ b/www/core/components/user/lang/ar.json @@ -3,10 +3,10 @@ "city": "المدينة/البلدة", "contact": "جهة اتصال", "country": "الدولة", - "description": "الوصف", - "details": "تفاصيل متابعة اسكو", + "description": "نص المقدمة", + "details": "التفاصيل", "editingteacher": "معلم", - "email": "عنوان البريد الإلكتروني", + "email": "بريد الإلكتروني", "emailagain": "إعادة إدخال البريد الإلكتروني للتأكيد ", "firstname": "الاسم الأول", "interests": "اهتمامات", @@ -15,7 +15,7 @@ "manager": "مدير", "newpicture": "صورة شخصية جديدة", "phone1": "هاتف", - "phone2": "رقم الهاتف المحمول", + "phone2": "الجوال", "roles": "أدوار", "student": "طالب", "viewprofile": "عرض الحساب", diff --git a/www/core/components/user/lang/bg.json b/www/core/components/user/lang/bg.json index 6141ac3935c..022f6afb2b1 100644 --- a/www/core/components/user/lang/bg.json +++ b/www/core/components/user/lang/bg.json @@ -1,22 +1,22 @@ { "address": "Адрес", "city": "Град/село", - "contact": "Контакти", + "contact": "Контакт", "country": "Държава", - "description": "Въвеждащ текст", + "description": "Описание", "details": "Подробности", "detailsnotavailable": "Детайлите за този потребител не са достъпни за Вас.", "editingteacher": "Учител", - "email": "Имейл адрес", + "email": "Имейл", "emailagain": "Имейл адрес (отново)", "firstname": "Име", "interests": "Интереси", - "invaliduser": "Невалиден потребител.", + "invaliduser": "Невалиден потребител", "lastname": "Фамилия", "manager": "Мениждър", "newpicture": "Нова снимка", "phone1": "Телефон", - "phone2": "Мобилен", + "phone2": "Мобилен телефон", "roles": "Роли", "student": "Студент", "teacher": "Не-редактиращ учител", diff --git a/www/core/components/user/lang/ca.json b/www/core/components/user/lang/ca.json index 94d4813e716..fe01cc4b106 100644 --- a/www/core/components/user/lang/ca.json +++ b/www/core/components/user/lang/ca.json @@ -7,16 +7,16 @@ "details": "Detalls", "detailsnotavailable": "No tens accés als detalls d'aquest usuari.", "editingteacher": "Professor", - "email": "Adreça electrònica", + "email": "Correu electrònic", "emailagain": "Correu electrònic (una altra vegada)", "firstname": "Nom", "interests": "Interessos", "invaliduser": "L'usuari no és vàlid", "lastname": "Cognoms", "manager": "Gestor", - "newpicture": "Nova imatge", + "newpicture": "Imatge nova", "phone1": "Telèfon", - "phone2": "Mòbil", + "phone2": "Telèfon mòbil", "roles": "Rols", "sendemail": "Correu-e", "student": "Estudiant", diff --git a/www/core/components/user/lang/cs.json b/www/core/components/user/lang/cs.json index c0978326868..d6a2f04ff29 100644 --- a/www/core/components/user/lang/cs.json +++ b/www/core/components/user/lang/cs.json @@ -3,11 +3,11 @@ "city": "Město/obec", "contact": "Kontakt", "country": "Země", - "description": "Úvodní text", + "description": "Popis", "details": "Detaily", "detailsnotavailable": "Podrobnosti o tomto uživateli nejsou k dispozici.", "editingteacher": "Učitel", - "email": "E-mailová adresa", + "email": "Poslat e-mailem", "emailagain": "E-mail (znovu)", "firstname": "Křestní jméno", "interests": "Zájmy", diff --git a/www/core/components/user/lang/da.json b/www/core/components/user/lang/da.json index b55d48a20e1..934282c82cc 100644 --- a/www/core/components/user/lang/da.json +++ b/www/core/components/user/lang/da.json @@ -3,15 +3,15 @@ "city": "By", "contact": "Kontakt", "country": "Land", - "description": "Introduktionstekst", - "details": "Følg detaljer", + "description": "Beskrivelse", + "details": "Detaljer", "detailsnotavailable": "Denne brugers data er ikke tilgængelige for dig.", "editingteacher": "Lærer", - "email": "E-mailadresse", + "email": "E-mail", "emailagain": "E-mail (igen)", "firstname": "Fornavn", "interests": "Interesser", - "invaliduser": "Ugyldig bruger", + "invaliduser": "Ugyldig bruger.", "lastname": "Efternavn", "manager": "Manager", "newpicture": "Nyt billede", @@ -20,6 +20,6 @@ "roles": "Roller", "student": "Studerende", "teacher": "Medlærer", - "viewprofile": "Vis Profil", + "viewprofile": "Vis profil", "webpage": "Webside" } \ No newline at end of file diff --git a/www/core/components/user/lang/de.json b/www/core/components/user/lang/de.json index aaf288443b2..c5acfba8273 100644 --- a/www/core/components/user/lang/de.json +++ b/www/core/components/user/lang/de.json @@ -7,7 +7,7 @@ "details": "Details", "detailsnotavailable": "Die Nutzerdetails zu dieser Person sind für Sie nicht verfügbar.", "editingteacher": "Trainer/in", - "email": "E-Mail-Adresse", + "email": "E-Mail", "emailagain": "E-Mail (wiederholen)", "firstname": "Vorname", "interests": "Persönliche Interessen", diff --git a/www/core/components/user/lang/el.json b/www/core/components/user/lang/el.json index f041ebc81a0..b3f61aab273 100644 --- a/www/core/components/user/lang/el.json +++ b/www/core/components/user/lang/el.json @@ -1,20 +1,26 @@ { "address": "Διεύθυνση", "city": "Πόλη/χωριό", + "contact": "Επικοινωνία", "country": "Χώρα", - "description": "Κείμενο εισαγωγής", - "details": "Παρακολούθηση λεπτομερειών", - "email": "Διεύθυνση ηλεκτρονικού ταχυδρομείου", + "description": "Περιγραφή", + "details": "Λεπτομέρειες", + "detailsnotavailable": "Λεπτομέρειες για αυτό τον χρήστη δεν είναι διαθέσιμες.", + "editingteacher": "Διδάσκων", + "email": "Ηλεκτρονικό Ταχυδρομείο", "emailagain": "Email (ξανά)", "firstname": "Όνομα", "interests": "Ενδιαφέροντα", "invaliduser": "Μη έγκυρος χρήστης", "lastname": "Επώνυμο", + "manager": "Διαχειριστής", "newpicture": "Νέα εικόνα", "phone1": "Τηλέφωνο", - "phone2": "Κινητό τηλέφωνο", + "phone2": "Κινητό", "roles": "Ρόλοι", - "student": "Φοιτητής", + "sendemail": "Email", + "student": "Μαθητής", + "teacher": "Διδάσκων χωρίς δικαιώματα αλλαγής", "viewprofile": "Επισκόπηση του προφίλ", "webpage": "Ιστοσελίδα" } \ No newline at end of file diff --git a/www/core/components/user/lang/es-mx.json b/www/core/components/user/lang/es-mx.json index f04ee84c54c..4a165259a1c 100644 --- a/www/core/components/user/lang/es-mx.json +++ b/www/core/components/user/lang/es-mx.json @@ -3,11 +3,11 @@ "city": "Ciudad", "contact": "Contacto", "country": "País", - "description": "Descripción -", + "description": "Descripción", "details": "Detalles", "detailsnotavailable": "Los detalles de este usuario no están disponibles para Usted.", "editingteacher": "Profesor", - "email": "Dirección Email", + "email": "Email", "emailagain": "Correo (de nuevo)", "firstname": "Nombre", "interests": "Intereses", @@ -16,7 +16,7 @@ "manager": "Mánager", "newpicture": "Imagen nueva", "phone1": "Teléfono", - "phone2": "Móvil", + "phone2": "Teléfono móvil", "roles": "Roles", "sendemail": "Email", "student": "Estudiante", diff --git a/www/core/components/user/lang/es.json b/www/core/components/user/lang/es.json index a57e113d551..42dfd84651d 100644 --- a/www/core/components/user/lang/es.json +++ b/www/core/components/user/lang/es.json @@ -7,7 +7,7 @@ "details": "Detalles", "detailsnotavailable": "No tiene acceso a los detalles de este usuario.", "editingteacher": "Profesor", - "email": "Dirección de correo", + "email": "Email", "emailagain": "Correo (de nuevo)", "firstname": "Nombre", "interests": "Intereses", @@ -18,6 +18,7 @@ "phone1": "Teléfono", "phone2": "Móvil", "roles": "Roles", + "sendemail": "Correo electrónico", "student": "Estudiante", "teacher": "Profesor sin permiso de edición", "viewprofile": "Ver perfil", diff --git a/www/core/components/user/lang/es_mx.json b/www/core/components/user/lang/es_mx.json deleted file mode 100644 index 3c101e861d8..00000000000 --- a/www/core/components/user/lang/es_mx.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "address": "Dirección", - "city": "Ciudad", - "contact": "Contacto", - "country": "País", - "description": "Descripción", - "details": "Detalles", - "email": "Email", - "interests": "Intereses", - "invaliduser": "Usuario no válido", - "manager": "Mánager", - "phone1": "Teléfono", - "phone2": "Móvil", - "roles": "Roles", - "student": "Estudiante", - "webpage": "Página web" -} \ No newline at end of file diff --git a/www/core/components/user/lang/eu.json b/www/core/components/user/lang/eu.json index 346af5911ec..c0d05d48750 100644 --- a/www/core/components/user/lang/eu.json +++ b/www/core/components/user/lang/eu.json @@ -2,12 +2,12 @@ "address": "Helbidea", "city": "Hiria/Herria", "contact": "Kontaktua", - "country": "Herria", + "country": "Herrialdea", "description": "Deskribapena", "details": "Xehetasunak", "detailsnotavailable": "Erabiltzaile honen xehetasunak ez daude zuretzat eskuragarri", "editingteacher": "Irakaslea", - "email": "E-posta helbidea", + "email": "E-posta", "emailagain": "E-posta (berriro)", "firstname": "Izena", "interests": "Interesguneak", diff --git a/www/core/components/user/lang/fa.json b/www/core/components/user/lang/fa.json index 23611349635..9980ecf4e7f 100644 --- a/www/core/components/user/lang/fa.json +++ b/www/core/components/user/lang/fa.json @@ -1,11 +1,11 @@ { "address": "آدرس", "city": "شهر/شهرک", - "contact": "مخاطب", + "contact": "تماس", "country": "کشور", - "description": "توضیح تکلیف", - "details": "جزئیات", - "email": "آدرس پست الکترونیک", + "description": "توصیف", + "details": "دنبال کردن جزئیات", + "email": "پست الکترونیک", "emailagain": "پست الکترونیک (دوباره)", "firstname": "نام", "interests": "علایق", @@ -13,7 +13,7 @@ "lastname": "نام خانوادگی", "newpicture": "عکس جدید", "phone1": "تلفن", - "phone2": "همراه", + "phone2": "تلفن همراه", "roles": "نقش‌ها", "student": "شاگرد", "viewprofile": "مشاهدهٔ صفحهٔ مشخصات فردی", diff --git a/www/core/components/user/lang/fr.json b/www/core/components/user/lang/fr.json index 75c5058d2bf..55ae03508ff 100644 --- a/www/core/components/user/lang/fr.json +++ b/www/core/components/user/lang/fr.json @@ -7,7 +7,7 @@ "details": "Détails", "detailsnotavailable": "Vous n'avez pas accès aux informations de cet utilisateur.", "editingteacher": "Enseignant", - "email": "Adresse de courriel", + "email": "Courriel", "emailagain": "Courriel (confirmation)", "firstname": "Prénom", "interests": "Centres d'intérêt", diff --git a/www/core/components/user/lang/he.json b/www/core/components/user/lang/he.json index a4891acf920..6eb90b319d2 100644 --- a/www/core/components/user/lang/he.json +++ b/www/core/components/user/lang/he.json @@ -1,22 +1,22 @@ { "address": "כתובת", "city": "ישוב", - "contact": "ליצירת קשר", + "contact": "צור קשר", "country": "ארץ", - "description": "תיאור", - "details": "דוח המעקב מפורט", + "description": "הנחיה למטלה", + "details": "פרטים", "detailsnotavailable": "פרטי משתמש זה אינם זמינים לך.", "editingteacher": "מרצה", - "email": "כתובת דואר אלקטרוני", + "email": "דוא\"ל", "emailagain": "דואר אלקטרוני (שוב)", "firstname": "שם פרטי", "interests": "תחומי עניין", - "invaliduser": "משתמש שגוי", + "invaliduser": "משתמש לא תקף.", "lastname": "שם משפחה", "manager": "מנהל", "newpicture": "תמונה חדשה", "phone1": "טלפון", - "phone2": "טלפון נייד", + "phone2": "סלולרי", "roles": "תפקידים", "student": "סטודנט", "teacher": "עוזר/ת הוראה", diff --git a/www/core/components/user/lang/hu.json b/www/core/components/user/lang/hu.json index de2880aacb9..ea3235ea2d0 100644 --- a/www/core/components/user/lang/hu.json +++ b/www/core/components/user/lang/hu.json @@ -3,9 +3,9 @@ "city": "Helység", "contact": "Kapcsolat", "country": "Ország", - "description": "Bevezető szöveg", + "description": "Leírás", "details": "SCO nyomon követésének részletei", - "email": "E-mail cím", + "email": "E-mail", "emailagain": "E-mail (ismét)", "firstname": "Keresztnév", "interests": "Érdeklődési kör", diff --git a/www/core/components/user/lang/it.json b/www/core/components/user/lang/it.json index bdbd8e8b4ec..8d2c83785c7 100644 --- a/www/core/components/user/lang/it.json +++ b/www/core/components/user/lang/it.json @@ -3,11 +3,11 @@ "city": "Città /Località", "contact": "Contatto", "country": "Nazione", - "description": "Commento", + "description": "Descrizione", "details": "Dettagli", "detailsnotavailable": "Non puoi visualizzare i dettagli di questo utente.", "editingteacher": "Docente", - "email": "Indirizzo email", + "email": "Email", "emailagain": "Indirizzo email (ripeti)", "firstname": "Nome", "interests": "Interessi", diff --git a/www/core/components/user/lang/ja.json b/www/core/components/user/lang/ja.json index ed89cc07550..7b191daf6d3 100644 --- a/www/core/components/user/lang/ja.json +++ b/www/core/components/user/lang/ja.json @@ -1,11 +1,11 @@ { "address": "住所", "city": "都道府県", - "contact": "連絡先", + "contact": "コンタクト", "country": "国", "description": "説明", - "details": "トラック詳細", - "email": "メールアドレス", + "details": "詳細", + "email": "メール", "emailagain": "メールアドレス (もう一度)", "firstname": "名", "interests": "興味のあること", diff --git a/www/core/components/user/lang/lt.json b/www/core/components/user/lang/lt.json index 794c12956b1..2f4a8565e55 100644 --- a/www/core/components/user/lang/lt.json +++ b/www/core/components/user/lang/lt.json @@ -3,11 +3,11 @@ "city": "Miestas / miestelis", "contact": "Kontaktai", "country": "Šalis", - "description": "Aprašas", + "description": "Įžangos tekstas", "details": "Detalės", "detailsnotavailable": "Šio vartotojo duomenys jums nepasiekiami.", "editingteacher": "Dėstytojas", - "email": "El. pašto adresas", + "email": "El. laiškas", "emailagain": "El. paštas (dar kartą)", "firstname": "Vardas", "interests": "Pomėgiai", @@ -16,7 +16,7 @@ "manager": "Valdytojas", "newpicture": "Naujas paveikslėlis", "phone1": "Telefonas", - "phone2": "Mobilus", + "phone2": "Mobilusis telefonas", "roles": "Vaidmenys", "student": "Besimokantysis", "teacher": "Neredaguojantis mokytojas", diff --git a/www/core/components/user/lang/nl.json b/www/core/components/user/lang/nl.json index 9e9b2898795..0ca1abf5ab6 100644 --- a/www/core/components/user/lang/nl.json +++ b/www/core/components/user/lang/nl.json @@ -3,11 +3,11 @@ "city": "Plaats", "contact": "Contact", "country": "Land", - "description": "Inleidende tekst", + "description": "Beschrijving", "details": "Details", "detailsnotavailable": "Je kunt de details voor deze gebruiker niet bekijken.", "editingteacher": "Leraar", - "email": "E-mailadres", + "email": "E-mail", "emailagain": "E-mail (nogmaals)", "firstname": "Voornaam", "interests": "Interesses", diff --git a/www/core/components/user/lang/pl.json b/www/core/components/user/lang/pl.json index 36dbf206198..e81808a5344 100644 --- a/www/core/components/user/lang/pl.json +++ b/www/core/components/user/lang/pl.json @@ -3,9 +3,9 @@ "city": "Miasto", "contact": "Połącz", "country": "Kraj", - "description": "Wstęp", + "description": "Opis", "details": "Szczegóły ścieżki", - "email": "E-mail", + "email": "e-mail", "emailagain": "E-mail (jeszcze raz)", "firstname": "Imię", "interests": "Zainteresowania", diff --git a/www/core/components/user/lang/pt-br.json b/www/core/components/user/lang/pt-br.json index 7ab46d831a7..acd7aa18a73 100644 --- a/www/core/components/user/lang/pt-br.json +++ b/www/core/components/user/lang/pt-br.json @@ -3,11 +3,11 @@ "city": "Cidade/Município", "contact": "Contato", "country": "País", - "description": "Texto do link", + "description": "Descrição", "details": "Detalhes", "detailsnotavailable": "Os detalhes desse usuário não estão disponíveis para você.", "editingteacher": "Professor", - "email": "Endereço de email", + "email": "Email", "emailagain": "Confirmar endereço de e-mail", "firstname": "Nome", "interests": "Interesses", @@ -16,7 +16,7 @@ "manager": "Gerente", "newpicture": "Nova imagem", "phone1": "Fone", - "phone2": "Celular", + "phone2": "Telefone celular", "roles": "Papéis", "sendemail": "Email", "student": "Estudante", diff --git a/www/core/components/user/lang/pt.json b/www/core/components/user/lang/pt.json index dd9f07a9a2c..21a6936bf0c 100644 --- a/www/core/components/user/lang/pt.json +++ b/www/core/components/user/lang/pt.json @@ -7,7 +7,7 @@ "details": "Detalhes", "detailsnotavailable": "Não tem acesso aos detalhes deste utilizador.", "editingteacher": "Professor", - "email": "Endereço de e-mail", + "email": "E-mail", "emailagain": "E-mail (novamente)", "firstname": "Nome", "interests": "Interesses", diff --git a/www/core/components/user/lang/pt_br.json b/www/core/components/user/lang/pt_br.json deleted file mode 100644 index 379cccabd73..00000000000 --- a/www/core/components/user/lang/pt_br.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "address": "Endereço", - "city": "Cidade", - "contact": "Contato", - "country": "País", - "description": "Descrição", - "details": "Detalhes", - "email": "Email", - "interests": "Interesses", - "invaliduser": "Usuário inválido", - "manager": "Gerente", - "phone1": "Telefone", - "phone2": "Celular", - "roles": "Papéis", - "student": "Estudante", - "webpage": "Página web" -} \ No newline at end of file diff --git a/www/core/components/user/lang/ro.json b/www/core/components/user/lang/ro.json index 5e7dcf168ec..b6929b4f310 100644 --- a/www/core/components/user/lang/ro.json +++ b/www/core/components/user/lang/ro.json @@ -3,22 +3,22 @@ "city": "Oraş/localitate", "contact": "Contact", "country": "Ţara", - "description": "Text introductiv", - "details": "Detalii", + "description": "Descriere", + "details": "Detalii înregistrare activitate", "detailsnotavailable": "Detaliile acestui utilizator nu vă sunt disponibile.", "editingteacher": "Profesor", - "email": "Adresă email", + "email": "Email", "emailagain": "Email (reintroduceţi)", "firstname": "Prenume", "interests": "Interese", - "invaliduser": "Utilizator necunoscut.", + "invaliduser": "Utilizator incorect", "lastname": "Nume", "manager": "Manager", "newpicture": "Imagine nouă", "phone1": "Telefon", "phone2": "Mobil", "roles": "Roluri", - "student": "Student", + "student": "Cursant", "teacher": "Profesor asistent", "viewprofile": "Vezi profilul", "webpage": "Pagină Web" diff --git a/www/core/components/user/lang/ru.json b/www/core/components/user/lang/ru.json index 33bd27a775e..0ded3856726 100644 --- a/www/core/components/user/lang/ru.json +++ b/www/core/components/user/lang/ru.json @@ -3,11 +3,11 @@ "city": "Город", "contact": "Контакты", "country": "Страна", - "description": "Вступление", + "description": "Описание", "details": "Подробнее", "detailsnotavailable": "Вам не доступны подробности этого пользователя", "editingteacher": "Учитель", - "email": "Адрес электронной почты", + "email": "Email", "emailagain": "Адрес электронной почты (еще раз)", "firstname": "Имя", "interests": "Интересы", diff --git a/www/core/components/user/lang/sr-cr.json b/www/core/components/user/lang/sr-cr.json new file mode 100644 index 00000000000..d9c657dc5ac --- /dev/null +++ b/www/core/components/user/lang/sr-cr.json @@ -0,0 +1,26 @@ +{ + "address": "Адреса", + "city": "Место", + "contact": "Контакт", + "country": "Држава", + "description": "Опис", + "details": "Подаци о кориснику", + "detailsnotavailable": "Подаци о овом кориснику вам нису доступни.", + "editingteacher": "Предавач", + "email": "Адреса е-поште", + "emailagain": "Адреса е-поште (поново)", + "firstname": "Име", + "interests": "Интересовања", + "invaliduser": "Неисправан корисник.", + "lastname": "Презиме", + "manager": "Менаџер", + "newpicture": "Нова слика", + "phone1": "Телефон", + "phone2": "Мобилни", + "roles": "Улоге", + "sendemail": "Е-пошта", + "student": "Полазник", + "teacher": "Предавач без уређивачких права", + "viewprofile": "Прегледај профил", + "webpage": "Веб страница" +} \ No newline at end of file diff --git a/www/core/components/user/lang/sr-lt.json b/www/core/components/user/lang/sr-lt.json new file mode 100644 index 00000000000..6f944737893 --- /dev/null +++ b/www/core/components/user/lang/sr-lt.json @@ -0,0 +1,26 @@ +{ + "address": "Adresa", + "city": "Mesto", + "contact": "Kontakt", + "country": "Država", + "description": "Opis", + "details": "Podaci o korisniku", + "detailsnotavailable": "Podaci o ovom korisniku vam nisu dostupni.", + "editingteacher": "Predavač", + "email": "Adresa e-pošte", + "emailagain": "Adresa e-pošte (ponovo)", + "firstname": "Ime", + "interests": "Interesovanja", + "invaliduser": "Neispravan korisnik.", + "lastname": "Prezime", + "manager": "Menadžer", + "newpicture": "Nova slika", + "phone1": "Telefon", + "phone2": "Mobilni", + "roles": "Uloge", + "sendemail": "E-pošta", + "student": "Polaznik", + "teacher": "Predavač bez uređivačkih prava", + "viewprofile": "Pregledaj profil", + "webpage": "Web stranica" +} \ No newline at end of file diff --git a/www/core/components/user/lang/sv.json b/www/core/components/user/lang/sv.json index 19f29bc1d7f..de1a0d62c87 100644 --- a/www/core/components/user/lang/sv.json +++ b/www/core/components/user/lang/sv.json @@ -3,11 +3,11 @@ "city": "Stad/ort", "contact": "Kontakt", "country": "Land", - "description": "Introduktion", + "description": "Beskrivning", "details": "Detaljer", "detailsnotavailable": "Detaljerna till denna användare är inte tillgängliga för dig.", "editingteacher": "Lärare", - "email": "E-postadress", + "email": "E-post", "emailagain": "E-post (igen)", "firstname": "Förnamn", "interests": "Intressen", diff --git a/www/core/components/user/lang/tr.json b/www/core/components/user/lang/tr.json index 7dc39a77eef..49ebb7e3098 100644 --- a/www/core/components/user/lang/tr.json +++ b/www/core/components/user/lang/tr.json @@ -3,10 +3,10 @@ "city": "Şehir", "contact": "Kişi", "country": "Ülke", - "description": "Tanıtım metni", + "description": "Açıklama", "details": "Detaylar", "editingteacher": "Öğretmen", - "email": "E-posta adresi", + "email": "E-posta", "emailagain": "E-posta (tekrar)", "firstname": "Adı", "interests": "İlgi alanları", @@ -15,7 +15,7 @@ "manager": "Yönetici", "newpicture": "Yeni resim", "phone1": "Telefon", - "phone2": "Mobil", + "phone2": "Cep telefonu", "roles": "Roller", "student": "Öğrenci", "teacher": "Düzenleme yetkisi olmayan öğretmen", diff --git a/www/core/components/user/lang/uk.json b/www/core/components/user/lang/uk.json index 4e829c3f276..dc4c1e7d015 100644 --- a/www/core/components/user/lang/uk.json +++ b/www/core/components/user/lang/uk.json @@ -3,11 +3,11 @@ "city": "Місто", "contact": "Контакт", "country": "Країна", - "description": "Текст вступу", + "description": "Опис", "details": "Деталі", "detailsnotavailable": "Деталі цього користувача вам не доступні", "editingteacher": "Вчитель", - "email": "Електронна пошта", + "email": "Ел.пошта", "emailagain": "Електронна пошта (повторно)", "firstname": "Ім'я", "interests": "Інтереси", diff --git a/www/core/components/user/lang/zh-cn.json b/www/core/components/user/lang/zh-cn.json index a1d49df5eb3..e87f7ac73ef 100644 --- a/www/core/components/user/lang/zh-cn.json +++ b/www/core/components/user/lang/zh-cn.json @@ -3,9 +3,9 @@ "city": "市/县", "contact": "联系方式", "country": "国家和地区", - "description": "简要描述", + "description": "描述", "details": "详情", - "email": "Email地址", + "email": "Email", "emailagain": "Email (重复)", "firstname": "名", "interests": "兴趣", diff --git a/www/core/components/user/lang/zh-tw.json b/www/core/components/user/lang/zh-tw.json index d54e254418d..36c566c489c 100644 --- a/www/core/components/user/lang/zh-tw.json +++ b/www/core/components/user/lang/zh-tw.json @@ -3,11 +3,11 @@ "city": "縣/市", "contact": "連絡人", "country": "國家", - "description": "簡介文字", + "description": "說明", "details": "明細", "detailsnotavailable": "這個使用者的詳細資料無法提供給您", "editingteacher": "教師", - "email": "電子郵件信箱", + "email": "電子郵件", "emailagain": "電子郵件(再次確認)", "firstname": "名字", "interests": "興趣", @@ -16,7 +16,7 @@ "manager": "管理者", "newpicture": "新照片", "phone1": "電話", - "phone2": "行動", + "phone2": "手機", "roles": "角色", "student": "學生", "teacher": "非編輯中的教師", diff --git a/www/core/components/user/lang/zh_cn.json b/www/core/components/user/lang/zh_cn.json deleted file mode 100644 index cd89bebc64e..00000000000 --- a/www/core/components/user/lang/zh_cn.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "address": "地址", - "city": "城市", - "contact": "联系方式", - "country": "国家", - "description": "描述", - "details": "详情", - "email": "Email", - "interests": "兴趣", - "invaliduser": "无效的用户", - "manager": "管理员", - "phone1": "电话", - "phone2": "手机", - "roles": "角色", - "student": "学生", - "webpage": "网页" -} \ No newline at end of file diff --git a/www/core/components/user/lang/zh_tw.json b/www/core/components/user/lang/zh_tw.json deleted file mode 100644 index 5a45095611c..00000000000 --- a/www/core/components/user/lang/zh_tw.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "address": "住址", - "city": "城市", - "contact": "連絡人", - "country": "國家", - "description": "描述", - "details": "明細", - "email": "電子郵件", - "interests": "興趣", - "invaliduser": "無效的用戶", - "manager": "管理員", - "phone1": "電話", - "phone2": "行動", - "roles": "角色", - "student": "學生", - "webpage": "網頁" -} \ No newline at end of file diff --git a/www/core/directives/chrono.js b/www/core/directives/chrono.js new file mode 100644 index 00000000000..12cedd17a31 --- /dev/null +++ b/www/core/directives/chrono.js @@ -0,0 +1,178 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.core') + +/** + * This directive shows a chronometer in format HH:MM:SS. + * + * @module mm.core + * @ngdoc directive + * @name mmChrono + * @description + * This directive shows a chronometer in format HH:MM:SS. + * + * If no startTime is provided, it will start at 00:00:00. If the startTime changes, the chrono + * will be resetted to the startTime (and it will keep running if it was already running). + * If an endTime is provided, the chrono will stop and call the onEnd function when that number of seconds is reached. + * E.g. if startTime=60000 and endTime=120000, the chrono will start at 00:01:00 and end when it reaches 00:02:00. + * + * This directive listens for scope events to start and stop the timer. All events accept an object as a parameter. + * If the chrono has an id, the events must pass an id in the param object. + * + * mm-chrono-start To start the chrono. + * mm-chrono-stop To stop the chrono, leaving the current value. + * mm-chrono-reset To stop and reset the chrono. If the chrono should play after reset, pass play=true. + * + * Example usage: + * + * + * Then the controller can send events like this: + * + * $scope.$broadcast('mm-chrono-reset', {id: 'mychrono', play: true}); + * + * @param {Number} [id] ID to identify the chrono. It's used when sending events to the chrono. + * @param {Number} [startTime] Number of milliseconds to put in the chrono before starting. Defaults to 0. + * @param {Number} [endTime] Number of milliseconds to stop the chrono. By default, never stop it. + * @param {Boolean} [autoPlay] True to start the chrono automatically right after creating it. + * @param {Function} [onEnd] Function called when the endTime is reached. + */ +.directive('mmChrono', function($interval) { + + /** + * Check if an event received belongs to the current chrono. + * + * @param {Object} scope Chrono's scope. + * @param {Object} data Data received by the event. + * @return {Boolean} True if this chrono, false otherwise. + */ + function isCurrentChrono(scope, data) { + if (!scope.id && (!data || !data.id)) { + // Neither the chrono or the event has ID, consider it's this chrono. + return true; + } else if (scope.id && data && data.id == scope.id) { + // IDs match, it's this chrono. + return true; + } + + return false; + } + + /** + * Reset the chrono, stopping it and setting it to startTime. + * + * @param {Object} scope Chrono's scope. + * @return {Void} + */ + function reset(scope) { + stop(scope); + scope.time = scope.startTime || 0; + } + + /** + * Start the chrono if it isn't running. + * + * @param {Object} scope Chrono's scope. + * @return {Void} + */ + function start(scope) { + if (scope.isRunning) { + // Already running. + return; + } + + var lastExecTime = Date.now(); + scope.isRunning = true; + + scope.interval = $interval(function() { + // Increase the chrono. + scope.time += Date.now() - lastExecTime; + lastExecTime = Date.now(); + + if (typeof scope.endTime != 'undefined' && scope.time > scope.endTime) { + // End time reached, stop the timer and call the end function. + stop(scope); + if (scope.onEnd) { + scope.onEnd(); + } + } + }, 200); + } + + /** + * Stop the chrono, leaving the same time it has. + * + * @param {Object} scope Chrono's scope. + * @return {Void} + */ + function stop(scope) { + scope.isRunning = false; + $interval.cancel(scope.interval); + } + + return { + restrict: 'E', + scope: { + id: '=?', + startTime: '=?', + endTime: '=?', + autoPlay: '=?', + onEnd: '&?' + }, + template: '{{ time / 1000 | mmSecondsToHMS }}', + link: function(scope) { + scope.time = scope.startTime || 0; + + // Listen for events to start, stop and reset. + scope.$on('mm-chrono-start', function (e, data) { + if (isCurrentChrono(scope, data)) { + start(scope); + } + }); + + scope.$on('mm-chrono-stop', function (e, data) { + if (isCurrentChrono(scope, data)) { + stop(scope); + } + }); + + scope.$on('mm-chrono-reset', function (e, data) { + if (isCurrentChrono(scope, data)) { + reset(scope); + if (data && data.play) { + start(scope); + } + } + }); + + // If start time changes, reset the chrono. + scope.$watch('startTime', function() { + var wasRunning = scope.isRunning; + reset(scope); + if (wasRunning) { + start(scope); + } + }); + + if (scope.autoPlay && scope.autoPlay !== 'false') { + // auto-play is true, start the chrono now. + start(scope); + } + + scope.$on('$destroy', function() { + stop(scope); + }); + } + }; +}); diff --git a/www/core/directives/file.js b/www/core/directives/file.js index e7f44d95d03..7b59ab12bf6 100644 --- a/www/core/directives/file.js +++ b/www/core/directives/file.js @@ -265,8 +265,8 @@ angular.module('mm.core') $mmFilepool.invalidateFileByUrl(siteId, fileUrl).finally(function() { scope.isDownloading = true; $mmFilepool.addToQueueByUrl(siteId, fileUrl, component, componentId, timeModified, - undefined, 0, scope.file).catch(function() { - $mmUtil.showErrorModal('mm.core.errordownloading', true); + undefined, 0, scope.file).catch(function(error) { + $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true); }); }); }); diff --git a/www/core/directives/formattext.js b/www/core/directives/formattext.js index 4c43b72edc3..9e1556e1f97 100644 --- a/www/core/directives/formattext.js +++ b/www/core/directives/formattext.js @@ -342,7 +342,7 @@ angular.module('mm.core') return; } - var data = JSON.parse(el.getAttribute('data-setup') || '{}'), + var data = JSON.parse(el.getAttribute('data-setup') || el.getAttribute('data-setup-lazy') || '{}'), youtubeId = data.techOrder && data.techOrder[0] && data.techOrder[0] == 'youtube' && data.sources && data.sources[0] && data.sources[0].src && youtubeGetId(data.sources[0].src); diff --git a/www/core/directives/link.js b/www/core/directives/link.js index 1edfb179a87..5c6bc32f62e 100644 --- a/www/core/directives/link.js +++ b/www/core/directives/link.js @@ -56,6 +56,7 @@ angular.module('mm.core') $mmUtil.scrollToElement(document, "#" + href + ", [name='" + href + "']"); } } else { + // It's an external link, we will open with browser. Check if we need to auto-login. if (!$mmSite.isLoggedIn()) { // Not logged in, cannot auto-login. @@ -64,23 +65,35 @@ angular.module('mm.core') } else { $mmUtil.openInBrowser(href); } - } else if (autoLogin == 'yes') { - if (inApp) { - $mmSite.openInAppWithAutoLogin(href); - } else { - $mmSite.openInBrowserWithAutoLogin(href); - } - } else if (autoLogin == 'no') { - if (inApp) { - $mmUtil.openInApp(href); - } else { - $mmUtil.openInBrowser(href); - } } else { - if (inApp) { - $mmSite.openInAppWithAutoLoginIfSameSite(href); + // Check if URL does not have any protocol, so it's a relative URL. + if (!$mmUtil.isAbsoluteURL(href)) { + // Add the site URL at the begining. + if (href.charAt(0) == '/') { + href = $mmSite.getURL() + href; + } else { + href = $mmSite.getURL() + '/' + href; + } + } + + if (autoLogin == 'yes') { + if (inApp) { + $mmSite.openInAppWithAutoLogin(href); + } else { + $mmSite.openInBrowserWithAutoLogin(href); + } + } else if (autoLogin == 'no') { + if (inApp) { + $mmUtil.openInApp(href); + } else { + $mmUtil.openInBrowser(href); + } } else { - $mmSite.openInBrowserWithAutoLoginIfSameSite(href); + if (inApp) { + $mmSite.openInAppWithAutoLoginIfSameSite(href); + } else { + $mmSite.openInBrowserWithAutoLoginIfSameSite(href); + } } } } diff --git a/www/core/directives/multipleselect.js b/www/core/directives/multipleselect.js index bd66d80f93e..0b93e7d2388 100644 --- a/www/core/directives/multipleselect.js +++ b/www/core/directives/multipleselect.js @@ -32,6 +32,7 @@ angular.module('mm.core') * @param {String} title Title and label of the selector. * @param {Array} options Options to be used in the selector. Each option must have a key and a value * property. Additionally selected property can be defined. + * @param {String} [name] Name for the input field if needed. * @param {String} [keyProperty="key"] Name of the key property of the option to be sent to the server. * @param {String} [valueProperty="value"] Name of the value property of the option to be shown, human readable. * @param {String} [selectedProperty="selected"] Name of the selected property that indicates if the option is selected. @@ -42,7 +43,8 @@ angular.module('mm.core') priority: 100, scope: { title: '@', - options: '=' + options: '=', + name: '@?' }, templateUrl: 'core/templates/multipleselect.html', link: function(scope, element, attrs) { @@ -54,6 +56,9 @@ angular.module('mm.core') scope.optionsRender = []; scope.selectedOptions = getSelectedOptionsText(); + if (scope.name) { + scope.selectedValues = getSelectedOptionsValues(); + } element.on('click', function(e) { e.preventDefault(); @@ -91,6 +96,9 @@ angular.module('mm.core') } }); scope.selectedOptions = getSelectedOptionsText(); + if (scope.name) { + scope.selectedValues = getSelectedOptionsValues(); + } scope.closeModal(); }; @@ -106,6 +114,17 @@ angular.module('mm.core') return selected.join(strSeparator); } + // Get string for selected options to be sent. + function getSelectedOptionsValues() { + var selected = scope.options.filter(function(option) { + return !!option[selectedProperty]; + }).map(function(option) { + return option[keyProperty]; + }); + + return selected.join('###'); + } + scope.closeModal = function(){ scope.modal.hide(); }; diff --git a/www/core/filters/secondstohms.js b/www/core/filters/secondstohms.js index 2649bdab51d..87bbecdf729 100644 --- a/www/core/filters/secondstohms.js +++ b/www/core/filters/secondstohms.js @@ -32,6 +32,9 @@ angular.module('mm.core') if (typeof seconds == 'undefined' || seconds < 0) { seconds = 0; + } else { + // Don't allow decimals. + seconds = Math.floor(seconds); } hours = Math.floor(seconds / mmCoreSecondsHour); diff --git a/www/core/lang/ar.json b/www/core/lang/ar.json index a16f56062b9..aae0e45feee 100644 --- a/www/core/lang/ar.json +++ b/www/core/lang/ar.json @@ -2,14 +2,14 @@ "allparticipants": "كل المشاركين", "areyousure": "هل انت متأكد؟", "back": "العودة", - "cancel": "إلغاء", + "cancel": "ألغي", "cannotconnect": "لا يمكن الاتصال: تحقق من أنك كتبت عنوان URL بشكل صحيح وأنك تستخدم موقع موودل 2.4 أو أحدث.", - "category": "التصنيف", + "category": "فئة", "choose": "اختر", "choosedots": "اختر...", "clicktohideshow": "انقر للطي أو التوسيع", - "close": "أغلق", - "comments": "تعليقاتك", + "close": "أغلاق النافذه", + "comments": "تعليقات", "commentscount": "التعليقات ({{$a}})", "completion-alt-auto-fail": "مكتمل (لم تحقق درحة النجاح)", "completion-alt-auto-n": "غير مكتمل", @@ -27,12 +27,12 @@ "decsep": ".", "delete": "حذف", "deleting": "حذف", - "description": "الوصف", + "description": "نص المقدمة", "done": "تم", "download": "تحميل", "downloading": "يتم التنزيل", - "edit": "حرر", - "error": "خطاء", + "edit": "تحرير", + "error": "حصل خطاء", "errordownloading": "خطأ عن تنزيل الملف", "filename": "اسم الملف", "folder": "مجلد", @@ -52,7 +52,7 @@ "loading": "يتم التحميل", "lostconnection": "فقدنا الاتصال تحتاج إلى إعادة الاتصال. المميز الخاص بك هو الآن غير صالح", "maxsizeandattachments": "الحجم الأقصى للملفات الجديدة: {{$a.size}}, أقصى عدد للمرفقات: {{$a.attachments}}", - "min": "الحد الأدنى", + "min": "أقل درجة", "mins": "دقائق", "mod_assign": "مهمة", "mod_assignment": "مهمة", @@ -77,14 +77,14 @@ "mod_workshop": "ورشة عمل", "moduleintro": "وصف", "mygroups": "مجموعاتي", - "name": "الاسم", + "name": "اسم", "networkerrormsg": "لم يتم تمكين الشبكة أو أنها لا تعمل.", "never": "مطلقاً", - "next": "التالي", + "next": "استمر", "no": "لا", "nocomments": "لا يوجد تعليقات", "nograde": "لا توجد درجة", - "none": "لا يوجد", + "none": "لا شئ", "nopasswordchangeforced": "لا يمكنك الاستمرار دون تغيير كلمة مرورك، لكن يبدو أنه لا يوجد صفحة متوفرة لتغييرها. رجاءً قم بالاتصال بمدير مودل.", "nopermissions": "عذراً ولكنك لا تملك حالياً الصلاحيات لتقوم بهذا ({{$a}})", "noresults": "لا توجد نتائج", @@ -99,29 +99,30 @@ "pictureof": "صورة {{$a}}", "previous": "السابق", "pulltorefresh": "اسحب للأسفل ليتم التحديث", - "refresh": "تحديث", - "required": "مفروض", + "refresh": "تنشيط", + "required": "مطلوب", "save": "حفظ", "search": "بحث", - "searching": "بحث في", + "searching": "يتم البحث", "searchresults": "نتائج البحث", "sec": "ثانية", "secs": "ثواني", "seemoredetail": "اضغط هنا لترى تفاصيل أكثر", - "send": "إرسل", + "send": "إرسال", "sending": "يتم الإرسال", "serverconnection": "خطأ في الاتصال بالخادم", - "show": "اظهر", + "show": "عرض", "site": "الموقع", "sizeb": "بايتز", "sizegb": "غيغابايت", "sizekb": "كيلو بايت", "sizemb": "ميغا بايب", + "sortby": "إفرز بـ", "start": "إبداء", - "submit": "سلم", + "submit": "سلم/قدم", "success": "نجاح", "teachers": "معلمون", - "time": "وقت", + "time": "الوقت", "timesup": "انتهى الوقت!", "today": "اليوم", "unexpectederror": "خطأ غير متوقع. الرجاء الإغلاق وإعادة فتح التطبيق للمحاولة مرة أخرى", @@ -131,7 +132,7 @@ "userdeleted": "تم حذف اشتراك هذا المستخدم", "userdetails": "تفاصيل المستخدم", "users": "المستخدمون", - "view": "معاينه", + "view": "استعراض", "viewprofile": "عرض الحساب", "year": "سنة", "years": "سنوات", diff --git a/www/core/lang/bg.json b/www/core/lang/bg.json index 1365af87752..76bce7bff1a 100644 --- a/www/core/lang/bg.json +++ b/www/core/lang/bg.json @@ -9,8 +9,8 @@ "choosedots": "Изберете...", "clearsearch": "Изчисти търсенето", "clicktohideshow": "Кликнете за да разгънете или свиете ", - "close": "Затваряне", - "comments": "Ваши коментари", + "close": "Затваряне на прозореца", + "comments": "Коментари", "commentscount": "Коментари ({{$a}})", "completion-alt-manual-n": "Не е завършена дейността: {{$a}}. Изберете я за да я отбележите за завършена.", "completion-alt-manual-y": "Завършена е дейността: {{$a}}. Изберете я за да я отбележите за незавършена.", @@ -21,16 +21,16 @@ "coursedetails": "Информация за курсове", "date": "Дата", "day": "ден", - "days": "дни", + "days": "Дена", "decsep": ",", "delete": "Изтриване", "deleting": "Изтриване", - "description": "Въвеждащ текст", + "description": "Описание", "done": "Извършено", "download": "Изтегляне", "downloading": "Изтегляне", "edit": "Редактиране", - "error": "Грешка", + "error": "Възникна непозната грешка!", "errordownloading": "Грешка при теглене на файл", "filename": "Име на файл", "folder": "Папка", @@ -49,7 +49,7 @@ "loading": "Зареждане", "lostconnection": "Изгубихме връзка и трябва да се свържете отново. Вашият ключ сега е невалиден.", "maxsizeandattachments": "Максимален размер за нови файлове: {{$a.size}}, максимален брой файлове: {{$a.attachments}}", - "min": "мин", + "min": "Най-ниска", "mins": "мин.", "mod_assign": "Задание", "mod_assignment": "Задание", @@ -80,11 +80,11 @@ "name": "Име", "networkerrormsg": "Мрежата не е разрешена или не работи", "never": "Никога", - "next": "Още", + "next": "Следващ", "no": "Не", "nocomments": "Няма коментари", - "nograde": "Без оценка", - "none": "Нищо", + "nograde": "Няма оценка.", + "none": "Няма", "nopasswordchangeforced": "Не можете да продължите без да се променили паролата, обаче няма налична страница за промяната и. Моля, свържете се с Вашия Moodle администратор.", "nopermissions": "За съжаление Вие нямате право да правите това ({{$a}})", "noresults": "Няма резултати", @@ -92,32 +92,33 @@ "notice": "Съобщене", "now": "сега", "numwords": "{{$a}} думи", - "offline": "Не се изисква предаване онлайн", + "offline": "Офлайн", "online": "Онлайн", "phone": "Телефон", "pictureof": "Снимка на {{$a}}", "previous": "Обратно", "pulltorefresh": "", "refresh": "Опресняване", - "required": "Задължително", - "save": "Запазване", + "required": "Задължителен", + "save": "Запис", "search": "Търсене", - "searching": "Търсене в", + "searching": "Търсене в ...", "searchresults": "Резултати от търсенето", "sec": "сек.", "secs": "сек.", "seemoredetail": "Щракнете тук за повече подробности", - "send": "изпращане", + "send": "Изпращане", "sending": "Изпраща се", - "show": "Да се вижда", + "show": "Показване", "site": "Сайт", "sizeb": "байта", "sizegb": "GB", "sizekb": "KB", "sizemb": "MB", "sizetb": "ТБ", + "sortby": "Нареждане по", "start": "Започване", - "submit": "Изпълняване", + "submit": "Качване", "success": "Успешно", "time": "Време", "timesup": "Времето изтече!", @@ -128,7 +129,7 @@ "userdeleted": "Тази потребителска регистрация е изтрита", "userdetails": "Информация за потребителя", "users": "Потребители", - "view": "Преглед", + "view": "Изглед", "viewprofile": "Разглеждане на профила", "whoops": "Опс!", "years": "години", diff --git a/www/core/lang/ca.json b/www/core/lang/ca.json index 3c4bb775308..21fd84a95a3 100644 --- a/www/core/lang/ca.json +++ b/www/core/lang/ca.json @@ -13,7 +13,7 @@ "clearsearch": "Neteja la cerca", "clicktohideshow": "Feu clic per ampliar o reduir", "clicktoseefull": "Cliqueu per veure el contingut complet.", - "close": "Tanca", + "close": "Tanca finestra", "comments": "Comentaris", "commentscount": "Comentaris ({{$a}})", "commentsnotworking": "No s'han pogut recuperar els comentaris", @@ -36,8 +36,8 @@ "currentdevice": "Dispositiu actual", "datastoredoffline": "S'han desat les dades al dispositiu perquè no s'han pogut enviar. S'enviaran de manera automàtica més tard.", "date": "Data", - "day": "dia", - "days": "dies", + "day": "Dia (dies)", + "days": "Dies", "decsep": ",", "delete": "Suprimeix", "deleting": "S'està eliminant", @@ -55,7 +55,7 @@ "downloading": "S'està descarregant", "edit": "Edita", "emptysplit": "Aquesta pàgina estarà buida si el panell esquerre està buit o s'està carregant.", - "error": "Error", + "error": "S'ha produït un error", "errorchangecompletion": "S'ha produït un error en carregar l'estat de la compleció. Si us plau torneu a intentar-ho.", "errordeletefile": "S'ha produït un error en eliminar el fitxer. Torneu-ho a provar més tard.", "errordownloading": "S'ha produït un error en baixar el fitxer.", @@ -95,8 +95,8 @@ "loading": "S'està carregant...", "loadmore": "Carrega'n més", "lostconnection": "S'ha perdut la connexió. Necessita tornar a connectar. El testimoni ja no és vàlid.", - "maxsizeandattachments": "Mida màxima per als nous fitxers, {{$a.size}}, adjunts màxims: {{$a.attachments}}", - "min": "minut", + "maxsizeandattachments": "Mida màxima dels fitxers nous: {{$a.size}}, màxim d'adjuncions: {{$a.attachments}}", + "min": "Puntuació mínima", "mins": "minuts", "mod_assign": "Tasca", "mod_assignment": "Tasca", @@ -126,13 +126,13 @@ "mod_workshop": "Taller", "moduleintro": "Descripció", "mygroups": "Els meus grups", - "name": "Nom", + "name": "Nombre", "networkerrormsg": "La connexió a la xarxa no està habilitada o no funciona.", "never": "Mai", - "next": "Següent", + "next": "Continua", "no": "No", - "nocomments": "Sense comentaris", - "nograde": "Sense qualificació", + "nocomments": "No hi ha comentaris", + "nograde": "No hi ha qualificació.", "none": "Cap", "nopasswordchangeforced": "No podeu continuar sense canviar la contrasenya.", "nopermissions": "Actualment no teniu permisos per a fer això ({{$a}})", @@ -155,20 +155,20 @@ "pulltorefresh": "Estira per actualitzar", "redirectingtosite": "Sereu redireccionats al lloc web.", "refresh": "Refresca", - "required": "Necessari", + "required": "Requerit", "requireduserdatamissing": "En aquest perfil d'usuari hi manquen dades requerides. Si us plau ompliu aquestes dades i torneu a intentar-ho.
    {{$a}}", "retry": "Reintenta", "save": "Desa", - "search": "Cerca", + "search": "Cerca...", "searching": "S'està cercant", "searchresults": "Resultats de la cerca", "sec": "segon", "secs": "segons", "seemoredetail": "Feu clic aquí per veure més detalls", - "send": "envia", + "send": "Envia", "sending": "S'està enviant", "serverconnection": "S'ha produït un error de connexió amb el servidor", - "show": "Mostrar", + "show": "Mostra", "showmore": "Mostra'n més...", "site": "Lloc", "sitemaintenance": "S'estan executant tasques de manteniment i el lloc no està disponible", @@ -178,13 +178,14 @@ "sizemb": "MB", "sizetb": "TB", "sorry": "Ho sentim...", + "sortby": "Ordena per", "start": "Inicia", - "submit": "Tramet", + "submit": "Envia", "success": "Èxit", "tablet": "Tablet", "teachers": "Professors", "thereisdatatosync": "Hi ha {{$a}} fora de línia per sincronitzar.", - "time": "Hora", + "time": "Temps", "timesup": "Temps esgotat", "today": "Avui", "tryagain": "Torna-ho a provar", @@ -198,16 +199,16 @@ "unzipping": "S'està descomprimint", "upgraderunning": "El lloc s'està actualitzant. Proveu-ho més tard.", "userdeleted": "S'ha suprimit aquest compte d'usuari", - "userdetails": "Més detall", + "userdetails": "Més dades de l'usuari", "users": "Usuaris", - "view": "Visualització", + "view": "Mostra", "viewprofile": "Mostra el perfil", "warningofflinedatadeleted": "Les dades fora de línia de {{component}} «{{name}}» s'han eliminat. {{error}}", "whoops": "Ui!", "whyisthishappening": "I això per què passa?", "windowsphone": "Windows Phone", "wsfunctionnotavailable": "La funció de webservice no està disponible.", - "year": "any", + "year": "Any(s)", "years": "anys", "yes": "Sí" } \ No newline at end of file diff --git a/www/core/lang/cs.json b/www/core/lang/cs.json index 188f6b3b442..704e5887bf2 100644 --- a/www/core/lang/cs.json +++ b/www/core/lang/cs.json @@ -4,7 +4,7 @@ "android": "Android", "areyousure": "Opravdu?", "back": "Zpět", - "cancel": "Přerušit", + "cancel": "Zrušit", "cannotconnect": "Nelze se připojit: Ověřte, zda je zadali správně adresu URL a že používáte Moodle 2.4 nebo novější.", "cannotdownloadfiles": "Stahování souborů je vypnuto v Mobilních službách webu. Prosím, obraťte se na správce webu.", "category": "Kategorie", @@ -13,8 +13,8 @@ "clearsearch": "Vymazat vyhledávání", "clicktohideshow": "Klikněte pro rozbalení nebo sbalení", "clicktoseefull": "Kliknutím zobrazit celý obsah.", - "close": "Zavřít", - "comments": "Váš komentář", + "close": "Zavřít okno", + "comments": "Komentáře", "commentscount": "Komentáře ({{$a}})", "commentsnotworking": "Komentáře nemohou být obnoveny", "completion-alt-auto-fail": "Splněno: {{$a}} ; ale nedosáhli se potřebné známky", @@ -36,13 +36,13 @@ "currentdevice": "Aktuální zařízení", "datastoredoffline": "Data byla uložena na zařízení, protože nemohla být odeslána. Budou odeslána automaticky později.", "date": "Datum", - "day": "den", - "days": "dnů", + "day": "Dnů", + "days": "Dnů", "decsep": ",", "defaultvalue": "Výchozí ({{$a}})", "delete": "Odstranit", "deleting": "Odstraňování", - "description": "Úvodní text", + "description": "Popis", "dfdaymonthyear": "MM-DD-YYYY", "dfdayweekmonth": "ddd, D MMM", "dffulldate": "dddd, D MMMM YYYY h[:]mm A", @@ -56,7 +56,7 @@ "downloading": "Stahování", "edit": "Upravit", "emptysplit": "Pokud je levý panel prázdný nebo se nahrává, zobrazí se tato stránka prázdná.", - "error": "Chyba", + "error": "Vyskytla se chyba", "errorchangecompletion": "Při změně stavu dokončení došlo k chybě. Prosím zkuste to znovu.", "errordeletefile": "Chyba při odstraňování souboru. Prosím zkuste to znovu.", "errordownloading": "Chyba při stahování souboru", @@ -80,7 +80,7 @@ "groupsseparate": "Oddělené skupiny", "groupsvisible": "Viditelné skupiny", "hasdatatosync": "{{$a}} má offline data, která mají být synchronizována.", - "help": "Nápověda", + "help": "Pomoc", "hide": "Skrýt", "hour": "hodina", "hours": "hodin", @@ -93,11 +93,11 @@ "lastmodified": "Naposledy změněno", "lastsync": "Poslední synchronizace", "listsep": ";", - "loading": "Nahrávání", + "loading": "Načítání...", "loadmore": "Načíst další", "lostconnection": "Ztratili jsme spojení, potřebujete se znovu připojit. Váš token je nyní neplatný", "maxsizeandattachments": "Maximální velikost nových souborů: {{$a.size}}, maximální přílohy: {{$a.attachments}}", - "min": "min.", + "min": "Minimální skóre", "mins": "min.", "mod_assign": "Úkol", "mod_assignment": "Úkol", @@ -127,17 +127,17 @@ "mod_workshop": "Workshop", "moduleintro": "Popis", "mygroups": "Moje skupiny", - "name": "Název", + "name": "Jméno", "networkerrormsg": "Síť není povolena nebo nefunguje.", "never": "Nikdy", - "next": "Další", + "next": "Pokračovat", "no": "Ne", - "nocomments": "Bez komentářů", - "nograde": "Bez známky", - "none": "Žádný", + "nocomments": "Nejsou žádné komentáře", + "nograde": "Žádné hodnocení.", + "none": "Nic", "nopasswordchangeforced": "Nelze pokračovat beze změny hesla.", "nopermissions": "Je mi líto, ale momentálně nemáte oprávnění vykonat tuto operaci ({{$a}})", - "noresults": "Bez výsledků", + "noresults": "Žádné výsledky", "notapplicable": "n/a", "notice": "Poznámka", "notsent": "Neodesláno", @@ -156,20 +156,20 @@ "pulltorefresh": "Stáhněte pro obnovu", "redirectingtosite": "Budete přesměrováni na web.", "refresh": "Obnovit", - "required": "Vyžadováno", + "required": "Povinné", "requireduserdatamissing": "Tento uživatel nemá některá požadovaná data v profilu. Prosím, vyplňte tato data v systému Moodle a zkuste to znovu.
    {{$a}}", "retry": "Opakovat", "save": "Uložit", - "search": "Hledat", + "search": "Vyhledat", "searching": "Hledání", "searchresults": "Výsledky hledání", "sec": "sek.", "secs": "sekund", "seemoredetail": "Více podrobností...", - "send": "odeslat", + "send": "Odeslat", "sending": "Odeslání", "serverconnection": "Chyba spojení se serverem", - "show": "Zobrazit", + "show": "Ukázat", "showmore": "Zobrazit více...", "site": "Stránky", "sitemaintenance": "Na webu probíhá údržba a aktuálně není k dispozici", @@ -179,6 +179,7 @@ "sizemb": "MB", "sizetb": "TB", "sorry": "Promiňte...", + "sortby": "Třídit podle", "start": "Začátek", "submit": "Odeslat", "success": "Úspěch!", @@ -202,14 +203,14 @@ "userdetails": "Detaily uživatele", "usernotfullysetup": "Uživatel není plně nastaven", "users": "Uživatelé", - "view": "Zobrazit", + "view": "Zobrazení", "viewprofile": "Zobrazit profil", "warningofflinedatadeleted": "Offline data z {{component}} \"{{name}}\" byla odstraněna. {{error}}", "whoops": "Herdekfilek!", "whyisthishappening": "Proč se to děje?", "windowsphone": "Windows Phone", "wsfunctionnotavailable": "Funkce webových služeb není k dispozici.", - "year": "rok", + "year": "Rok(y)", "years": "roky", "yes": "Ano" } \ No newline at end of file diff --git a/www/core/lang/da.json b/www/core/lang/da.json index 847a8e2b5f1..849e6a2f3a0 100644 --- a/www/core/lang/da.json +++ b/www/core/lang/da.json @@ -14,14 +14,14 @@ "clicktohideshow": "Klik for at udvide eller folde sammen", "clicktoseefull": "Klik for at se alt indhold.", "close": "Luk", - "comments": "Dine kommentarer", + "comments": "Kommentarer", "commentscount": "Kommentarer ({{$a}})", - "completion-alt-auto-fail": "Gennemført: {{$a}} (opnåede ikke beståelseskarakter)", + "completion-alt-auto-fail": "Gennemført: {{$a}} (bestod ikke)", "completion-alt-auto-n": "Ikke gennemført: {{$a}}", - "completion-alt-auto-pass": "Gennemført: {{$a}} (opnåede beståelseskarakter)", + "completion-alt-auto-pass": "Gennemført: {{$a}} (bestod)", "completion-alt-auto-y": "Gennemført: {{$a}}", - "completion-alt-manual-n": "Ikke gennemført: {{$a}}. Vælg for at markere som gennemført.", - "completion-alt-manual-y": "Gennemført: {{$a}}. Vælg for at markere som ikke gennemført.", + "completion-alt-manual-n": "Ikke gennemført: {{$a}}. Vælg til markering som gennemført.", + "completion-alt-manual-y": "Gennemført: {{$a}}. Vælg til markering som ikke gennemført.", "confirmcanceledit": "Er du sikker på at du vil forlade denne side? Alle ændringer vil gå tabt.", "confirmdeletefile": "Er du sikker på at du vil slette denne fil?", "confirmopeninbrowser": "Vil du åbne den i en browser?", @@ -31,17 +31,17 @@ "coursedetails": "Kursusdetaljer", "datastoredoffline": "Der blev gemt data på enheden da det ikke kunne sendes. Det vil blive sendt senere.", "date": "Dato", - "day": "dag", - "days": "dage", + "day": "Dag(e)", + "days": "Dage", "decsep": ",", "delete": "Slet", "deleting": "Sletter", - "description": "Introduktionstekst", + "description": "Beskrivelse", "done": "Færdig", "download": "Download", "downloading": "Downloader", "edit": "Rediger", - "error": "Fejl", + "error": "Fejl opstået", "errorchangecompletion": "En fejl opstod under ændring af gennemførelsesstatus. Prøv igen.", "errordownloading": "Fejl ved download af fil.", "errordownloadingsomefiles": "Fejl ved download af modulfiler. Nogle filer mangler måske.", @@ -65,13 +65,13 @@ "info": "Information", "ios": "iOS", "labelsep": ":", - "lastmodified": "Sidst ændret", + "lastmodified": "Senest ændret", "lastsync": "Sidste sunkronisering", "listsep": ";", - "loading": "Indlæser", + "loading": "Indlæser...", "lostconnection": "Din godkendelse er ugyldig eller udløbet, så du skal genoprette forbindelsen til webstedet.", "maxsizeandattachments": "Maksimal størrelse på nye filer: {{$a.size}}, højeste antal bilag: {{$a.attachments}}", - "min": "min.", + "min": "Minimum point", "mins": "min.", "mod_assign": "Opgave", "mod_assignment": "Opgave", @@ -103,10 +103,10 @@ "name": "Navn", "networkerrormsg": "Netværk ikke aktiveret eller virker ikke.", "never": "Aldrig", - "next": "Næste", + "next": "Fortsæt", "no": "Nej", - "nocomments": "Ingen kommentarer", - "nograde": "Ingen karakter", + "nocomments": "Der er ingen kommentarer", + "nograde": "Ingen bedømmelse.", "none": "Ingen", "nopasswordchangeforced": "Du kan ikke fortsætte uden at ændre din adgangskode, men der er ingen tilgængelig side at ændre den på. Kontakt venligst din Moodleadministrator.", "nopermissions": "Beklager, men dette ({{$a}}) har du ikke tilladelse til.", @@ -115,7 +115,7 @@ "notice": "Bemærk", "now": "nu", "numwords": "{{$a}} ord", - "offline": "Der kræves ikke online-aflevering", + "offline": "Offline", "online": "Online", "openfullimage": "Klik her for at vise billedet i fuld størrelse.", "openinbrowser": "Åben i browser", @@ -126,31 +126,32 @@ "previous": "Forrige", "pulltorefresh": "Træk for at opdatere", "refresh": "Genindlæs", - "required": "Påkrævet", + "required": "Krævet", "requireduserdatamissing": "Denne bruger mangler nogle krævede profildata. Udfyld venligst de manglende data i din Moodle og prøv igen.
    {{$a}}", "save": "Gem", - "search": "Søg", - "searching": "Søg i", + "search": "Søg...", + "searching": "Søger", "searchresults": "Søgeresultater", "sec": "sekunder", "secs": "sekunder", "seemoredetail": "Klik her for detaljer", - "send": "send", + "send": "Send", "sending": "Sender", "serverconnection": "Fejl ved forbindelse til server", "show": "Vis", "site": "Websted", "sizeb": "bytes", - "sizegb": "Gb", - "sizekb": "Kb", - "sizemb": "Mb", + "sizegb": "GB", + "sizekb": "KB", + "sizemb": "MB", "sizetb": "TB", + "sortby": "Sorter efter", "start": "Start", - "submit": "Gem", - "success": "Succes", + "submit": "Send", + "success": "Succes!", "tablet": "Tablet", - "teachers": "Undervisere", - "time": "Tidspunkt", + "teachers": "Lærere", + "time": "Tid", "timesup": "Tiden er gået!", "today": "I dag", "twoparagraphs": "{{p1}}

    {{p2}}", @@ -163,11 +164,11 @@ "userdetails": "Brugeroplysninger", "users": "Brugere", "view": "Vis", - "viewprofile": "Vis Profil", + "viewprofile": "Vis profil", "whoops": "Hovsa", "windowsphone": "Windowstelefon", "wsfunctionnotavailable": "Denne webservicefunktion er ikke tilgængelig.", - "year": "år", + "year": "År", "years": "år", "yes": "Ja" } \ No newline at end of file diff --git a/www/core/lang/de.json b/www/core/lang/de.json index 211871a577b..59516edcac7 100644 --- a/www/core/lang/de.json +++ b/www/core/lang/de.json @@ -7,14 +7,18 @@ "cancel": "Abbrechen", "cannotconnect": "Die Verbindung ist nicht möglich. Prüfen Sie, ob die URL richtig ist und dass mindestens Moodle 2.4 verwendet wird.", "cannotdownloadfiles": "Das Herunterladen von Dateien ist im mobilen Webservice deaktiviert. Wenden Sie sich an den Administrator der Website.", - "category": "Kategorie", + "captureaudio": "Audio aufnehmen", + "capturedimage": "Foto aufgenommen.", + "captureimage": "Foto aufnehmen", + "capturevideo": "Video aufnehmen", + "category": "Kursbereich", "choose": "Auswahl", "choosedots": "Auswählen...", "clearsearch": "Suche löschen", "clicktohideshow": "Zum Erweitern oder Zusammenfassen klicken", "clicktoseefull": "Tippen zum Anzeigen aller Inhalte", - "close": "Schließen", - "comments": "Ihr Feedback", + "close": "Fenster schließen", + "comments": "Kommentare", "commentscount": "Kommentare ({{$a}})", "commentsnotworking": "Kommentare können nicht mehr abgerufen werden", "completion-alt-auto-fail": "Abgeschlossen: {{$a}} (Anforderung nicht erreicht)", @@ -29,14 +33,14 @@ "confirmopeninbrowser": "Möchten Sie dies im Browser öffnen?", "content": "Inhalt", "contenteditingsynced": "Der Inhalt, den Sie bearbeiten, wurde synchronisiert.", - "continue": "Weiter", + "continue": "Fortsetzen", "copiedtoclipboard": "Text in die Zwischenablage kopiert", "course": "Kurs", "coursedetails": "Kursdetails", "currentdevice": "Aktuelles Gerät", "datastoredoffline": "Daten wurden im Gerät gespeichert, da sie nicht gesendet werden konnten. Sie werden automatisch später gesendet.", "date": "Datum", - "day": "Tag", + "day": "Tag(e)", "days": "Tage", "decsep": ",", "defaultvalue": "Standard ({{$a}})", @@ -56,7 +60,7 @@ "downloading": "Herunterladen ...", "edit": "Bearbeiten", "emptysplit": "Diese Seite ist leer, wenn das linke Panel leer ist oder noch geladen wird.", - "error": "Fehler", + "error": "Fehler aufgetreten", "errorchangecompletion": "Fehler beim Ändern des Abschlussstatus. Versuchen Sie es noch einmal.", "errordeletefile": "Fehler beim Löschen der Datei. Versuchen Sie es noch einmal.", "errordownloading": "Fehler beim Laden der Datei", @@ -90,14 +94,15 @@ "info": "Info", "ios": "iOS", "labelsep": ": ", + "lastdownloaded": "Zuletzt heruntergeladen", "lastmodified": "Zuletzt geändert", - "lastsync": "Letztes Synchronisieren", + "lastsync": "Zuletzt synchronisiert", "listsep": ";", - "loading": "Wird geladen", + "loading": "Wird geladen...", "loadmore": "Mehr laden", "lostconnection": "Die Authentifizierung ist abgelaufen oder ungültig. Sie müssen sich neu verbinden.", "maxsizeandattachments": "Maximale Größe für neue Dateien: {{$a.size}}, Maximale Zahl von Anhängen: {{$a.attachments}}", - "min": "Minute", + "min": "Niedrigste Punktzahl", "mins": "Minuten", "mod_assign": "Aufgabe", "mod_assignment": "Aufgabe", @@ -128,13 +133,13 @@ "moduleintro": "Beschreibung", "mygroups": "Meine Gruppen", "name": "Name", - "networkerrormsg": "Kein Netzwerk", + "networkerrormsg": "Problem mit der Verbindung. Prüfen Sie die Verbindung und versuchen Sie es noch einmal.", "never": "Nie", "next": "Weiter", "no": "Nein", - "nocomments": "Noch keine Kommentare", - "nograde": "Keine Bewertung", - "none": "Keine", + "nocomments": "Keine Kommentare", + "nograde": "Keine Bewertung.", + "none": "Kein", "nopasswordchangeforced": "Sie können nicht weitermachen, ohne das Kennwort zu ändern.", "nopermissions": "Sie besitzen derzeit keine Rechte, dies zu tun ({{$a}}).", "noresults": "Keine Ergebnisse", @@ -155,12 +160,12 @@ "previous": "Zurück", "pulltorefresh": "Zum Aktualisieren runterziehen", "redirectingtosite": "Sie werden zur Website weitergeleitet.", - "refresh": "Aktualisieren", - "required": "Erforderlich", + "refresh": "Neu laden", + "required": "Notwendig", "requireduserdatamissing": "In diesem Nutzerprofil fehlen notwendige Daten. Füllen Sie die Daten in der Website aus und versuchen Sie es noch einmal.
    {{$a}}", "retry": "Neu versuchen", - "save": "Speichern", - "search": "Suchen", + "save": "Sichern", + "search": "Suche", "searching": "Suchen", "searchresults": "Suchergebnisse", "sec": "Sekunde", @@ -169,7 +174,7 @@ "send": "Senden", "sending": "Senden", "serverconnection": "Fehler beim Aufbau der Verbindung zum Server", - "show": "Anzeigen", + "show": "Zeigen", "showmore": "Mehr anzeigen ...", "site": "Website", "sitemaintenance": "Wartungsmodus: Die Website ist im Moment nicht erreichbar!", @@ -179,8 +184,9 @@ "sizemb": "MB", "sizetb": "TB", "sorry": "Sorry ...", + "sortby": "Sortiert nach", "start": "Start", - "submit": "Speichern", + "submit": "Übertragen", "success": "Fertig!", "tablet": "Tablet", "teachers": "Trainer/innen", @@ -202,14 +208,14 @@ "userdetails": "Mehr Details", "usernotfullysetup": "Nutzerkonto unvollständig", "users": "Nutzer/innen", - "view": "Zum Kurs", + "view": "Anzeigen", "viewprofile": "Profil anzeigen", "warningofflinedatadeleted": "Die Offline-Daten von {{component}} '{{name}}' wurden gelöscht. {{error}}", "whoops": "Uuups!", "whyisthishappening": "Warum geschieht dies?", "windowsphone": "Windows Phone", "wsfunctionnotavailable": "Die Webservice-Funktion ist nicht verfügbar.", - "year": "Jahr", + "year": "Jahr(e)", "years": "Jahre", "yes": "Ja" } \ No newline at end of file diff --git a/www/core/lang/el.json b/www/core/lang/el.json index 01ffb362a04..a442a65b656 100644 --- a/www/core/lang/el.json +++ b/www/core/lang/el.json @@ -4,17 +4,17 @@ "android": "Android", "areyousure": "Είστε σίγουρος ;", "back": "Πίσω", - "cancel": "Άκυρο", + "cancel": "Ακύρωση", "cannotconnect": "Δεν είναι δυνατή η σύνδεση: Βεβαιωθείτε ότι έχετε πληκτρολογήσει σωστά τη διεύθυνση URL και ότι το site σας χρησιμοποιεί το Moodle 2.4 ή νεότερη έκδοση.", "cannotdownloadfiles": "Το κατέβασμα αρχείων είναι απενεργοποιημένο. Παρακαλώ, επικοινωνήστε με το διαχειριστή του site σας.", - "category": "Τμήμα", + "category": "Κατηγορία", "choose": "Επιλέξτε", "choosedots": "Επιλέξτε...", "clearsearch": "Καθαρισμός αναζήτησης", "clicktohideshow": "Πατήστε για επέκταση ή κατάρρευση", "clicktoseefull": "Κάντε κλικ για να δείτε το πλήρες περιεχόμενο.", - "close": "Κλείσιμο", - "comments": "Τα σχόλιά σας", + "close": "Κλείσιμο παραθύρου", + "comments": "Σχόλια", "commentscount": "Σχόλια ({{$a}})", "commentsnotworking": "Τα σχόλια δεν μπορούν να ανακτηθούν", "completion-alt-auto-fail": "Ολοκληρώθηκε: {{$a}} (δεν πετύχατε βαθμό πρόσβασης)", @@ -25,23 +25,26 @@ "completion-alt-manual-y": "Ολοκληρώθηκε: {{$a}}. Επιλέξτε για να οριστεί ως μη ολοκληρωμένο.", "confirmcanceledit": "Είστε σίγουροι ότι θέλετε να αποχωρήσετε από αυτήν τη σελίδα; Όλες οι αλλαγές θα χαθούν.", "confirmdeletefile": "Είστε σίγουροι οτι θέλετε να διαγράψετε αυτό το αρχείο?", + "confirmloss": "Είστε σίγουροι? Όλες οι αλλαγές θα χαθούν.", "confirmopeninbrowser": "Θέλετε να το ανοίξετε στο πρόγραμμα περιήγησης;", "content": "Περιεχόμενο", "contenteditingsynced": "Το περιεχόμενο που επεξεργάζεστε έχει συγχρονιστεί.", "continue": "Συνέχεια", + "copiedtoclipboard": "Το κείμενο αντιγράφηκε στο πρόχειρο", "course": "Μάθημα", "coursedetails": "Λεπτομέρειες μαθήματος", "currentdevice": "Τρέχουσα συσκευή", "datastoredoffline": "Τα δεδομένα αποθηκεύονται στη συσκευή, διότι δεν μπορούν να σταλούν. Θα αποσταλούν αυτόματα αργότερα.", "date": "Ημερομηνία", "day": "ημέρα", - "days": "ημέρες", + "days": "Ημέρες", "decsep": ",", "delete": "Διαγραφή", "deleting": "Γίνεται διαγραφή", - "description": "Κείμενο εισαγωγής", + "description": "Περιγραφή", "dfdaymonthyear": "MM-DD-YYYY", "dfdayweekmonth": "ddd, D MMM", + "dffulldate": "dddd, D MMMM YYYY h[:]mm A", "dflastweekdate": "ddd", "dfmediumdate": "LLL", "dftimedate": "h[:]mm A", @@ -50,8 +53,9 @@ "done": "Ολοκληρώθηκε", "download": "Μεταφόρτωση", "downloading": "Κατέβασμα", - "edit": "Edit", - "error": "Σφάλμα", + "edit": "Επεξεργασία ", + "emptysplit": "Αυτή η σελίδα θα εμφανιστεί κενή, εάν ο αριστερός πίνακας είναι κενός ή φορτώνεται.", + "error": "Συνέβη κάποιο σφάλμα", "errorchangecompletion": "Παρουσιάστηκε σφάλμα κατά την αλλαγή της κατάστασης ολοκλήρωσης. Παρακαλώ προσπαθήστε ξανά.", "errordeletefile": "Σφάλμα κατά τη διαγραφή του αρχείου. Παρακαλώ προσπαθήστε ξανά.", "errordownloading": "Σφάλμα στο κατέβασμα του αρχείου.", @@ -59,6 +63,7 @@ "errorfileexistssamename": "Υπάρχει ήδη ένα αρχείο με αυτό το όνομα.", "errorinvalidform": "Η φόρμα περιέχει μη έγκυρα δεδομένα. Παρακαλούμε φροντίστε να συμπληρώσετε όλα τα απαιτούμενα πεδία και ότι τα δεδομένα είναι έγκυρα.", "errorinvalidresponse": "Ελήφθη μη έγκυρη απάντηση. Επικοινωνήστε με το διαχειριστή εάν το πρόβλημα επιμείνει.", + "errorloadingcontent": "Σφάλμα κατά τη φόρτωση περιεχομένου.", "erroropenfilenoapp": "Σφάλμα κατά το άνοιγμα του αρχείου: δεν βρέθηκε εφαρμογή για το άνοιγμα αυτού του είδους αρχεία.", "erroropenfilenoextension": "Σφάλμα κατά το άνοιγμα του αρχείου: το αρχείο δεν έχει επέκταση.", "erroropenpopup": "Αυτή η δραστηριότητα προσπαθεί να ανοίξει ένα αναδυόμενο παράθυρο. Αυτό δεν υποστηρίζεται σε αυτή την εφαρμογή.", @@ -86,10 +91,11 @@ "lastmodified": "Τελευταία τροποποίηση", "lastsync": "Τελευταίος συγχρονισμός", "listsep": ";", - "loading": "Φορτώνει", + "loading": "Φόρτωση...", + "loadmore": "Φόρτωση περισσότερων", "lostconnection": "Η σύνδεσή σας είναι άκυρη ή έχει λήξει. Πρέπει να ξανασυνδεθείτε στο site.", "maxsizeandattachments": "Μέγιστο μέγεθος για νέα αρχεία: {{$a.size}}, μέγιστος αριθμός συνημμένων: {{$a.attachments}}", - "min": "λεπτό", + "min": "Ελάχιστος βαθμός", "mins": "λεπτά", "mod_assign": "Εργασία", "mod_assignment": "Εργασία", @@ -122,11 +128,11 @@ "name": "Όνομα", "networkerrormsg": "Το δίκτυο δεν είναι ενεργοποιημένο ή δεν δουλεύει.", "never": "Ποτέ", - "next": "Επόμενο", + "next": "Συνέχεια", "no": "Όχι", - "nocomments": "Χωρίς Σχόλια", - "nograde": "Δεν υπάρχει βαθμός", - "none": "Κανένας", + "nocomments": "Δεν υπάρχουν σχόλια", + "nograde": "Κανένα βαθμό.", + "none": "Κανένα", "nopasswordchangeforced": "Δεν μπορείτε να προχωρήσετε χωρίς να αλλάξετε τον κωδικό πρόσβασής σας.", "nopermissions": "Συγνώμη, αλλά επί του τρεχόντως δεν έχετε το δικαίωμα να το κάνετε αυτό ({{$a}})", "noresults": "Κανένα αποτέλεσμα", @@ -152,15 +158,15 @@ "requireduserdatamissing": "Αυτός ο χρήστης δεν έχει συμπληρωμένα κάποια απαιτούμενα στοιχεία του προφίλ του. Συμπληρώστε τα δεδομένα στο Moodle σας και προσπαθήστε ξανά.
    {{$a}}", "retry": "Προσπαθήστε ξανά", "save": "Αποθήκευση", - "search": "Αναζήτηση", + "search": "Έρευνα", "searching": "Αναζήτηση", - "searchresults": "Αποτελέσματα αναζήτησης", + "searchresults": "Αναζήτηση στα αποτελέσματα", "sec": "δευτερόλεπτο", "secs": "δευτερόλεπτα", "seemoredetail": "Κάντε κλικ εδώ για να δείτε περισσότερες λεπτομέρειες", "send": "Αποστολή", "sending": "Αποστολή", - "show": "Προβολή", + "show": "Εμφάνιση", "showmore": "Περισσότερα...", "site": "ιστοχώρος", "sitemaintenance": "Η ιστοσελίδα είναι υπό συντήρηση και δεν είναι άμεσα διαθέσιμη", @@ -170,19 +176,22 @@ "sizemb": "MB", "sizetb": "TB", "sorry": "Λυπάμαι...", + "sortby": "Ταξινόμηση κατά", "start": "Αρχή", "submit": "Υποβολή", "success": "Επιτυχία!", "tablet": "Tablet", "teachers": "Καθηγητές", "thereisdatatosync": "Υπάρχουν εκτός σύνδεσης {{$a}} για συγχρονισμό.", - "time": "Ώρα", + "time": "Χρόνος", "timesup": "Έληξε ο χρόνος!", "today": "Σήμερα", "tryagain": "Προσπαθήστε ξανά.", "twoparagraphs": "{{p1}}

    {{p2}}", "uhoh": "Uh oh!", "unexpectederror": "Απρόσμενο σφάλμα. Κλείστε και ανοίξτε ξανά την εφαρμογή για να προσπαθήσετε ξανά", + "unicodenotsupported": "Ορισμένα emojis δεν υποστηρίζονται σε αυτόν τον ιστότοπο. Αυτοί οι χαρακτήρες θα αφαιρεθούν κατά την αποστολή του μηνύματος.", + "unicodenotsupportedcleanerror": "Κενό κείμενο βρέθηκε κατά τον καθαρισμό χαρακτήρων Unicode.", "unknown": "Άγνωστο", "unlimited": "Χωρίς περιορισμό", "unzipping": "Αποσυμπίεση", diff --git a/www/core/lang/en.json b/www/core/lang/en.json index 3870dcb79dd..783417f3a48 100644 --- a/www/core/lang/en.json +++ b/www/core/lang/en.json @@ -7,6 +7,10 @@ "cancel": "Cancel", "cannotconnect": "Cannot connect: Verify that you have typed correctly the URL and that your site uses Moodle 2.4 or later.", "cannotdownloadfiles": "File downloading is disabled in your Mobile service. Please, contact your site administrator.", + "captureaudio": "Record audio", + "capturedimage": "Taken picture.", + "captureimage": "Take picture", + "capturevideo": "Record video", "category": "Category", "choose": "Choose", "choosedots": "Choose...", @@ -90,6 +94,7 @@ "info": "Info", "ios": "iOS", "labelsep": ": ", + "lastdownloaded": "Last downloaded", "lastmodified": "Last modified", "lastsync": "Last synchronization", "listsep": ",", @@ -129,7 +134,7 @@ "mygroups": "My groups", "name": "Name", "nograde": "No grade", - "networkerrormsg": "Network not enabled or not working.", + "networkerrormsg": "There was a problem connecting to the site. Please check your connection and try again.", "never": "Never", "next": "Next", "no": "No", @@ -158,6 +163,7 @@ "refresh": "Refresh", "required": "Required", "requireduserdatamissing": "This user lacks some required profile data. Please, fill this data in your Moodle and try again.
    {{$a}}", + "restore": "Restore", "retry": "Retry", "save": "Save", "search": " Search...", @@ -179,6 +185,7 @@ "sizemb": "MB", "sizetb": "TB", "sorry": "Sorry...", + "sortby": "Sort by", "start": "Start", "submit": "Submit", "success": "Success", diff --git a/www/core/lang/es-mx.json b/www/core/lang/es-mx.json index 0ed3bc93f3a..662830dfc48 100644 --- a/www/core/lang/es-mx.json +++ b/www/core/lang/es-mx.json @@ -7,22 +7,26 @@ "cancel": "Cancelar", "cannotconnect": "No se puede conectar: Verifique que Usted escribió la URL correcta y que su sitio usa Moodle 2.4 o más reciente.", "cannotdownloadfiles": "La descarga de archivos está deshabilitada en su servicio Mobile. Por favor contacte a su administrador del sitio.", + "captureaudio": "Grabar audio", + "capturedimage": "Foto tomada.", + "captureimage": "Tomar foto", + "capturevideo": "Grabar video", "category": "Categoría", "choose": "Elegir", "choosedots": "Elegir...", "clearsearch": "Limpiar búsqueda", "clicktohideshow": "Clic para expandir o colapsar", "clicktoseefull": "Hacer click para ver los contenidos completos.", - "close": "Cerrar", - "comments": "Sus comentarios", + "close": "Cerrar vista previa", + "comments": "Comentarios", "commentscount": "Comentarios ({{$a}})", "commentsnotworking": "No pueden recuperarse comentarios", - "completion-alt-auto-fail": "Completado: {{$a}} (no obtuvo calificación aprobatoria)", - "completion-alt-auto-n": "No completado: {{$a}}", - "completion-alt-auto-pass": "Completado: {{$a}} (obtuvo calificación aprobatoria)", - "completion-alt-auto-y": "Completado: {{$a}}", - "completion-alt-manual-n": "No-completado: {{$a}}. Seleccionar mara marcarlo como completado.", - "completion-alt-manual-y": "Completado: {{$a}}. Seleccionar mara marcarlo como no completado.", + "completion-alt-auto-fail": "Finalizado {{$a}} (no obtuvo calificación de aprobado)", + "completion-alt-auto-n": "Sin finalizar: {{$a}}", + "completion-alt-auto-pass": "Finalizado: {{$a}} (obtuvo calificación de aprobado)", + "completion-alt-auto-y": "Finalizado: {{$a}}", + "completion-alt-manual-n": "No finalizado; {{$a}}. Seleccione para marcar como finalizado", + "completion-alt-manual-y": "Finalizado; {{$a}} seleccione para marcar como no finalizado", "confirmcanceledit": "¿Está Usted seguro de que quiere abandonar esta página? Se perderán todos los cambios.", "confirmdeletefile": "¿Está seguro de que desea eliminar este archivo?", "confirmloss": "¿Está Usted seguro? Se perderán todos los cambios.", @@ -36,13 +40,13 @@ "currentdevice": "Dispositivo actual", "datastoredoffline": "Los datos se almacenaron en el dispositivo debido a que no se pudieron enviar. Serán enviados automáticamente más tarde.", "date": "Fecha", - "day": "día", - "days": "días", + "day": "Día(s)", + "days": "Días", "decsep": ".", "defaultvalue": "Valor por defecto ({{$a}})", "delete": "Eliminar", "deleting": "Eliminando", - "description": "Descripción -", + "description": "Descripción", "dfdaymonthyear": "MM-DD-AAAA", "dfdayweekmonth": "ddd, D MMM", "dffulldate": "dddd, D MMMM AAAA h[:]mm A", @@ -54,9 +58,9 @@ "done": "Hecho", "download": "Descargar", "downloading": "Descargando", - "edit": "Edición", + "edit": "Editar", "emptysplit": "Esta página aparecerá en blanco si el panel izquierdo está vacío o si está cargando.", - "error": "Error", + "error": "Ocurrió un error", "errorchangecompletion": "Ocurrió un error al cambiar el estatus de finalización. Por favor inténtelo nuevamente.", "errordeletefile": "Error al eliminar el archivo. Por favor inténtelo nuevamente.", "errordownloading": "Error al descargar archivo", @@ -90,14 +94,15 @@ "info": "Información", "ios": "iOS", "labelsep": ":", - "lastmodified": "Última modificación", + "lastdownloaded": "Última descarga", + "lastmodified": "Última modicficación", "lastsync": "Última sincronzación", "listsep": ";", - "loading": "Cargando", + "loading": "Cargando...", "loadmore": "Cargar más", "lostconnection": "Hemos perdido la conexión, necesita reconectar. Su ficha (token) ya no es válido", "maxsizeandattachments": "Tamaño máximo para archivos nuevos: {{$a.size}}, anexos máximos: {{$a.attachments}}", - "min": "minutos", + "min": "Puntuación mínima", "mins": "minutos", "mod_assign": "Tarea", "mod_assignment": "Tarea", @@ -128,16 +133,16 @@ "moduleintro": "Descripción", "mygroups": "Mis grupos", "name": "Nombre", - "networkerrormsg": "Red no disponible o no funcionando.", + "networkerrormsg": "Hubo un problema para conectarse al sitio. Por favor revise su conexión e inténtelo nuevamente.", "never": "Nunca", - "next": "Siguiente", + "next": "Continuar", "no": "No", "nocomments": "No hay comentarios", - "nograde": "No hay calificación", - "none": "Ninguno/a", + "nograde": "Sin calificación.", + "none": "Ninguno(a)", "nopasswordchangeforced": "Usted no puede proceder sin cambiar su contraseña.", "nopermissions": "Lo sentimos, pero por el momento no tiene permiso para hacer eso ({{$a}})", - "noresults": "No hay resultados", + "noresults": "Sin resultados", "notapplicable": "no disp.", "notice": "Aviso", "notsent": "No enviado", @@ -156,17 +161,17 @@ "pulltorefresh": "''Pull'' para refrescar", "redirectingtosite": "Usted será redireccionado al sitio.", "refresh": "Refrescar", - "required": "Obligatorio", + "required": "Requerido", "requireduserdatamissing": "A este usuario le faltan algunos datos requeridos del perfil. Por favor, llene estos datos en su Moodle e inténtelo nuevamente.
    {{$a}}", "retry": "Reintentar", "save": "Guardar", - "search": "Buscar", + "search": "Búsqueda", "searching": "Buscando", - "searchresults": "Resultados de la búsqueda", + "searchresults": "Resultado", "sec": "segundos", "secs": "segundos", "seemoredetail": "Haga clic aquí para ver más detalles", - "send": "enviar", + "send": "Enviar", "sending": "Enviando", "serverconnection": "Error al conectarse al servidor", "show": "Mostrar", @@ -179,13 +184,14 @@ "sizemb": "MB", "sizetb": "TB", "sorry": "Lo siento...", + "sortby": "Ordenar por", "start": "Inicio", "submit": "Enviar", - "success": "¡Éxito!", + "success": "Éxito", "tablet": "Tableta", "teachers": "Profesores", "thereisdatatosync": "Existen {{$a}} fuera-de-línea para ser sincronizados/as.", - "time": "Hora", + "time": "Tiempo", "timesup": "¡Se ha pasado el tiempo!", "today": "Hoy", "tryagain": "Intentar nuevamente", @@ -202,14 +208,14 @@ "userdetails": "Detalles de usuario", "usernotfullysetup": "Usuario no cnfigurado completamente", "users": "Usuarios", - "view": "Vista", + "view": "Ver", "viewprofile": "Ver perfil", "warningofflinedatadeleted": "Los datos fuera-de-línea de {{component}} '{{name}}' han sido borrados. {{error}}", "whoops": "¡Órale!", "whyisthishappening": "¿Porqué está pasando esto?", "windowsphone": "Teléfono Windows", "wsfunctionnotavailable": "La función webservice no está disponible.", - "year": "año", + "year": "Año(s)", "years": "años", "yes": "Sí" } \ No newline at end of file diff --git a/www/core/lang/es.json b/www/core/lang/es.json index 708e85381b9..33d6d69cde8 100644 --- a/www/core/lang/es.json +++ b/www/core/lang/es.json @@ -13,8 +13,8 @@ "clearsearch": "Limpiar búsqueda", "clicktohideshow": "Clic para expandir o colapsar", "clicktoseefull": "Clic para ver el contenido al completo", - "close": "Cerrar", - "comments": "Sus comentarios", + "close": "Cerrar vista previa", + "comments": "Comentarios", "commentscount": "Comentarios ({{$a}})", "commentsnotworking": "No pueden recuperarse comentarios", "completion-alt-auto-fail": "Finalizado {{$a}} (no ha alcanzado la calificación de aprobado)", @@ -25,23 +25,26 @@ "completion-alt-manual-y": "Finalizado; {{$a}} seleccione para marcar como no finalizado", "confirmcanceledit": "¿Está usted seguro de que quiere abandonar esta página? Se perderán todos los cambios.", "confirmdeletefile": "¿Está seguro de que desea eliminar este archivo?", + "confirmloss": "¿Está seguro? Se perderán todos los cambios.", "confirmopeninbrowser": "¿Quiere abrirlo en el navegador?", "content": "Contenido", "contenteditingsynced": "El contenido que está editando ha sido sincronizado.", "continue": "Continuar", + "copiedtoclipboard": "Texto copiado al portapapeles", "course": "Curso", "coursedetails": "Detalles del curso", "currentdevice": "Dispositivo actual", "datastoredoffline": "Los datos se almacenaron en el dispositivo debido a que no se pudieron enviar. Serán enviados automáticamente más tarde.", "date": "Fecha", - "day": "día", - "days": "días", + "day": "Día(s)", + "days": "Días", "decsep": ",", - "delete": "Eliminar", + "delete": "Borrar", "deleting": "Borrando", "description": "Descripción", "dfdaymonthyear": "MM-DD-YYYY", "dfdayweekmonth": "ddd, D MMM", + "dffulldate": "dddd, D MMMM YYYY h[:]mm A", "dflastweekdate": "ddd", "dfmediumdate": "LLL", "dftimedate": "h[:]mm A", @@ -50,8 +53,9 @@ "done": "Hecho", "download": "Descargar", "downloading": "Descargando...", - "edit": "Edición", - "error": "Error", + "edit": "Editar", + "emptysplit": "Esta página aparecerá en blanco si el panel izquierdo está vacío o si está cargando.", + "error": "Se produjo un error", "errorchangecompletion": "Ha ocurrido un error cargando el grado de realización. Por favor inténtalo de nuevo.", "errordeletefile": "Error al eliminar el archivo. Por favor inténtelo de nuevo.", "errordownloading": "Ocurrió un error descargando el archivo", @@ -59,6 +63,7 @@ "errorfileexistssamename": "Ya existe un archivo con este nombre.", "errorinvalidform": "El formulario contiene datos inválidos. Por favor, asegúrese de rellenar todos los campos requeridos y que los datos son válidos.", "errorinvalidresponse": "Se ha recibido una respuesta no válida. Por favor contactar con el administrador de Moodle si el error persiste.", + "errorloadingcontent": "Error cargando contenido.", "erroropenfilenoapp": "Error durante la apertura del archivo: no se encontró ninguna aplicación capaz de abrir este tipo de archivo.", "erroropenfilenoextension": "Se ha producido un error abriendo el archivo: el archivo no tiene extensión.", "erroropenpopup": "Esta actividad está intentando abrir una ventana emergente. Esta aplicación no lo soporta.", @@ -87,10 +92,11 @@ "lastmodified": "Última modificación", "lastsync": "Última sincronización", "listsep": ";", - "loading": "Cargando", + "loading": "Cargando...", + "loadmore": "Cargar más", "lostconnection": "Hemos perdido la conexión, necesita reconectar. Su token ya no es válido", "maxsizeandattachments": "Tamaño máximo para nuevos archivos: {{$a.size}}, número máximo de archivos adjuntos: {{$a.attachments}}", - "min": "minutos", + "min": "Calificación mínima", "mins": "minutos", "mod_assign": "Tarea", "mod_assignment": "Tarea", @@ -123,14 +129,14 @@ "name": "Nombre", "networkerrormsg": "Conexión no disponible o sin funcionar.", "never": "Nunca", - "next": "Siguiente", + "next": "Continuar", "no": "No", "nocomments": "No hay comentarios", - "nograde": "No hay calificación", - "none": "Ninguna", + "nograde": "Sin calificación", + "none": "Ninguno", "nopasswordchangeforced": "No puede continuar sin cambiar su contraseña.", "nopermissions": "Lo sentimos, pero por el momento no tiene permiso para hacer eso ({{$a}})", - "noresults": "No hay resultados", + "noresults": "Sin resultados", "notapplicable": "n/a", "notice": "Noticia", "notsent": "No enviado", @@ -148,18 +154,18 @@ "previous": "Anterior", "pulltorefresh": "Tirar para recargar", "redirectingtosite": "Será redirigido al sitio.", - "refresh": "Recargar", + "refresh": "Refrescar", "required": "Obligatorio", "requireduserdatamissing": "En este perfil de usuario faltan datos requeridos. Por favor, rellene estos datos e inténtelo otra vez.
    {{$a}}", "retry": "Reintentar", "save": "Guardar", - "search": "Buscar", + "search": "Búsqueda", "searching": "Buscando", - "searchresults": "Resultados de la búsqueda", + "searchresults": "Resultado", "sec": "segundos", "secs": "segundos", "seemoredetail": "Haga clic aquí para ver más detalles", - "send": "enviar", + "send": "Enviar", "sending": "Enviando", "serverconnection": "Error al conectarse al servidor", "show": "Mostrar", @@ -172,19 +178,22 @@ "sizemb": "MB", "sizetb": "TB", "sorry": "Disculpe...", + "sortby": "Ordenar por", "start": "Inicio", "submit": "Enviar", "success": "Éxito", "tablet": "Tablet", "teachers": "Profesores", "thereisdatatosync": "Hay {{$a}} fuera de línea pendiente de ser sincronizado.", - "time": "Hora", + "time": "Tiempo", "timesup": "¡Se ha pasado el tiempo!", "today": "Hoy", "tryagain": "Intentar de nuevo", "twoparagraphs": "{{p1}}

    {{p2}}", "uhoh": "¡Oh oh!", "unexpectederror": "Error inesperado. Por favor cierre y vuelva a abrir la aplicación para intentarlo de nuevo", + "unicodenotsupported": "Los emojis no están soportado en este sitio; esos caracteres serán quitados cuando el mensaje sea enviado.", + "unicodenotsupportedcleanerror": "Se encontró texto vacío al limpiar caracteres Unicode.", "unknown": "Desconocido", "unlimited": "Sin límite", "unzipping": "Descomprimiendo", @@ -192,14 +201,14 @@ "userdeleted": "Esta cuenta se ha cancelado", "userdetails": "Detalles de usuario", "users": "Usuarios", - "view": "Vista", + "view": "Ver", "viewprofile": "Ver perfil", "warningofflinedatadeleted": "Los datos fuera de línea de {{component}} '{{name}}' han sido borrados. {{error}}", "whoops": "Oops!", "whyisthishappening": "¿Porqué está pasando esto?", "windowsphone": "Windows Phone", "wsfunctionnotavailable": "La función de webservice no está disponible.", - "year": "año", + "year": "Año(s)", "years": "años", "yes": "Sí" } \ No newline at end of file diff --git a/www/core/lang/eu.json b/www/core/lang/eu.json index d7c8d3dd593..e89366b2e26 100644 --- a/www/core/lang/eu.json +++ b/www/core/lang/eu.json @@ -13,8 +13,8 @@ "clearsearch": "Bilaketa garbia", "clicktohideshow": "Sakatu zabaltzeko edo tolesteko", "clicktoseefull": "Klik egin eduki guztiak ikusteko.", - "close": "Itxi", - "comments": "Zure iruzkinak", + "close": "Leihoa itxi", + "comments": "Iruzkinak", "commentscount": "Iruzkinak: ({{$a}})", "commentsnotworking": "Iruzkinak ezin izan dira atzitu", "completion-alt-auto-fail": "Osatuta: {{$a}} (ez dute gutxieneko kalifikazioa lortu)", @@ -36,8 +36,8 @@ "currentdevice": "Oraingo gailua", "datastoredoffline": "Gailu honetan gordetako informazioa ezin izan da bidali. Beranduago automatikoki bidaliko da.", "date": "Data", - "day": "egun(a)", - "days": "egun", + "day": "Egun", + "days": "Egun", "decsep": ",", "delete": "Ezabatu", "deleting": "Ezabatzen", @@ -55,7 +55,7 @@ "downloading": "Jaisten", "edit": "Editatu", "emptysplit": "Orri hau hutsik agertuko da ezkerreko panela hutsik badago edo kargatzen ari bada.", - "error": "Errorea", + "error": "Errorea gertatu da", "errorchangecompletion": "Errorea gertatu da osaketa-egoera aldatzean. Mesedez saiatu berriz.", "errordeletefile": "Errorea fitxategia ezabatzean. Mesedez, saiatu berriz.", "errordownloading": "Errorea fitxategia jaistean.", @@ -92,11 +92,11 @@ "lastmodified": "Azken aldaketa", "lastsync": "Azken sinkronizazioa", "listsep": ";", - "loading": "Kargatzen", + "loading": "Kargatzen...", "loadmore": "Kargatu gehiago", "lostconnection": "Zure token-a orain ez da baliozkoa edo iraungitu da, gunera berriz konektatu beharko zara.", "maxsizeandattachments": "Gehienezko tamaina fitxategi berrietarako: {{$a.size}}, gehienezko eranskin-kopurua: {{$a.attachments}}", - "min": "minutu", + "min": "Gutxieneko puntuazioa", "mins": "minutu", "mod_assign": "Zeregina", "mod_assignment": "Zeregina", @@ -129,10 +129,10 @@ "name": "Izena", "networkerrormsg": "Sarea ezgaituta dago edo ez dabil.", "never": "Inoiz ez", - "next": "Hurrengoa", + "next": "Jarraitu", "no": "Ez", - "nocomments": "Iruzkinik ez", - "nograde": "Kalifikaziorik ez", + "nocomments": "Ez dago iruzkinik", + "nograde": "Kalifikaziorik ez.", "none": "Bat ere ez", "nopasswordchangeforced": "Ezin duzu jarraitu zure pasahitza aldatu gabe.", "nopermissions": "Sentitzen dugu, baina oraingoz ez duzu hori egiteko baimenik ({{$a}})", @@ -155,17 +155,17 @@ "pulltorefresh": "Sakatu freskatzeko", "redirectingtosite": "Gunera berbideratua izango zara.", "refresh": "Freskatu", - "required": "Beharrezkoa", + "required": "Ezinbestekoa", "requireduserdatamissing": "Erabiltzaile honek beharrezkoak diren profileko datuak bete gabe ditu. Mesedez, bete itzazu datu hauek zure Moodle gunean eta saiatu berriz.
    {{$a}}", "retry": "Berriz saiatu", "save": "Gorde", - "search": "Bilatu", + "search": "Bilatu...", "searching": "Bilatzen", "searchresults": "Bilaketaren emaitzak", "sec": "seg", "secs": "segundu", "seemoredetail": "Klik egin hemen xehetasun gehiago ikusteko", - "send": "bidali", + "send": "Bidali", "sending": "Bidaltzen", "serverconnection": "Errorea zerbitzariarekin konektatzean", "show": "Erakutsi", @@ -178,13 +178,14 @@ "sizemb": "MB", "sizetb": "TB", "sorry": "Barkatu...", + "sortby": "Zeren arabera ordenatu", "start": "Hasiera", "submit": "Bidali", "success": "Ondo!", "tablet": "Tablet-a", "teachers": "Irakasleak", "thereisdatatosync": "Lineaz-kanpoko {{$a}} daude sinkronizatzeko .", - "time": "Ordua", + "time": "Denbora", "timesup": "Denbora amaitu egin da!", "today": "Gaur", "tryagain": "Saiatu berriz", @@ -207,7 +208,7 @@ "whyisthishappening": "Zergatik ari da hau gertatzen?", "windowsphone": "Windows Phone", "wsfunctionnotavailable": "Web-zerbitzu funtzioa ez dago eskuragarri.", - "year": "urtea", + "year": "Urte", "years": "urte", "yes": "Bai" } \ No newline at end of file diff --git a/www/core/lang/fa.json b/www/core/lang/fa.json index 0d4d923b0cc..80f79164356 100644 --- a/www/core/lang/fa.json +++ b/www/core/lang/fa.json @@ -4,12 +4,12 @@ "back": "بازگشت", "cancel": "انصراف", "cannotconnect": "اتصال به سایت ممکن نبود. بررسی کنید که نشانی سایت را درست وارد کرده باشید و اینکه سایت شما از مودل ۲٫۴ یا جدیدتر استفاده کند.", - "category": "طبقه", + "category": "دسته", "choose": "انتخاب کنید", "choosedots": "انتخاب کنید...", "clicktohideshow": "برای باز یا بسته شدن کلیک کنید", "close": "بستن پنجره", - "comments": "نظرات", + "comments": "توضیحات شما", "commentscount": "نظرات ({{$a}})", "completion-alt-auto-fail": "تکمیل شده است (بدون اکتساب نمرهٔ قبولی)", "completion-alt-auto-n": "تکمیل نشده است", @@ -32,11 +32,11 @@ "decsep": ".", "delete": "حذف", "deleting": "در حال حذف", - "description": "توضیح تکلیف", + "description": "توصیف", "done": "پر کرده است", "download": "دریافت", "edit": "ویرایش", - "error": "خطا", + "error": "خطا رخ داد", "errordownloading": "خطا در دانلود فایل", "folder": "پوشه", "forcepasswordchangenotice": "برای پیش‌روی باید رمز ورود خود را تغییر دهید.", @@ -48,14 +48,14 @@ "hour": "ساعت", "hours": "ساعت", "imageviewer": "نمایشگر تصویر", - "info": "توضیحات", + "info": "اطلاعات", "labelsep": ": ", "lastmodified": "آخرین تغییر", "listsep": ",", - "loading": "در حال بارگیری", + "loading": "دریافت اطلاعات...", "lostconnection": "اطلاعات توکن شناسایی شما معتبر نیست یا منقضی شده است. باید دوباره به سایت متصل شوید.", "maxsizeandattachments": "حداکثر اندازه برای فایل‌های جدید: {{$a.size}}، حداکثر تعداد فایل‌های پیوست: {{$a.attachments}}", - "min": "دقیقه", + "min": "کمترین امتیاز", "mins": "دقیقه", "mod_assign": "تکلیف", "mod_chat": "اتاق گفتگو", @@ -75,7 +75,7 @@ "never": "هیچ‌وقت", "next": "ادامه", "no": "خیر", - "nocomments": "بدون دیدگاه", + "nocomments": "نظری ارائه نشده است", "nograde": "بدون نمره", "none": "هیچ", "nopasswordchangeforced": "شما نمی‌توانید بدون تغییر رمز عبور ادامه دهید اما هیچ صفحه‌ای برای عوض کردن آن وجود ندارد. لطفا با مدیریت سایت تماس بگیرید.", @@ -93,15 +93,15 @@ "previous": "قبلی", "pulltorefresh": "برای تازه‌سازی بکشید", "refresh": "تازه‌سازی", - "required": "لازم است", + "required": "الزامی بودن", "save": "ذخیره", - "search": "جستجو", + "search": "جستجو...", "searching": "در حال جستجو در ...", - "searchresults": "نتیجهٔ جستجو", + "searchresults": "نتایج جستجو", "sec": "ثانیه", "secs": "ثانیه", "seemoredetail": "برای دیدن جزئیات بیشتر اینجا را کلیک کنید", - "send": "فرستادن", + "send": "ارسال", "sending": "در حال ارسال", "serverconnection": "خطا در اتصال به کارگزار", "show": "نمایش", @@ -112,8 +112,9 @@ "sizekb": "کیلوبایت", "sizemb": "مگابایت", "sorry": "متاسفیم...", + "sortby": "مرتب شدن بر اساس", "start": "آغاز", - "submit": "ارائه", + "submit": "ارسال", "success": "موفق", "teachers": "استاد", "time": "زمان", diff --git a/www/core/lang/fr.json b/www/core/lang/fr.json index 6b59ade573d..a9abbd16cc9 100644 --- a/www/core/lang/fr.json +++ b/www/core/lang/fr.json @@ -7,14 +7,18 @@ "cancel": "Annuler", "cannotconnect": "Connexion impossible : vérifiez que l'URL a été saisie correctement et que votre site utilise Moodle 2.4 ou ultérieur.", "cannotdownloadfiles": "Le téléchargement de fichiers est désactivé dans le service mobile de votre plateforme. Veuillez contacter l'administrateur de la plateforme.", + "captureaudio": "Enregistrer un son", + "capturedimage": "Photo prise", + "captureimage": "Prendre une photo", + "capturevideo": "Enregistrer une vidéo", "category": "Catégorie", "choose": "Choisir", "choosedots": "Choisir...", "clearsearch": "Effacer la recherche", "clicktohideshow": "Cliquer pour déplier ou replier", "clicktoseefull": "Cliquer pour voir tout le contenu.", - "close": "Fermer", - "comments": "Vos commentaires", + "close": "Fermer la prévisualisation", + "comments": "Commentaires", "commentscount": "Commentaires ({{$a}})", "commentsnotworking": "Les commentaires ne peuvent pas être récupérés", "completion-alt-auto-fail": "Terminé : {{$a}} (n'a pas atteint la note pour passer)", @@ -36,8 +40,8 @@ "currentdevice": "Appareil actuel", "datastoredoffline": "Données stockées sur l'appareil, car elles n'ont pas pu être envoyées. Elles seront automatiquement envoyées ultérieurement.", "date": "Date", - "day": "jour", - "days": "jours", + "day": "Jour(s)", + "days": "Jours", "decsep": ",", "defaultvalue": "Défaut ({{$a}})", "delete": "Supprimer", @@ -45,6 +49,7 @@ "description": "Description", "dfdaymonthyear": "DD-MM-YYYY", "dfdayweekmonth": "ddd, D MMM", + "dffulldate": "dddd, D MMMM YYYY h[:]mm A", "dflastweekdate": "ddd", "dfmediumdate": "LLL", "dftimedate": "hh[:]mm", @@ -54,7 +59,8 @@ "download": "Télécharger", "downloading": "Téléchargement en cours", "edit": "Modifier", - "error": "Erreur", + "emptysplit": "Cette page paraîtra vide si le panneau de gauche est vide ou en cours de chargement.", + "error": "Une erreur est survenue", "errorchangecompletion": "Une erreur est survenue lors du changement de l'état d'achèvement. Veuillez essayer à nouveau.", "errordeletefile": "Erreur lors de la suppression du fichier. Veuillez essayer à nouveau.", "errordownloading": "Erreur lors du téléchargement du fichier.", @@ -88,13 +94,15 @@ "info": "Info", "ios": "iOS", "labelsep": " ", - "lastmodified": "Modifié le", + "lastdownloaded": "Dernier téléchargement", + "lastmodified": "Dernière modification", "lastsync": "Dernière synchronisation", "listsep": ";", - "loading": "Chargement", + "loading": "Chargement...", + "loadmore": "Charger plus", "lostconnection": "Connexion perdue. Vous devez vous reconnecter. Votre jeton n'est plus valide", "maxsizeandattachments": "Taille maximale des nouveaux fichiers : {{$a.size}}. Nombre maximal d'annexes : {{$a.attachments}}", - "min": "min", + "min": "Score minimum", "mins": "min", "mod_assign": "Devoir", "mod_assignment": "Devoir", @@ -125,16 +133,16 @@ "moduleintro": "Description", "mygroups": "Mes groupes", "name": "Nom", - "networkerrormsg": "Réseau désactivé ou en panne.", + "networkerrormsg": "Un problème est survenu lors de la connexion au site. Veuillez vérifier votre connexion et essayer à nouveau.", "never": "Jamais", - "next": "Suivant", + "next": "Suite", "no": "Non", "nocomments": "Aucun commentaire", - "nograde": "Pas de note", + "nograde": "Aucune note.", "none": "Aucun", "nopasswordchangeforced": "Vous ne pouvez pas continuer ans changer votre mot de passe.", "nopermissions": "Désolé, vous n'avez actuellement pas les droits d'accès requis pour effectuer ceci ({{$a}})", - "noresults": "Aucun résultat", + "noresults": "Pas de résultat", "notapplicable": "n/a", "notice": "Remarque", "notsent": "Pas envoyé", @@ -157,7 +165,7 @@ "requireduserdatamissing": "Il manque certaines données au profil de cet utilisateur. Veuillez compléter ces données dans votre plateforme Moodle et essayer à nouveau.
    {{$a}}", "retry": "Essayer à nouveau", "save": "Enregistrer", - "search": "Rechercher", + "search": "Recherche", "searching": "Recherche", "searchresults": "Résultats de la recherche", "sec": "s", @@ -176,20 +184,21 @@ "sizemb": "Mo", "sizetb": "To", "sorry": "Désolé...", + "sortby": "Trier par", "start": "Début", "submit": "Envoyer", "success": "Succès !", "tablet": "Tablette", "teachers": "Enseignants", "thereisdatatosync": "Il y a des {{$a}} locales à synchroniser", - "time": "Heure", + "time": "Temps", "timesup": "Le chrono est enclenché !", "today": "Aujourd'hui", "tryagain": "Essayer encore", "twoparagraphs": "{{p1}}

    {{p2}}", "uhoh": "Aïe !", "unexpectederror": "Erreur inattendue. Veuillez fermer et rouvrir l'app pour continuer", - "unicodenotsupported": "Les caractères encodés en Unicode, par exemple les emojis, ne sont pas supportés sur ce site. Ces caractères seront supprimés avant l'envoi.", + "unicodenotsupported": "Certains emojis ne sont pas supportés sur ce site. Ils seront supprimés avant l'envoi.", "unicodenotsupportedcleanerror": "Un texte vide a été rencontré lors du nettoyage des caractères Unicode.", "unknown": "Inconnu", "unlimited": "Illimité", @@ -199,14 +208,14 @@ "userdetails": "Informations détaillées", "usernotfullysetup": "Utilisateur pas complètement défini", "users": "Utilisateurs", - "view": "Affichage", + "view": "Afficher", "viewprofile": "Consulter le profil", "warningofflinedatadeleted": "Des données locales de {{component}} « {{name}} » ont été supprimées. {{error}}", "whoops": "Oups !", "whyisthishappening": "Que se passe-t-il ?", "windowsphone": "Windows phone", "wsfunctionnotavailable": "La fonction webservice n'est pas disponible", - "year": "année", + "year": "Année(s)", "years": "années", "yes": "Oui" } \ No newline at end of file diff --git a/www/core/lang/he.json b/www/core/lang/he.json index d0306063c87..abb00055b11 100644 --- a/www/core/lang/he.json +++ b/www/core/lang/he.json @@ -11,27 +11,27 @@ "choosedots": "בחירה...", "clearsearch": "איפוס חיפוש", "clicktohideshow": "הקש להרחבה או לצמצום", - "close": "סגירה", - "comments": "ההערות שלך", + "close": "סגירת חלון", + "comments": "הערות", "commentscount": "({{$a}}) הערות", - "completion-alt-auto-fail": "הושלם: {{$a}} (לא השיג ציון עובר)", + "completion-alt-auto-fail": "הושלם: {{$a}} (לא הושג ציון עובר)", "completion-alt-auto-n": "לא הושלם: {{$a}}", - "completion-alt-auto-pass": "הושלם: {{$a}} (השיג ציון עובר)", + "completion-alt-auto-pass": "הושלם: {{$a}} (הושג ציון עובר)", "completion-alt-auto-y": "הושלם: {{$a}}", - "completion-alt-manual-n": "{{$a}} לא הושלם. הקליקו לסימון כ\"הושלם\"", - "completion-alt-manual-y": "{{$a}} הושלם. הקליקו לסימון כ\"לא הושלם\"", + "completion-alt-manual-n": "לא הושלם: {{$a}}. יש לבחור כדי לסמן כ:הושלם.", + "completion-alt-manual-y": "הושלם: {{$a}}. יש לבחור כדי לסמן כ:לא-הושלם.", "confirmdeletefile": "האם הינך בטוח כי ברצונך למחוק את קובץ זה?", "content": "תוכן", "continue": "המשך", "course": "קורס", "coursedetails": "פרטי הקורס", "date": "תאריך", - "day": "יום", + "day": "ימים", "days": "ימים", "decsep": ".", "delete": "מחיקה", "deleting": "מוחק", - "description": "תיאור", + "description": "הנחיה למטלה", "dfdayweekmonth": "dddd, D MMMM", "dflastweekdate": "dddd", "dftimedate": "hh[:]mm", @@ -39,7 +39,7 @@ "download": "הורדה", "downloading": "מוריד", "edit": "עריכה", - "error": "טעות", + "error": "שגיאה התרחשה", "errordownloading": "שגיאה בהורדת קובץ", "errordownloadingsomefiles": "שגיאה בהורדת קבצי המודול. יתכן וחלק מהקבצים חסרים.", "filename": "שם הקובץ", @@ -56,12 +56,12 @@ "imageviewer": "מציג תמונות", "info": "מידע", "labelsep": ":", - "lastmodified": "שינוי אחרון", + "lastmodified": "עדכון אחרון", "listsep": ",", - "loading": "טוען...", + "loading": "טעינה", "lostconnection": "לקוד הזיהוי המאובטח שלך פג התוקף, ולכן החיבור נותק. עליך להתחבר שוב.", "maxsizeandattachments": "נפח קבצים מירבי: {{$a.size}}, מספר קבצים מצורפים מירבי: {{$a.attachments}}", - "min": "דקה", + "min": "תוצאה מינמלית", "mins": "דקות", "mod_assign": "מטלה", "mod_assignment": "מטלה", @@ -90,23 +90,23 @@ "mod_wiki": "ויקי (תוצר משותף)", "mod_workshop": "הערכת־עמיתים", "moduleintro": "הנחיה לפעילות", - "name": "שם:", + "name": "שם", "networkerrormsg": "הרשת לא מופעלת או לא עובדת.", - "never": "אף פעם לא", - "next": "הבא", + "never": "לעולם לא", + "next": "הבא אחריו", "no": "לא", - "nocomments": "ללא הערות", + "nocomments": "אין הערות", "nograde": "אין ציון", - "none": "אין", + "none": "ללא", "nopasswordchangeforced": "אינך יכול להמשיך ללא שינוי הסיסמה שלך. אך נכון לעכשיו אין דף זמין בו ניתן לשנותה. אנא צור קשר עם מנהל המוודל שלך.", "nopermissions": "למשתמש שלכם אין את ההרשאה לבצע את הפעולה \"{{$a}}\".\n
    \nיש לפנות למנהל(ת) המערכת שלכם לקבלת ההרשאות המתאימות.", - "noresults": "אין תוצאות", + "noresults": "לא נמצאו תוצאות", "notapplicable": "לא זמין", "notice": "לתשומת לב", "now": "עכשיו", "numwords": "{{$a}} מילים", - "offline": "לא נדרשות הגשות מקוונות", - "online": "מקוון", + "offline": "לא מחובר", + "online": "מחובר", "openfullimage": "יש להקליק כאן להצגת התמונה בגודל מלא", "openinbrowser": "תצוגה בדפדפן", "pagea": "עמוד {{$a}}", @@ -115,27 +115,28 @@ "previous": "קודם", "pulltorefresh": "משיכה לרענון", "refresh": "רענון", - "required": "דרוש", + "required": "נדרש", "requireduserdatamissing": "למשתמש זה חסרים שדות נדרשים בפרופיל המשתמש. יש להשלים מידע זה באתר המוודל שלך ולנסות שוב.
    {{$a}}", "save": "שמירה", - "search": "חיפוש", - "searching": "חיפוש ב-", - "searchresults": "תוצאות חיפוש", + "search": "חפשו", + "searching": "מחפש ב...", + "searchresults": "תוצאות החיפוש", "sec": "שניה", "secs": "שניות", "seemoredetail": "הקליקו כאן כדי לראות פרטים נוספים", - "send": "שליחה", - "sending": "שולחים", + "send": "לשלוח", + "sending": "שולח", "serverconnection": "שגיאה בהתחברות לשרת", - "show": "הצגה", + "show": "תצוגה", "site": "מערכת", "sizeb": "בתים", "sizegb": "GB", "sizekb": "KB", "sizemb": "MB", + "sortby": "מיון לפי", "start": "התחלה", - "submit": "שמירה", - "success": "הצלחה", + "submit": "הגש", + "success": "הצלחה!", "tablet": "טאבלט", "teachers": "מורים", "time": "זמן", @@ -148,10 +149,10 @@ "userdeleted": "חשבון משתמש זה נמחק", "userdetails": "מאפייניי המשתמש", "users": "משתמשים", - "view": "תצוגה", + "view": "צפיה", "viewprofile": "תצוגת מאפיינים", "whoops": "אוווווופס!", - "year": "שנה", + "year": "שנים", "years": "שנים", "yes": "כן" } \ No newline at end of file diff --git a/www/core/lang/hu.json b/www/core/lang/hu.json index 6376ed158d7..3ae8c76a690 100644 --- a/www/core/lang/hu.json +++ b/www/core/lang/hu.json @@ -2,14 +2,14 @@ "allparticipants": "Összes résztvevő", "areyousure": "Biztos?", "back": "Vissza", - "cancel": "Mégse", + "cancel": "Törlés", "cannotconnect": "Sikertelen kapcsolódás: ellenőrizze, jó-e az URL és a portál legalább 2.4-es Moodle-t használ-e.", "category": "Kategória", "choose": "Választás", "choosedots": "Választás...", "clicktohideshow": "Kattintson a kibontáshoz vagy a becsukáshoz.", - "close": "Bezárás", - "comments": "Megjegyzései", + "close": "Ablak bezárása", + "comments": "Megjegyzések", "commentscount": "Megjegyzések ({{$a}})", "completion-alt-auto-fail": "Teljesítve: {{$a}} (a teljesítési pontszámot nem érte el)", "completion-alt-auto-n": "Nincs teljesítve: {{$a}}", @@ -19,22 +19,22 @@ "completion-alt-manual-y": "Teljesítve: {{$a}}, teljesítetlenként való megjelöléséhez válassza ki.", "confirmdeletefile": "Biztosan törli ezt az állományt?", "content": "Tartalom", - "continue": "Folytatás", + "continue": "Tovább", "course": "Kurzus", "coursedetails": "Kurzusadatok", "date": "Dátum", "day": "nap", - "days": "nap", + "days": "Nap", "decsep": ",", "defaultvalue": "Alapeset ({{$a}})", "delete": "Törlés", "deleting": "Törlés", - "description": "Bevezető szöveg", + "description": "Leírás", "done": "Kész", "download": "Letöltés", "downloading": "Letöltés...", "edit": "Szerkesztés", - "error": "Hiba", + "error": "Hiba történt.", "errordownloading": "Nem sikerült letölteni az állományt.", "filename": "Állománynév", "folder": "Mappa", @@ -46,14 +46,14 @@ "hide": "Elrejtés", "hour": "óra", "hours": "óra", - "info": "Információ", + "info": "Információk", "labelsep": ":", - "lastmodified": "Utolsó módosítás", + "lastmodified": "Utolsó módosítás dátuma:", "listsep": ";", - "loading": "Betöltés", + "loading": "Betöltés...", "lostconnection": "A kapcsolat megszakadt, kacsolódjon újból. Jele érvénytelen.", "maxsizeandattachments": "Új állományok maximális mérete: {{$a.size}}, maximális csatolt állomány: {{$a.attachments}}", - "min": "p", + "min": "Min. pontszám", "mins": "perc", "mod_assign": "Feladat", "mod_chat": "Csevegés", @@ -68,21 +68,21 @@ "mod_survey": "Felmérés", "mod_wiki": "Wiki", "moduleintro": "Leírás", - "name": "Név:", + "name": "Név", "networkerrormsg": "A hálózat nincs bekapcsolva vagy nem működik.", "never": "Soha", - "next": "Következő", + "next": "Tovább", "no": "Nem", - "nocomments": "Nincs megjegyzés.", - "nograde": "Nincs pont", - "none": "Nincs", + "nocomments": "Nincs megjegyzés", + "nograde": "Nincs osztályzat", + "none": "Egy sem", "nopasswordchangeforced": "A továbblépéshez először módosítania kell a jelszavát, ehhez azonban nem áll rendelkezésre megfelelő oldal. Forduljon a Moodle rendszergazdájához.", "nopermissions": "Ehhez ({{$a}}) jelenleg nincs engedélye", "noresults": "Nincs eredmény", "notice": "Tájékoztatás", "now": "most", "numwords": "{{$a}} szó", - "offline": "Nincs szükség neten keresztüli leadásra", + "offline": "Offline", "online": "Online", "pagea": "{{$a}} oldal", "phone": "Telefon", @@ -91,21 +91,22 @@ "refresh": "Frissítés", "required": "Kitöltendő", "save": "Mentés", - "search": "Keresés", - "searching": "Hol keres?", + "search": "Keresés...", + "searching": "Keresés helye ...", "searchresults": "Keresési eredmények", "sec": "mp", "secs": "mp", "seemoredetail": "A részletekért kattintson ide", - "send": "Elküld", + "send": "küldés", "sending": "Küldés", "serverconnection": "Hiba a szerverhez csatlakozás közben", - "show": "Megjelenítés", + "show": "Mutat", "site": "Portál", "sizeb": "bájt", "sizegb": "GB", "sizekb": "KB", "sizemb": "MB", + "sortby": "Rendezési szempont", "start": "Kezdés", "submit": "Leadás", "success": "Sikerült", @@ -121,9 +122,9 @@ "userdetails": "Felhasználó adatai", "usernotfullysetup": "A felhasználó beállítása még nincs kész", "users": "Felhasználó", - "view": "Nézet", + "view": "Megtekintés", "viewprofile": "Profil megtekintése", - "year": "év", + "year": "Év", "years": "év", "yes": "Igen" } \ No newline at end of file diff --git a/www/core/lang/it.json b/www/core/lang/it.json index fca22023ba9..08162d7a645 100644 --- a/www/core/lang/it.json +++ b/www/core/lang/it.json @@ -12,8 +12,8 @@ "clearsearch": "Pulisci la ricerca", "clicktohideshow": "Click per aprire e chiudere", "clicktoseefull": "Click per visualizzare il contenuto completo.", - "close": "Chiudi", - "comments": "I tuoi commenti", + "close": "Chiudi finestra", + "comments": "Commenti", "commentscount": "Commenti: ({{$a}})", "commentsnotworking": "Non è possibile scaricare i commenti", "completion-alt-auto-fail": "Completato: {{$a}} (senza la sufficienza)", @@ -30,13 +30,13 @@ "course": "Corso", "coursedetails": "Dettagli corso", "date": "Data", - "day": "giorno", - "days": "giorni", + "day": "Giorni", + "days": "Giorni", "decsep": ",", "defaultvalue": "Default ({{$a}})", "delete": "Elimina", "deleting": "Eliminazione in corso", - "description": "Commento", + "description": "Descrizione", "dfdayweekmonth": "ddd, D MMM", "dflastweekdate": "ddd", "dfmediumdate": "LLL", @@ -45,7 +45,7 @@ "download": "Download", "downloading": "Scaricamento in corso", "edit": "Modifica", - "error": "Errore", + "error": "Si è verificato un errore", "errorchangecompletion": "Si è verificato un errore durante la modifica dello stato di completamento. Per favore riprova.", "errordeletefile": "Si è verificato un errore durante l'eliminazione del file. Per favore riprova.", "errordownloading": "Si è verificato un errore durante lo scaricamento del file.", @@ -73,13 +73,13 @@ "info": "Informazioni", "ios": "iOS", "labelsep": ": ", - "lastmodified": "Ultime modifiche", + "lastmodified": "Ultima modifica", "lastsync": "Ultima sincronizzazione", "listsep": ";", - "loading": "Caricamento in corso", + "loading": "Caricamento in corso...", "lostconnection": "La connessione è stata perduta. Il tuo token non è più valido.", "maxsizeandattachments": "Dimensione massima per i file nuovi: {{$a.size}}, numero massimo di allegati: {{$a.attachments}}", - "min": "min.", + "min": "Punteggio minimo", "mins": "min.", "mod_assign": "Compito", "mod_assignment": "Compito", @@ -109,13 +109,13 @@ "mod_workshop": "Workshop", "moduleintro": "Descrizione", "mygroups": "I miei gruppi", - "name": "Titolo", + "name": "Nome", "networkerrormsg": "La rete non è abilitata o non funziona.", "never": "Mai", - "next": "Successivo", + "next": "Continua", "no": "No", "nocomments": "Non ci sono commenti", - "nograde": "Senza valutazione", + "nograde": "Nessuna valutazione.", "none": "Nessuno", "nopasswordchangeforced": "Non puoi proseguire senza modificare la tua password, ma non c'è una pagina per cambiarla. Contatta il tuo amministratore Moodle.", "nopermissions": "Spiacente, ma attualmente non avete il permesso per fare questo ({{$a}})", @@ -136,17 +136,17 @@ "previous": "Precedente", "pulltorefresh": "Trascina per aggiornare", "refresh": "Aggiorna", - "required": "La risposta è obbligatoria", + "required": "Obbligatorio", "requireduserdatamissing": "Nel profilo di questo utente mancano alcuni dati. Per favore compila i dati mancanti in Moodle e riprova.
    {{$a}}", "retry": "Riprova", "save": "Salva", - "search": "Cerca", + "search": "Ricerca", "searching": "Ricerca in corso", - "searchresults": "Risultati della ricerca", + "searchresults": "Risultati delle ricerche", "sec": "secondo", "secs": "secondi", "seemoredetail": "Clicca qui per ulteriori dettagli", - "send": "invia", + "send": "Invia", "sending": "Invio in c orso", "serverconnection": "Si è verificato un errore durante la connessione al server", "show": "Visualizza", @@ -156,12 +156,13 @@ "sizekb": "KB", "sizemb": "MB", "sizetb": "TB", + "sortby": "Ordina per", "start": "Apertura", "submit": "Invia", "success": "OK!", "tablet": "Tablet", "teachers": "Docenti", - "time": "Data/Ora", + "time": "Tempo", "timesup": "Tempo scaduto!", "today": "Oggi", "twoparagraphs": "{{p1}}

    {{p2}}", @@ -179,7 +180,7 @@ "whoops": "Oops!", "windowsphone": "Windows Phone", "wsfunctionnotavailable": "La funzione webservice non è disponibile.", - "year": "anno", + "year": "Anni", "years": "anni", - "yes": "Sì" + "yes": "Si" } \ No newline at end of file diff --git a/www/core/lang/ja.json b/www/core/lang/ja.json index 72124e5922a..09c885988cd 100644 --- a/www/core/lang/ja.json +++ b/www/core/lang/ja.json @@ -1,59 +1,103 @@ { + "accounts": "アカウント", "allparticipants": "すべての参加者", + "android": "Android", "areyousure": "本当によろしいですか?", "back": "戻る", "cancel": "キャンセル", "cannotconnect": "接続できません:正しいURLを入力しているか、サイトのMoodleが2.4以降であることを確認してください。", + "cannotdownloadfiles": "ダウンロードしようとしているファイルは、あなたのモバイルサービスでは無効になっています。あなたのサイト管理者に連絡してください。", "category": "カテゴリ", "choose": "選択", "choosedots": "選択 ...", + "clearsearch": "検索のクリア", "clicktohideshow": "展開または折りたたむにはここをクリックしてください。", - "close": "閉じる", - "comments": "あなたのコメント", + "clicktoseefull": "クリックで全てのコンテンツを見る", + "close": "ウィンドウを閉じる", + "comments": "コメント", "commentscount": "コメント ({{$a}})", - "completion-alt-auto-fail": "完了: {{$a}} (合格点未到達)", - "completion-alt-auto-n": "未完了: {{$a}}", - "completion-alt-auto-pass": "完了: {{$a}} (合格点到達)", + "commentsnotworking": "コメントが取得できませんでした", + "completion-alt-auto-fail": "完了: {{$a}} (合格点に達していない)", + "completion-alt-auto-n": "未了: {{$a}}", + "completion-alt-auto-pass": "完了: {{$a}} (合格点達成)", "completion-alt-auto-y": "完了: {{$a}}", - "completion-alt-manual-n": "未完了: {{$a}} 完了マークするには選択してください。", - "completion-alt-manual-y": "完了: {{$a}} 未完了マークするには選択してください。", + "completion-alt-manual-n": "未了: {{$a}}。選択して完了に変更してください。", + "completion-alt-manual-y": "完了: {{$a}}。選択して未了に変更してください。", + "confirmcanceledit": "本当にこのページを離れますか? 全ての変更が失われます。", "confirmdeletefile": "本当にこのファイルを削除してもよろしいですか?", + "confirmloss": "本当ですか? すべての変更が失われます。", + "confirmopeninbrowser": "これをブラウザで開きますか?", "content": "コンテンツ", + "contenteditingsynced": "編集中のコンテンツが同期されました。", "continue": "続ける", + "copiedtoclipboard": "クリップボードにコピーされたテキスト", "course": "コース", "coursedetails": "コース詳細", + "currentdevice": "現在のデバイス", + "datastoredoffline": "送信できなかったため、データはデバイスに保存されました。後で自動的に送信されます。", "date": "日付", "day": "日", "days": "日", "decsep": ".", "defaultvalue": "デフォルト ({{$a}})", "delete": "削除", - "deleting": "削除中", + "deleting": "消去中", "description": "説明", + "dfdaymonthyear": "YYYY/MM/DD", + "dfdayweekmonth": "MMM月D日(ddd)", + "dffulldate": "YYYY年MMMM月D日(dddd) h[:]mm A", + "dflastweekdate": "ddd", + "dfmediumdate": "LLL", + "dftimedate": "h[:]mm A", + "discard": "無視", + "dismiss": "取消", "done": "完了", "download": "ダウンロード", - "downloading": "ダウンロード中 ...", + "downloading": "ダウンロード中", "edit": "編集", - "error": "エラー", - "errordownloading": "ファイルのダウンロードのエラー", + "emptysplit": "左パネルが空またはロード中のため本ページは空白", + "error": "エラーが発生しました。", + "errorchangecompletion": "完了状態の変更中にエラーが発生しました。再度実行してください。", + "errordeletefile": "ファイル消去中にエラーが発生しました。再度実行してください。", + "errordownloading": "ファイルダウンロードのエラー", + "errordownloadingsomefiles": "モジュールファイルのダウンロード中にエラーが発生しました。欠落しているファイルがあるかもしれません。", + "errorfileexistssamename": "同じ名前のファイルがあります。", + "errorinvalidform": "フォームに不正なデータが含まれています。必須フィールドすべてが記入され、データが正しいことを確認してください。", + "errorinvalidresponse": "不正な返信を受信しました。エラーが連続する場合、あなたのMoodleサイト管理者に連絡をとってください。", + "errorloadingcontent": "コンテンツのロード中にエラーが発生しました。", + "erroropenfilenoapp": "ファイルを開く際にエラーが発生しました。この種のファイルを開くアプリが見つかりません。", + "erroropenfilenoextension": "ファイルを開く際にエラーが発生しました。ファイルに拡張子がありません。", + "erroropenpopup": "このアクティビティはポップアップを開こうとしています。本アプリではサポートされていません。", + "errorrenamefile": "ファイル名変更でエラーが発生しました。再度実行してください。", + "errorsync": "同期中にエラーが発生しました。再度実行してください。", + "errorsyncblocked": "実行中のプロセスがあったため、この {{$a}} はすぐに同期できませんでした。再度実行してください。問題が継続する場合、アプリを再起動してください。", "filename": "ファイル名", + "filenameexist": "ファイル名がすでに存在しています:{{$a}}", "folder": "フォルダ", "forcepasswordchangenotice": "続けるにはパスワードを変更してください。", "fulllistofcourses": "すべてのコース", + "fullnameandsitename": "{{fullname}} ({{sitename}})", "groupsseparate": "分離グループ", "groupsvisible": "可視グループ", + "hasdatatosync": "この {{$a}} には同期すべきオフラインデータがあります。", "help": "ヘルプ", "hide": "非表示", "hour": "時間", "hours": "時間", + "humanreadablesize": "{{size}} {{unit}}", + "image": "画像", + "imageviewer": "画像ビューア", "info": "情報", + "ios": "iOS", "labelsep": ":", "lastmodified": "最終更新日時", + "lastsync": "最後の同期", "listsep": ",", - "loading": "読み込み", + "loading": "読み込み中 ...", + "loadmore": "続きを読み込む", "lostconnection": "あなたのトークンが無効になったため、再接続に必要な情報がサーバにはありません。", "maxsizeandattachments": "新しいファイルの最大サイズ: {{$a.size}} / 最大添付: {{$a.attachments}}", - "min": "分", + "min": "最小評点", "mins": "分", "mod_assign": "課題", "mod_chat": "チャット", @@ -68,31 +112,42 @@ "mod_survey": "調査", "mod_wiki": "Wiki", "moduleintro": "説明", + "mygroups": "マイグループ", "name": "名称", "networkerrormsg": "ネットワークが無効もしくは機能していません", "never": "なし", - "next": "次へ", + "next": "続ける", "no": "No", - "nocomments": "コメントなし", + "nocomments": "コメントはありません。", "nograde": "評点なし", "none": "なし", - "nopasswordchangeforced": "あなたはパスワードを変更せずに次へ進むことはできません。しかし、パスワードを変更するため利用できるページがありません。あなたのMoodle管理者にご連絡ください。", + "nopasswordchangeforced": "パスワードを変更するまで続きを実行できません。", "nopermissions": "申し訳ございません、現在、あなたは 「 {{$a}} 」を実行するためのパーミッションがありません。", "noresults": "該当データがありません。", + "notapplicable": "なし", "notice": "警告", + "notsent": "未送信", "now": "現在", "numwords": "{{$a}} 語", - "offline": "オンライン提出不要", + "offline": "オフライン", "online": "オンライン", + "openfullimage": "クリックしてフルサイズの画像を表示", + "openinbrowser": "ブラウザで開く", + "othergroups": "他のグループ", "pagea": "ページ {{$a}}", + "percentagenumber": "{{$a}}%", "phone": "電話", "pictureof": "画像 {{$a}}", "previous": "前へ", + "pulltorefresh": "引いて更新", + "redirectingtosite": "サイトにリダイレクトされます。", "refresh": "リフレッシュ", "required": "必須", + "requireduserdatamissing": "このユーザは必須のプロフィールデータが欠けています。Moodleでデータを補い、再度開いてください。
    {{$a}}", + "retry": "再実行", "save": "保存", - "search": "検索", - "searching": "検索:", + "search": "検索 ...", + "searching": "検索中", "searchresults": "検索結果", "sec": "秒", "secs": "秒", @@ -101,21 +156,34 @@ "sending": "送信中", "serverconnection": "サーバへの接続中にエラーが発生しました。", "show": "表示", + "showmore": "さらに表示...", "site": "サイト", + "sitemaintenance": "サイトがメンテナンス中のため、現在利用できません。", "sizeb": "バイト", "sizegb": "GB", "sizekb": "KB", "sizemb": "MB", + "sizetb": "TB", + "sorry": "すみません...", + "sortby": "並べ替え", "start": "開始", "submit": "送信", - "success": "成功", + "success": "成功!", + "tablet": "タブレット", "teachers": "教師", + "thereisdatatosync": "同期が必要なオフライン {{$a}} があります。", "time": "時間", "timesup": "時間終了!", "today": "本日", + "tryagain": "再実行", + "twoparagraphs": "{{p1}}

    {{p2}}", + "uhoh": "おおっと!", "unexpectederror": "不明なエラー。アプリを閉じて再起動してみてください。", - "unknown": "不明", + "unicodenotsupported": "本サイトでは一部の絵文字がサポートされていません。それらは送信されたメッセージから削除されます。", + "unicodenotsupportedcleanerror": "Unicode文字をクリアする際に空のテキストがありました。", + "unknown": "不明な", "unlimited": "無制限", + "unzipping": "未展開の", "upgraderunning": "サイトはアップグレード中です。後ほどお試しください。", "userdeleted": "このユーザのアカウントは削除されました。", "userdetails": "ユーザ詳細", @@ -123,6 +191,8 @@ "users": "ユーザ", "view": "表示", "viewprofile": "プロファイルを表示する", + "whoops": "しまった!", + "windowsphone": "Windows Phone", "year": "年", "years": "年", "yes": "Yes" diff --git a/www/core/lang/lt.json b/www/core/lang/lt.json index 599e752d69d..8b5aff4a572 100644 --- a/www/core/lang/lt.json +++ b/www/core/lang/lt.json @@ -7,22 +7,22 @@ "cancel": "Atšaukti", "cannotconnect": "Negalima prisijungti: patikrinkite, ar teisingai įvedėte URL adresą, ar Jūsų svetainė naudoja Moodle 2.4. ar vėlesnę versiją.", "cannotdownloadfiles": "Jūsų mobiliuoju ryšiu negalima atsisiųsti failo. Prašome susisiekti su svetainės administratoriumi.", - "category": "Kursų kategorija", + "category": "Kategorija", "choose": "Pasirinkite", "choosedots": "Pasirinkite...", "clearsearch": "Išvalyti peiškos laukelį", "clicktohideshow": "Spustelėkite, kad išplėstumėte ar sutrauktumėte", "clicktoseefull": "Paspauskite norėdami pamatyti visą turinį.", - "close": "Uždaryti", - "comments": "Jūsų komentarai", + "close": "Uždaryti langą", + "comments": "Komentarai", "commentscount": "Komentarai ({{$a}})", "commentsnotworking": "Komentarų negalima ištaisyti", - "completion-alt-auto-fail": "Baigta: {{$a}} (nepasiekta)", + "completion-alt-auto-fail": "Užbaigta: {{$a}} (negautas išlaikymo įvertis)", "completion-alt-auto-n": "Nebaigta: {{$a}}", - "completion-alt-auto-pass": "Baigta: {{$a}} (pasiekta)", - "completion-alt-auto-y": "Baigta: {{$a}}", - "completion-alt-manual-n": "Nebaigta: {{$a}}. Pažymėti, kaip baigtą", - "completion-alt-manual-y": "Baigta: {{$a}}. Pažymėti, kaip nebaigtą.", + "completion-alt-auto-pass": "Užbaigta: {{$a}} (gautas išlaikymo įvertis)", + "completion-alt-auto-y": "Užbaigta: {{$a}}", + "completion-alt-manual-n": "Dar neužbaigta: {{$a}}. Pasirinkti pažymėti kaip užbaigtą", + "completion-alt-manual-y": "Užbaigta: {{$a}}. Pasirinkti pažymėti kaip nebaigtą", "confirmcanceledit": "Ar tikrai norite išeiti iš šio puslapio? Visi pakeitimai bus prarasti.", "confirmdeletefile": "Ar tikrai norite naikinti šį failą?", "confirmopeninbrowser": "Ar norite tai atidaryti naršyklėje?", @@ -34,12 +34,12 @@ "currentdevice": "Dabartinis prietaisas", "datastoredoffline": "Duomenys saugomi įrenginyje, nes šiuo metu negalima išsiųsti. Bus vėlaiu išsiųsti automatiškai.", "date": "Data", - "day": "diena", - "days": "dienos", + "day": "Diena(-os)", + "days": "Dienos", "decsep": ".", - "delete": "Naikinti", + "delete": "Pašalinti", "deleting": "Trinama", - "description": "Aprašas", + "description": "Įžangos tekstas", "dfdaymonthyear": "MM-DD-MMMM", "dfdayweekmonth": "ddd, D MMM", "dflastweekdate": "ddd", @@ -51,7 +51,7 @@ "download": "Atsisiųsti", "downloading": "Siunčiama", "edit": "Redaguoti", - "error": "Klaida", + "error": "Įvyko klaida", "errorchangecompletion": "Klaida keičiant baigimo būseną. Pabandykite dar kartą.", "errordeletefile": "Klaida trinant failą. Pabandykite dar kartą.", "errordownloading": "Klaida siunčiant failą.", @@ -74,7 +74,7 @@ "groupsseparate": "Atskiros grupės", "groupsvisible": "Matomos grupės", "hasdatatosync": "{{$a}} turi duomenis, kuriuos reikia sinchronizuoti.", - "help": "Žinynas", + "help": "Pagalba", "hide": "Slėpti", "hour": "valanda", "hours": "valandos", @@ -84,13 +84,13 @@ "info": "Informacija", "ios": "iOS", "labelsep": ":", - "lastmodified": "Paskutinį kartą modifikuota", + "lastmodified": "Paskutinį kartą keista", "lastsync": "Paskutinis sinchronizavimas", "listsep": ";", - "loading": "Įkeliama...", + "loading": "Kraunasi", "lostconnection": "Jūsų atpažinimo kodas neteisingas arba negalioja, turėsite vėl prisijungti prie svetainės.", "maxsizeandattachments": "Maksimalus naujo failo dydis: {{$a.size}}, maksimalus priedų skaičius: {{$a.attachments}}", - "min": "min.", + "min": "Mažiausias balas", "mins": "min.", "mod_assign": "Užduotis", "mod_assignment": "Užduotis", @@ -120,14 +120,14 @@ "mod_workshop": "Darbas grupėje", "moduleintro": "Aprašas", "mygroups": "Mano grupės", - "name": "Vardas", + "name": "Pavadinimas", "networkerrormsg": "Tinklas nepasiekiamas arba neveikia.", "never": "Niekada", - "next": "Pirmyn", + "next": "Tęsti", "no": "Ne", - "nocomments": "Jokių komentarų", - "nograde": "Nėra įverčio", - "none": "Nei vienas", + "nocomments": "Nėra komentarų", + "nograde": "Nėra įvertinimų.", + "none": "Nėra", "nopasswordchangeforced": "Nepakeitus slaptažodžio, negalima tęsti.", "nopermissions": "Atsiprašome, tačiau šiuo metu jūs neturite teisės atlikti šio veiksmo", "noresults": "Nėra rezultatų", @@ -149,17 +149,17 @@ "pulltorefresh": "Atnaujinti", "redirectingtosite": "Būsite nukreiptas į svetainę.", "refresh": "Atnaujinti", - "required": "Būtina", + "required": "Privalomas", "requireduserdatamissing": "Trūkta vartotojo duomenų. Prašome užpildyti duomenis Moodle ir pabandyti dar kartą.
    {{$a}}", "retry": "Bandykite dar kartą", - "save": "Įrašyti", - "search": "Ieškoti", + "save": "Išsaugoti", + "search": "Paieška", "searching": "Ieškoma", "searchresults": "Ieškos rezultatai", "sec": "sek.", "secs": "sek.", "seemoredetail": "Spustelėkite čia, kad pamatytumėte daugiau informacijos", - "send": "siųsti", + "send": "Siųsti", "sending": "Siunčiama", "serverconnection": "Klaida jungiantis į serverį", "show": "Rodyti", @@ -172,9 +172,10 @@ "sizemb": "MB", "sizetb": "TB", "sorry": "Atsiprašome...", + "sortby": "Rūšiuoti pagal", "start": "Pradėti", "submit": "Pateikti", - "success": "Sėkmė!", + "success": "Sėkmingai", "tablet": "Planšetė", "teachers": "Dėstytojai", "thereisdatatosync": "Neprijungtas {{$a}}, kad sinchronizuotų.", @@ -199,7 +200,7 @@ "whyisthishappening": "Kodėl tai nutiko?", "windowsphone": "Windows telefonas", "wsfunctionnotavailable": "Interneto paslaugų funkcija nepasiekiama.", - "year": "metai", + "year": "Metai (-ų)", "years": "metai", "yes": "Taip" } \ No newline at end of file diff --git a/www/core/lang/nl.json b/www/core/lang/nl.json index 59efdc360b6..5bffa08b133 100644 --- a/www/core/lang/nl.json +++ b/www/core/lang/nl.json @@ -7,14 +7,18 @@ "cancel": "Annuleer", "cannotconnect": "Kan niet verbinden: controleer of je de URL juist hebt ingegeven en dat je site Moodle 2.4 of recenter gebruikt.", "cannotdownloadfiles": "Bestanden downloaden is uitgeschakeld voor jouw mobiele service. Neem contact op met je systeembeheerder.", + "captureaudio": "Audio opnemen", + "capturedimage": "Foto genomen.", + "captureimage": "Maak foto", + "capturevideo": "Film opnemen", "category": "Categorie", "choose": "Kies", "choosedots": "Kies...", "clearsearch": "Zoekresultaten leegmaken", "clicktohideshow": "Klik om te vergroten of te verkleinen", "clicktoseefull": "Klik hier om de volledige inhoud te zien", - "close": "Sluit", - "comments": "Notities", + "close": "Sluit weergave test", + "comments": "Jouw commentaar", "commentscount": "Opmerkingen ({{$a}})", "commentsnotworking": "Opmerkingen konden niet opgehaald worden", "completion-alt-auto-fail": "Voltooid: {{$a}} (slaagcijfer niet behaald)", @@ -29,20 +33,20 @@ "confirmopeninbrowser": "Wil je het openen in je browser?", "content": "Inhoud", "contenteditingsynced": "De inhoud die je aan het bewerken bent, is gesynchroniseerd.", - "continue": "Ga door", + "continue": "Ga verder", "copiedtoclipboard": "Tekst gekopieerd naar klembord", "course": "Cursus", "coursedetails": "Cursusdetails", "currentdevice": "Huidig apparaat", "datastoredoffline": "Gegevens die bewaard werden op het toestel konden niet verstuurd worden. Ze zullen later automatisch verzonden worden.", "date": "Datum", - "day": "dag", - "days": "dagen", + "day": "Dag(en)", + "days": "Dagen", "decsep": ",", "defaultvalue": "Standaard ({{$a}})", "delete": "Verwijder", "deleting": "Verwijderen.", - "description": "Inleidende tekst", + "description": "Beschrijving", "dfdaymonthyear": "MM-DD-JJJJ", "dfdayweekmonth": "ddd, D, MMM", "dffulldate": "dddd, D MMMM YYYY h[:]mm A", @@ -54,9 +58,9 @@ "done": "Voltooid", "download": "Download", "downloading": "Downloaden", - "edit": "Wijzig", + "edit": "Bewerk", "emptysplit": "Deze pagina zal leeg verschijnen als het linker paneel leeg of aan het laden is.", - "error": "Fout", + "error": "Er is een fout opgetreden", "errorchangecompletion": "Er is een fout opgetreden tijdens het wijzigen van de voltooiingsstatus. Probeer opnieuw.", "errordeletefile": "Fout tijdens het verwijderen van het bestand. Probeer opnieuw.", "errordownloading": "Fout bij downloaden bestand", @@ -90,14 +94,15 @@ "info": "Info", "ios": "iOS", "labelsep": ": ", - "lastmodified": "Laatste wijziging", + "lastdownloaded": "Laatste download", + "lastmodified": "Laatst gewijzigd", "lastsync": "Laatste synchronisatie", "listsep": ";", - "loading": "Aan het laden", + "loading": "Laden...", "loadmore": "Meer laden", "lostconnection": "We zijn de verbinding kwijt en moeten opnieuw verbinden. Je token is nu ongeldig.", "maxsizeandattachments": "Maximale grootte voor nieuwe bestanden: {{$a.size}}, maximum aantal bijlagen: {{$a.attachments}}", - "min": "minuut", + "min": "Minimumscore", "mins": "minuten", "mod_assign": "Opdracht", "mod_assignment": "Opdracht", @@ -128,16 +133,16 @@ "moduleintro": "Beschrijving", "mygroups": "Mijn groepen", "name": "Naam", - "networkerrormsg": "Netwerk niet ingeschakeld of werkt niet.", + "networkerrormsg": "Er was een probleem met het verbinden met de site. Controleer je verbinding en probeer opnieuw.", "never": "Nooit", - "next": "VolgendeAdm", + "next": "Volgende", "no": "Nee", - "nocomments": "Geen commentaren", - "nograde": "Nog geen cijfer", + "nocomments": "Er zijn geen opmerkingen", + "nograde": "Geen cijfer.", "none": "Geen", "nopasswordchangeforced": "Je kunt niet verdergaan zonder je wachtwoord te veranderen.", "nopermissions": "Sorry, maar je hebt nu niet het recht om dat te doen ({{$a}}).", - "noresults": "Geen resultaten", + "noresults": "Geen resultaat", "notapplicable": "n/a", "notice": "Opmerking", "notsent": "Niet verstuurd", @@ -156,20 +161,20 @@ "pulltorefresh": "Slepen om te verversen", "redirectingtosite": "Je wordt doorgestuurd naar de site.", "refresh": "Vernieuw", - "required": "Verplicht", + "required": "Vereist", "requireduserdatamissing": "Er ontbreken vereiste gegevens in het profiel van deze gebruiker. Vul deze gegevens in op je Moodle site en probeer opnieuw.
    {{$a}}", "retry": "Probeer opnieuw", "save": "Bewaar", - "search": "Zoek", + "search": "Zoeken...", "searching": "Zoeken", "searchresults": "Zoekresultaten", "sec": "seconde", "secs": "seconden", "seemoredetail": "Klik hier om meer details te zien", - "send": "Stuur", + "send": "stuur", "sending": "Sturen", "serverconnection": "Fout bij het verbinden met de server", - "show": "Toon", + "show": "Laat zien", "showmore": "Toon meer...", "site": "Site", "sitemaintenance": "De site is in onderhoud en is op dit ogenblik niet beschikbaar.", @@ -179,8 +184,9 @@ "sizemb": "MB", "sizetb": "TB", "sorry": "Sorry...", + "sortby": "Sorteer volgens", "start": "Start", - "submit": "Insturen", + "submit": "Verstuur", "success": "Gelukt!", "tablet": "Tablet", "teachers": "leraren", @@ -202,7 +208,7 @@ "userdetails": "Gebruikersdetails", "usernotfullysetup": "Gebruiker niet volledig ingesteld", "users": "Gebruikers", - "view": "Bekijken", + "view": "Bekijk", "viewprofile": "Bekijk profiel", "warningofflinedatadeleted": "Offline data van {{component}} '{{name}}' is verwijderd. {{error}}", "whoops": "Oei!", diff --git a/www/core/lang/pl.json b/www/core/lang/pl.json index d01910cc16c..29222edf577 100644 --- a/www/core/lang/pl.json +++ b/www/core/lang/pl.json @@ -8,8 +8,8 @@ "choose": "Wybierz", "choosedots": "Wybierz ...", "clicktohideshow": "Kliknij, aby rozwinąć lub zwinąć", - "close": "Zamknij", - "comments": "Twój komentarz", + "close": "Zamknij okno", + "comments": "Komentarze", "commentscount": "Komentarze ({{$a}})", "completion-alt-auto-fail": "Ukończone: {{$a}} (bez pozytywnej oceny)", "completion-alt-auto-n": "Nie ukończone: {{$a}}", @@ -22,18 +22,18 @@ "continue": "Kontynuuj", "course": "Kurs", "coursedetails": "Szczegóły kursu", - "date": "Data", - "day": "dzień", - "days": "dni", + "date": "data", + "day": "Dzień/dni", + "days": "Dni", "decsep": ",", "delete": "Usuń", "deleting": "Usuwanie", - "description": "Wstęp", + "description": "Opis", "done": "Wykonane", "download": "Pobierz", "downloading": "Pobieranie ...", - "edit": "Modyfikuj", - "error": "Błąd", + "edit": "Edytuj", + "error": "Wystąpił błąd", "filename": "Nazwa pliku", "folder": "Folder", "forcepasswordchangenotice": "W celu kontynuacji musisz zmienić swoje hasło", @@ -46,12 +46,12 @@ "hours": "godz.", "info": "Informacja", "labelsep": ": ", - "lastmodified": "Ostatnia modyfikacja", + "lastmodified": "Ostatnia modyfikacja:", "listsep": ";", - "loading": "Ładowanie", + "loading": "Ładuję ...", "lostconnection": "Straciliśmy połączenie i musisz się połączyć ponowne. Twój token jest teraz nieważny", "maxsizeandattachments": "Maksymalny rozmiar dla nowych plików: {{$a.size}}, maksimum załączników: {{$a.attachments}}", - "min": "min", + "min": "Min punkty", "mins": "min.", "mod_assign": "Zadanie", "mod_chat": "Czat", @@ -66,13 +66,13 @@ "mod_survey": "Ankieta", "mod_wiki": "Wiki", "moduleintro": "Opis", - "name": "Nazwa:", + "name": "Nazwa", "networkerrormsg": "Sieć jest wyłączona lub nie działa.", "never": "Nigdy", - "next": "Dalej", + "next": "Następny", "no": "Nie", "nocomments": "Brak komentarzy", - "nograde": "Brak oceny", + "nograde": "Brak oceny.", "none": "Żaden", "nopasswordchangeforced": "Nie możesz kontynuować bez zmiany hasła, jakkolwiek nie ma dostępnej strony do tej zmiany. Proszę skontaktować się z Administratorem Moodla.", "nopermissions": "Brak odpowiednich uprawnień do wykonania ({{$a}})", @@ -80,22 +80,22 @@ "notice": "Powiadomienie", "now": "teraz", "numwords": "{{$a}} słów", - "offline": "Wysyłanie online nie jest wymagane", + "offline": "Offline", "online": "Online", "pagea": "Strona {{$a}}", "phone": "Telefon", "pictureof": "Obraz {{$a}}", "previous": "Poprzedni", - "refresh": "Odśwież", + "refresh": "Odswież", "required": "Wymagane", "save": "Zapisz", - "search": "Wyszukaj", - "searching": "Szukaj w", - "searchresults": "Wyniki wyszukiwania", + "search": "Szukaj", + "searching": "Wyszukiwanie w ...", + "searchresults": "Szukaj w rezultatach", "sec": "sek", "secs": "sek.", "seemoredetail": "Kliknij aby zobaczyć więcej szczegółów", - "send": "wyślij", + "send": "Wyślij", "sending": "Wysyłanie", "serverconnection": "Błąd podczas łączenia się z serwerem", "show": "Pokaż", @@ -104,8 +104,9 @@ "sizegb": "GB", "sizekb": "KB", "sizemb": "MB", + "sortby": "Posortuj według", "start": "Rozpocznij", - "submit": "Prześlij", + "submit": "Zatwierdź", "success": "Gotowe", "teachers": "Prowadzący", "time": "Czas", @@ -118,9 +119,9 @@ "userdeleted": "To konto użytkownika zostało usunięte", "userdetails": "Szczegóły użytkownika", "users": "Użytkownicy", - "view": "Wejście", + "view": "Przegląd", "viewprofile": "Zobacz profil", - "year": "rok", + "year": "Rok/lata", "years": "lata", "yes": "Tak" } \ No newline at end of file diff --git a/www/core/lang/pt-br.json b/www/core/lang/pt-br.json index a461e54702c..97ffa6a7ca0 100644 --- a/www/core/lang/pt-br.json +++ b/www/core/lang/pt-br.json @@ -13,16 +13,16 @@ "clearsearch": "Limpar busca", "clicktohideshow": "Clique para expandir ou contrair", "clicktoseefull": "Clique para ver o conteúdo completo.", - "close": "Fechar", - "comments": "Seus comentários", + "close": "Fechar janela", + "comments": "Comentários", "commentscount": "Comentários ({{$a}})", "commentsnotworking": "Os comentários não podem ser recuperados", - "completion-alt-auto-fail": "Concluído: {{$a}} (não alcançou a nota para passar)", - "completion-alt-auto-n": "Não concluído: {{$a}}", - "completion-alt-auto-pass": "Concluído: {{$a}} (nota para passar foi alcançada)", + "completion-alt-auto-fail": "Concluído: {{$a}} (não obteve nota para aprovação)", + "completion-alt-auto-n": "Não concluído(s): {{$a}}", + "completion-alt-auto-pass": "Concluído: {{$a}} (foi atingida a nota de aprovação)", "completion-alt-auto-y": "Concluído: {{$a}}", - "completion-alt-manual-n": "Não concluído: {{$a}}. Selecione para marcar como concluída.", - "completion-alt-manual-y": "Concluído: {{$a}}. Selecione para marcar como não concluída.", + "completion-alt-manual-n": "Não concluído(s): {{$a}}. Selecione para marcar como concluído.", + "completion-alt-manual-y": "Concluído(s): {{$a}}. Selecione para marcar como não concluído.", "confirmcanceledit": "Você tem certeza que quer sair dessa página? Todas as mudanças serão perdidas.", "confirmdeletefile": "Você tem certeza que quer excluir este arquivo?", "confirmloss": "Você tem certeza? Todas as alterações serão perdidas.", @@ -36,12 +36,12 @@ "currentdevice": "Dispositivo atual", "datastoredoffline": "Os dados foram guardados no dispositivo porque não foi possível enviar agora. Os dados serão automaticamente enviados mais tarde.", "date": "Data", - "day": "dia", - "days": "dias", + "day": "Dia(s)", + "days": "Dias", "decsep": ",", - "delete": "Cancelar", + "delete": "Excluir", "deleting": "Excluindo", - "description": "Texto do link", + "description": "Descrição", "dfdaymonthyear": "MM-DD-YYYY", "dfdayweekmonth": "ddd, D MMM", "dflastweekdate": "ddd", @@ -53,7 +53,7 @@ "download": "Download", "downloading": "Baixando", "edit": "Editar", - "error": "Erro", + "error": "Ocorreu um erro", "errorchangecompletion": "Ocorreu um erro ao alterar o status de conclusão. Por favor, tente novamente.", "errordeletefile": "Erro ao excluir o arquivo. Por favor tente novamente.", "errordownloading": "Erro ao baixar o arquivo", @@ -87,13 +87,13 @@ "info": "Informações", "ios": "iOS", "labelsep": ": ", - "lastmodified": "Última atualização", + "lastmodified": "Última modificação", "lastsync": "Última sincronização", "listsep": ";", - "loading": "Carregando", + "loading": "Carregando...", "lostconnection": "Perdemos conexão. Você precisa se reconectar. Seu token agora está inválido.", "maxsizeandattachments": "Tamanho máximo para novos arquivos: {{$a.size}}, máximo de anexos: {{$a.attachments}}", - "min": "minuto", + "min": "Pontuação mínima", "mins": "minutos", "mod_assign": "Tarefa", "mod_assignment": "Tarefa", @@ -126,14 +126,14 @@ "name": "Nome", "networkerrormsg": "Rede não habilitada ou não está funcionado", "never": "Nunca", - "next": "Próximo", + "next": "Próxima", "no": "Não", - "nocomments": "Nenhum comentário", - "nograde": "Nenhuma nota", + "nocomments": "Não existem comentários", + "nograde": "Não há nota", "none": "Nenhum", "nopasswordchangeforced": "Você não pode proceder sem mudar sua senha.", "nopermissions": "Você não tem permissão para {{$a}}", - "noresults": "Nenhum resultado", + "noresults": "Sem resultados", "notapplicable": "n/a", "notice": "Notar", "notsent": "Não enviado", @@ -152,20 +152,20 @@ "pulltorefresh": "Puxe para atualizar", "redirectingtosite": "Você será redirecionado para o site.", "refresh": "Atualizar", - "required": "Necessários", + "required": "Exigido", "requireduserdatamissing": "Este usuário não possui alguns dados de perfil exigidos. Por favor, preencha estes dados em seu Moodle e tente novamente.
    {{$a}}", "retry": "Tentar novamente", - "save": "Gravar", - "search": "Buscar", + "save": "Salvar", + "search": "Busca", "searching": "Procurando", "searchresults": "Resultados da busca", "sec": "segundo", "secs": "segundos", "seemoredetail": "Clique aqui para mais detalhes", - "send": "enviar", + "send": "Enviar", "sending": "Enviando", "serverconnection": "Erro ao conectar ao servidor", - "show": "Mostrar", + "show": "Exibir", "showmore": "Exibir mais...", "site": "Site", "sitemaintenance": "Os site está em manutenção e atualmente não está disponível", @@ -175,13 +175,14 @@ "sizemb": "Mb", "sizetb": "TB", "sorry": "Desculpe...", + "sortby": "Ordenar por", "start": "Início", "submit": "Enviar", - "success": "Sucesso!", + "success": "Sucesso", "tablet": "Tablet", "teachers": "Professores", "thereisdatatosync": "Existem {{$a}} offline para ser sincronizados.", - "time": "Hora", + "time": "Duração", "timesup": "Acabou o tempo de duração!", "today": "Hoje", "tryagain": "Tente de novo", @@ -196,15 +197,16 @@ "upgraderunning": "O site está sendo atualizado, por favor, tente novamente mais tarde.", "userdeleted": "Esta conta de usuário foi cancelada", "userdetails": "Detalhes do usuário", + "usernotfullysetup": "O usuário não está totalmente configurado", "users": "Usuários", - "view": "Ver", + "view": "Visualizar", "viewprofile": "Ver perfil", "warningofflinedatadeleted": "Dados offline de {{component}} '{{name}}' foram excluídos. {{error}}", "whoops": "Oops!", "whyisthishappening": "Por que isso está acontecendo?", "windowsphone": "Windows Phone", "wsfunctionnotavailable": "A função do webservice não está disponível.", - "year": "ano", + "year": "Ano(s)", "years": "anos", "yes": "Sim" } \ No newline at end of file diff --git a/www/core/lang/pt.json b/www/core/lang/pt.json index 8914e8b66a2..035b58a0bc3 100644 --- a/www/core/lang/pt.json +++ b/www/core/lang/pt.json @@ -13,16 +13,16 @@ "clearsearch": "Limpar pesquisa", "clicktohideshow": "Clique para expandir ou contrair", "clicktoseefull": "Clique para ver todos os conteúdos.", - "close": "Fechar", - "comments": "Os seus comentários", + "close": "Fechar janela", + "comments": "Comentários", "commentscount": "Comentários ({{$a}})", "commentsnotworking": "Não foi possível recuperar os comentários", - "completion-alt-auto-fail": "Concluído: {{$a}} (não alcançou a nota mínima para passar)", - "completion-alt-auto-n": "Não concluído: {{$a}}", - "completion-alt-auto-pass": "Concluído: {{$a}} (alcançou a nota mínima para passar)", - "completion-alt-auto-y": "Concluído: {{$a}}", - "completion-alt-manual-n": "Não concluído: {{$a}}. Selecione para marcar como concluída.", - "completion-alt-manual-y": "Concluído: {{$a}}. Selecione para marcar como não concluída.", + "completion-alt-auto-fail": "Concluída: {{$a}} (não atingiu nota de aprovação)", + "completion-alt-auto-n": "Não concluída: {{$a}}", + "completion-alt-auto-pass": "Concluída: {{$a}} (atingiu nota de aprovação)", + "completion-alt-auto-y": "Concluída: {{$a}}", + "completion-alt-manual-n": "Não concluída: {{$a}}. Selecione para assinalar como concluída", + "completion-alt-manual-y": "Concluída: {{$a}}. Selecione para dar como não concluída", "confirmcanceledit": "Tem a certeza de que pretende sair desta página? Todas as alterações serão perdidas.", "confirmdeletefile": "Tem a certeza de que pretende apagar este ficheiro?", "confirmloss": "Tem a certeza absoluta? Todas as alterações serão perdidas.", @@ -36,8 +36,8 @@ "currentdevice": "Dispositivo atual", "datastoredoffline": "Dados armazenados no dispositivo por não ter sido possível enviar. Serão automaticamente enviados mais tarde.", "date": "Data", - "day": "dia", - "days": "dias", + "day": "Dia(s)", + "days": "Dias", "decsep": ",", "delete": "Apagar", "deleting": "A apagar", @@ -55,7 +55,7 @@ "downloading": "A descarregar", "edit": "Editar", "emptysplit": "Esta página aparecerá em branco se o painel esquerdo estiver vazio ou enquanto estiver a ser carregado.", - "error": "Erro", + "error": "Ocorreu um erro", "errorchangecompletion": "Ocorreu um erro ao alterar o estado de conclusão. Por favor, tente novamente.", "errordeletefile": "Erro ao apagar o ficheiro. Por favor, tente novamente.", "errordownloading": "Erro ao descarregar ficheiro.", @@ -89,14 +89,14 @@ "info": "Informações", "ios": "iOS", "labelsep": ": ", - "lastmodified": "Última alteração", + "lastmodified": "Modificado pela última vez:", "lastsync": "Última sincronização", "listsep": ";", - "loading": "A carregar", + "loading": "A carregar...", "loadmore": "Ver mais", "lostconnection": "O seu token é inválido ou expirou, terá de se autenticar novamente no site.", "maxsizeandattachments": "Tamanho máximo para novos ficheiros: {{$a.size}}, número máximo de anexos: {{$a.attachments}}", - "min": "minuto", + "min": "Pontuação mínima", "mins": "minutos", "mod_assign": "Trabalho", "mod_assignment": "Trabalho", @@ -126,14 +126,14 @@ "mod_workshop": "Workshop", "moduleintro": "Descrição", "mygroups": "Meus grupos", - "name": "Designação", + "name": "Nome", "networkerrormsg": "A rede está desativada ou não está a funcionar corretamente.", "never": "Nunca", - "next": "Seguinte", + "next": "Continuar", "no": "Não", - "nocomments": "Sem comentários", - "nograde": "Nenhuma nota", - "none": "Nenhum", + "nocomments": "Não existem comentários", + "nograde": "Sem avaliação", + "none": "Nenhuma", "nopasswordchangeforced": "Não pode prosseguir sem alterar sua senha.", "nopermissions": "Atualmente, não tem permissões para realizar a operação {{$a}}", "noresults": "Sem resultados", @@ -155,13 +155,13 @@ "pulltorefresh": "Puxe para atualizar", "redirectingtosite": "Irá ser redirecionado para o site.", "refresh": "Atualizar", - "required": "Resposta obrigatória", + "required": "Obrigatório", "requireduserdatamissing": "Este utilizador não possui todos os dados de perfil obrigatórios. Por favor, preencha estes dados no seu Moodle e tente novamente.
    {{$a}}", "retry": "Tentar novamente", - "save": "Gravar", - "search": "Procurar", + "save": "Guardar", + "search": "Pesquisa", "searching": "A procurar", - "searchresults": "Procurar resultados", + "searchresults": "Resultados da procura", "sec": "segundo", "secs": "segundos", "seemoredetail": "Clique aqui para ver mais detalhes", @@ -178,13 +178,14 @@ "sizemb": "MB", "sizetb": "TB", "sorry": "Desculpe...", + "sortby": "Ordenar por", "start": "Iniciar", - "submit": "Enviar", - "success": "Sucesso!", + "submit": "Submeter", + "success": "Operação realizada com sucesso!", "tablet": "Tablet", "teachers": "Professores", "thereisdatatosync": "Existem {{$a}} offline que têm de ser sincronizados.", - "time": "Hora", + "time": "Tempo", "timesup": "O tempo terminou!", "today": "Hoje", "tryagain": "Tente novamente", @@ -208,7 +209,7 @@ "whyisthishappening": "Por que é que isto está a acontecer?", "windowsphone": "Windows Phone", "wsfunctionnotavailable": "A função do webservice não está disponível.", - "year": "ano", + "year": "Ano(s)", "years": "anos", "yes": "Sim" } \ No newline at end of file diff --git a/www/core/lang/ro.json b/www/core/lang/ro.json index 68b050e23b9..2d0e704da7e 100644 --- a/www/core/lang/ro.json +++ b/www/core/lang/ro.json @@ -12,28 +12,28 @@ "clearsearch": "Curățați căutările", "clicktohideshow": "Click pentru maximizare sau minimizare", "clicktoseefull": "Apăsați pentru a vedea întregul conținut", - "close": "Închide", - "comments": "Comentariile dumneavoastră", + "close": "Închide fereastra", + "comments": "Comentarii", "commentscount": "Comentarii ({{$a}})", - "completion-alt-auto-fail": "Realizat: {{$a}} (nu este suficient pentru promovare)", - "completion-alt-auto-n": "Nerealizat: {{$a}}", - "completion-alt-auto-pass": "Realizat: {{$a}} (este obținută nota pentru promovare)", - "completion-alt-auto-y": "Realizat: {{$a}}", - "completion-alt-manual-n": "Nerealizat: {{$a}}. Selectați pentru a fi marcat ca realizat.", - "completion-alt-manual-y": "Realizat: {{$a}}. Selectați pentru a fi marcat ca nerealizat.", + "completion-alt-auto-fail": "Finalizat: {{$a}} (nu a obținut notă de trecere)", + "completion-alt-auto-n": "Nu s-a finalizat: {{$a}}", + "completion-alt-auto-pass": "Finalizat: {{$a}} (s-a obținut notă de trecere)", + "completion-alt-auto-y": "Finalizat: {{$a}}", + "completion-alt-manual-n": "Necompletat: {{$a}}. Selectați pentru a-l seta ca fiind completat.", + "completion-alt-manual-y": "Completat: {{$a}}. Selectați pentru a-l seta ca fiind necompletat.", "confirmdeletefile": "Sunteți sigur că doriți să ștergeți acest fișier?", "confirmopeninbrowser": "Doriți să deschideți într-un browser?", "content": "Conţinut", - "continue": "Continuă", + "continue": "Mai departe", "course": "Curs", "coursedetails": "Detalii curs", - "date": "Dată", - "day": "zi", - "days": "zile", + "date": "Data", + "day": "Zi(Zile)", + "days": "Zile", "decsep": ",", - "delete": "Şterge", - "deleting": "Se șterge", - "description": "Text introductiv", + "delete": "Ștergeți", + "deleting": "În curs de ştergere", + "description": "Descriere", "dfdayweekmonth": "zzz, Z LLL", "dflastweekdate": "zzz", "dfmediumdate": "LLL", @@ -41,8 +41,8 @@ "done": "Terminat", "download": "Descarcă", "downloading": "Se descarcă", - "edit": "Editează", - "error": "Eroare", + "edit": "Editare", + "error": "A apărut o eroare", "errorchangecompletion": "A apărut o eroare în timpul schimbării nivelului de completare a cursului. Încercați din nou!", "errordownloading": "A apărut o eroare la descărcarea fișierului.", "errordownloadingsomefiles": "A apărut o eroare la descărcarea fișierelor modulului. Unele fișiere pot lipsi.", @@ -63,16 +63,16 @@ "humanreadablesize": "{{mărime}} {{unitate}}", "image": "Imagine", "imageviewer": "Vizualizator pentru imagini", - "info": "Info", + "info": "Informaţii", "ios": "iOS", "labelsep": ":", - "lastmodified": "Ultima modificare", + "lastmodified": "Modificat ultima dată", "lastsync": "Ultima sincronizare", "listsep": ";", - "loading": "Se încarcă", + "loading": "Încărcare ...", "lostconnection": "Tokenul pentru autentificare este invalid sau a expirat; trebuie să va reconectați!", "maxsizeandattachments": "Dimensiunea maximă pentru fișierele noi: {{$a.size}}, atașamente maxime: {{$a.attachments}}", - "min": "min", + "min": "Punctaj minim", "mins": "min", "mod_assign": "Temă", "mod_assignment": "Temă", @@ -104,19 +104,19 @@ "name": "Nume", "networkerrormsg": "Rețea de date inexistentă sau nefuncțională", "never": "Niciodată", - "next": "Următorul", + "next": "Înainte", "no": "Nu", - "nocomments": "Nu sunt comentarii", - "nograde": "Nicio notă", - "none": "nici unul", + "nocomments": "Nu există comentarii", + "nograde": "Fără notă.", + "none": "Niciunul", "nopasswordchangeforced": "Nu puteţi trece mai departe fără să vă schimbaţi parola, însă nu există nicio pagină în care să realizaţi această operaţiune. Vă rugăm contactaţi un administrator Moodle.", "nopermissions": "Ne pare rău, dar în acest moment nu aveţi permisiunea să realizaţi această operaţiune ({{$a}})", - "noresults": "Niciun rezultat", + "noresults": "Nu sunt rezultate", "notapplicable": "n/a", "notice": "Notificare", "now": "acum", "numwords": "{{$a}} cuvinte", - "offline": "Offline", + "offline": "Nu se solicită răspunsuri online", "online": "Online", "openfullimage": "Apăsați aici pentru a vizualiza imaginea la dimensiunea întreagă", "openinbrowser": "Deschideți în browser", @@ -126,32 +126,33 @@ "pictureof": "Imaginea {{$a}}", "previous": "Precedent", "pulltorefresh": "Trageți în jos pentru actualizare", - "refresh": "Reîncarcă", - "required": "Obligatoriu", + "refresh": "Actualizați", + "required": "Necesar", "requireduserdatamissing": "Acest utilizator are unele date de profil obligatorii necompletate. Completați aceste date în contul din Moodle și încercați din nou.
    {{$a}}", - "save": "Salvare", - "search": "Caută", - "searching": "Căutare", - "searchresults": "Rezultate căutare", + "save": "Salvează", + "search": "Căutați", + "searching": "Căutare în", + "searchresults": "Rezultatele căutării", "sec": "sec", "secs": "secs", "seemoredetail": "Apasă aici pentru mai multe detalii", - "send": "Trimis", + "send": "trimis", "sending": "Se trimite", "serverconnection": "Eroare la conectarea la server", - "show": "Afişare", + "show": "Afișați", "site": "Site", "sizeb": "bytes", "sizegb": "GB", "sizekb": "KB", "sizemb": "MB", "sizetb": "TB", + "sortby": "Sortează după", "start": "Start", "submit": "Trimite", - "success": "Succes!", + "success": "Succes", "tablet": "Tabletă", "teachers": "Profesori", - "time": "Ora", + "time": "Timp", "timesup": "Timpul a expirat!", "today": "Azi", "twoparagraphs": "{{p1}}

    {{p2}}", @@ -168,7 +169,7 @@ "whoops": "Ops!", "windowsphone": "Telefon cu sistem de operare Windows", "wsfunctionnotavailable": "Această funcție Web nu este disponibilă.", - "year": "an", + "year": "An (Ani)", "years": "ani", "yes": "Da" } \ No newline at end of file diff --git a/www/core/lang/ru.json b/www/core/lang/ru.json index e9f8b22367f..b66086f9a2f 100644 --- a/www/core/lang/ru.json +++ b/www/core/lang/ru.json @@ -3,7 +3,7 @@ "android": "Android", "areyousure": "Вы уверены?", "back": "Назад", - "cancel": "Отмена", + "cancel": "Отменить", "cannotconnect": "Не удается подключиться: убедитесь, что Вы ввели правильный URL-адрес и что сайт использует Moodle 2.4 или более поздней версии.", "cannotdownloadfiles": "Скачивание файла отключено для мобильных служб. Пожалуйста, свяжитесь с администратором сайта.", "category": "Категория", @@ -11,8 +11,8 @@ "choosedots": "Выберите...", "clearsearch": "Очистить поиск", "clicktohideshow": "Нажмите, чтобы раскрыть или скрыть", - "close": "Закрыть", - "comments": "Ваши комментарии", + "close": "Закрыть окно", + "comments": "Комментарии", "commentscount": "Комментарии ({{$a}})", "completion-alt-auto-fail": "Выполнено: {{$a}} (оценка ниже проходного балла)", "completion-alt-auto-n": "Не выполнено: {{$a}}", @@ -27,18 +27,18 @@ "course": "Курс", "coursedetails": "Информация о курсе", "date": "Дата", - "day": "день", - "days": "дн.", + "day": "дн.", + "days": "Дней", "decsep": ",", "defaultvalue": "Значение по умолчанию ({{$a}})", "delete": "Удалить", "deleting": "Удаление", - "description": "Вступление", + "description": "Описание", "done": "Завершено", "download": "Скачать", "downloading": "Загрузка", "edit": "Редактировать", - "error": "Ошибка", + "error": "Произошла ошибка", "errordownloading": "Ошибка загрузки файла", "filename": "Имя файла", "folder": "Папка", @@ -46,19 +46,19 @@ "fulllistofcourses": "Все курсы", "groupsseparate": "Изолированные группы", "groupsvisible": "Видимые группы", - "help": "Справка", + "help": "Помощь", "hide": "Скрыть", "hour": "ч.", "hours": "час.", "humanreadablesize": "{{size}} {{unit}}", - "info": "Информация", + "info": "информация", "labelsep": ":", - "lastmodified": "Последнее изменение", + "lastmodified": "Последние изменения:", "listsep": ";", - "loading": "Загрузка", + "loading": "Загрузка...", "lostconnection": "Ваш ключ аутентификации недействителен или просрочен. Вам придется повторно подключиться к сайту.", "maxsizeandattachments": "Максимальный размер новых файлов: {{$a.size}}, максимальное количество прикрепленных файлов: {{$a.attachments}}", - "min": "мин.", + "min": "Минимальный балл", "mins": "мин.", "mod_assign": "Задание", "mod_assignment": "Задание", @@ -87,14 +87,14 @@ "mod_wiki": "Вики", "mod_workshop": "Семинар", "moduleintro": "Описание", - "name": "Название:", + "name": "Название", "networkerrormsg": "Сеть не работает или работа в ней не разрешена.", "never": "Никогда", - "next": "Далее", + "next": "Следующий", "no": "Нет", "nocomments": "Нет комментариев", - "nograde": "Без оценки", - "none": "Пусто", + "nograde": "Нет оценки.", + "none": "Никто", "nopasswordchangeforced": "Вы не можете продолжать работу без смены пароля, однако страница для его изменения не доступна. Пожалуйста, свяжитесь с администратором сайта.", "nopermissions": "Извините, но у Вас нет прав сделать это ({{$a}})", "noresults": "Нет результатов", @@ -102,7 +102,7 @@ "notice": "Уведомление", "now": "сейчас", "numwords": "всего слов - {{$a}}", - "offline": "Ответ вне сайта", + "offline": "Вне сайта", "online": "На сайте", "openinbrowser": "Открыть в браузере", "pagea": "Страница {{$a}}", @@ -111,10 +111,10 @@ "previous": "Назад", "pulltorefresh": "Потяните, чтобы обновить", "refresh": "Обновить", - "required": "Необходимо заполнить", + "required": "Обязательный", "save": "Сохранить", - "search": "Найти", - "searching": "Искать в", + "search": "Искать", + "searching": "Поиск в...", "searchresults": "Результаты поиска", "sec": "сек.", "secs": "сек.", @@ -130,6 +130,7 @@ "sizekb": "Кбайт", "sizemb": "Мбайт", "sizetb": "Тб", + "sortby": "Сортировать по", "start": "Начало", "submit": "Отправить", "success": "Успешно", @@ -143,11 +144,12 @@ "upgraderunning": "Сайт обновляется, повторите попытку позже.", "userdeleted": "Учетная запись пользователя была удалена", "userdetails": "Подробная информация о пользователе", + "usernotfullysetup": "Пользователь не полностью настроен", "users": "Пользователи", "view": "Просмотр", "viewprofile": "Просмотр профиля", "whoops": "Ой!", - "year": "г.", + "year": "Год(ы)", "years": "г.", "yes": "Да" } \ No newline at end of file diff --git a/www/core/lang/sr-cr.json b/www/core/lang/sr-cr.json new file mode 100644 index 00000000000..eb73433f6fe --- /dev/null +++ b/www/core/lang/sr-cr.json @@ -0,0 +1,206 @@ +{ + "accounts": "Налози", + "allparticipants": "Сви учесници", + "android": "Андроид", + "areyousure": "Да ли сте сигурни?", + "back": "Назад", + "cancel": "Одустани", + "cannotconnect": "Није могуће успоставити везу. Проверите да ли сте унели исправну URL адресу и да ли ваш сајт користи Moodle 2.4 или новију верзију.", + "cannotdownloadfiles": "Преузимање датотека је онемогућено у подешавањима вашег мобилног сервиса. Обратите се администратору сајта.", + "captureaudio": "Сними аудио", + "capturedimage": "Снимљена слика", + "captureimage": "Усликај", + "capturevideo": "Сними видео", + "category": "Категорија", + "choose": "Изабери", + "choosedots": "Изабери...", + "clearsearch": "Обриши претрагу", + "clicktohideshow": "Кликните да бисте раширили или скупили", + "clicktoseefull": "Кликните да бисте видели комплетан садржај.", + "close": "Затвори", + "comments": "Коментари", + "commentscount": "Коментари ({{$a}})", + "commentsnotworking": "Коментари не могу да буду преузети", + "completion-alt-auto-fail": "Завршено: {{$a}} (није постигнута прелазна оцена)", + "completion-alt-auto-n": "Није завршено: {{$a}}", + "completion-alt-auto-pass": "Завршено: {{$a}} (постигнута прелазна оцена)", + "completion-alt-auto-y": "Завршено: {{$a}}", + "completion-alt-manual-n": "Није завршено: {{$a}}. Изаберите да бисте означили као завршено.", + "completion-alt-manual-y": "Завршено: {{$a}}. Изаберите да бисте означили као незавршено.", + "confirmcanceledit": "Да ли сте сигурни да желите да напустите ову страницу? Све промене ће бити изгубљене.", + "confirmdeletefile": "Да ли сте сигурни да желите да обришете ову датотетеку?", + "confirmloss": "Да ли сте сигурни? Све промене ће бити изгубљене.", + "confirmopeninbrowser": "Да ли желите да отворите у веб читачу?", + "content": "Садржај", + "contenteditingsynced": "Садржај који уређујете је синхронизован.", + "continue": "Настави", + "copiedtoclipboard": "Текст копиран у клипборд", + "course": "Курс", + "coursedetails": "Подаци о курсeвима", + "currentdevice": "Тренутни уређај", + "datastoredoffline": "Подаци су сачувани у мобилном уређају, зато што не могу да се пошаљу. Аутоматски ће бити послати касније.", + "date": "Датум", + "day": "дан", + "days": "дан/а", + "decsep": ",", + "delete": "Обриши", + "deleting": "Брисање", + "description": "Опис", + "dfdaymonthyear": "MM-DD-YYYY", + "dfdayweekmonth": "ddd, D MMM", + "dffulldate": "dddd, D MMMM YYYY h[:]mm A", + "dflastweekdate": "ddd", + "dfmediumdate": "LLL", + "dftimedate": "h[:]mm A", + "discard": "Одбаци", + "dismiss": "Обустави", + "done": "Урађено", + "download": "Преузми", + "downloading": "Преузимање", + "edit": "Уреди", + "emptysplit": "Ова страница ће се појавити празна уколико је леви панел празан или се учитава.", + "error": "Грешка", + "errorchangecompletion": "Дошло је до грешке приликом промене статуса завршетка. Молимо, покушајте поново.", + "errordeletefile": "Грешка приликом брисања датотеке. Молимо, покушајте поново.", + "errordownloading": "Грешка приликом преузимања датотеке.", + "errordownloadingsomefiles": "Грешка приликом преузимања датотека модула. Могуће је да неке датотеке недостају.", + "errorfileexistssamename": "Већ постоји датотека са овим називом.", + "errorinvalidform": "Образац садржи неисправне податке. Уверите се да сте попунили сва неопходна поља и да су подаци исправни.", + "errorinvalidresponse": "Примљен је неисправан одговор. Обратите се администратору вашег Moodle сајта ако се грешка понови.", + "errorloadingcontent": "Грешка при учитавању садржаја.", + "erroropenfilenoapp": "Грешка приликом отварања датотеке: није пронађена апликација која може да отвори овај тип датотеке.", + "erroropenfilenoextension": "Грешка приликом отварања датотеке: датотека нема екстензију.", + "erroropenpopup": "Ова активност покушава да отвори искачући прозор. Ова апликација то не подржава.", + "errorrenamefile": "Грешка приликом покушаја промене назива датотеке. Молимо, покушајте поново.", + "errorsync": "Дошло је до грешке приликом синхронизацији. Молимо, покушајте поново.", + "errorsyncblocked": "{{$a}} тренутно не може да се синхронизује због текућег процеса. Молимо, покушајте поново касније. Ако се проблем и даље буде постојао, покушајте поново да покренете апликацију.", + "filename": "Име датотеке", + "filenameexist": "Назив датотеке већ постоји: {{$a}}", + "folder": "Директоријум", + "forcepasswordchangenotice": "Морате променити своју лозинку да бисте наставили", + "fulllistofcourses": "Сви курсеви", + "fullnameandsitename": "{{fullname}} ({{sitename}})", + "groupsseparate": "Одвојене групе", + "groupsvisible": "Видљиве групе", + "hasdatatosync": "{{$a}} има офлајн податке које треба синхронизовати.", + "help": "Помоћ", + "hide": "Сакриј", + "hour": "h", + "hours": "сат/а/и", + "humanreadablesize": "{{size}} {{unit}}", + "image": "Слика", + "imageviewer": "Приказивач слике", + "info": "Инфо", + "ios": "iOS", + "labelsep": ":", + "lastdownloaded": "Последњи пут преузето", + "lastmodified": "Последња измена", + "lastsync": "Последња синхронизација", + "listsep": ";", + "loading": "Учитавање", + "loadmore": "Учитај још", + "lostconnection": "Ваш токен за потврду идентитета је неважећи или је истекао. Мораћете поново да успоставите везу са сајтом.", + "maxsizeandattachments": "Максимална величина за нове датотеке: {{$a.size}}, макисималан број прилога: {{$a.attachments}}", + "min": "min", + "mins": "min", + "mod_assign": "Задатак", + "mod_chat": "Причаоница", + "mod_choice": "Избор", + "mod_data": "База података", + "mod_feedback": "Упитник (Feedback)", + "mod_forum": "Форум", + "mod_lesson": "Лекција", + "mod_lti": "Екстерни алат", + "mod_quiz": "Тест", + "mod_scorm": "SCORM пакет", + "mod_survey": "Упитник (Survey)", + "mod_wiki": "Wiki", + "moduleintro": "Опис", + "mygroups": "Моје групе", + "name": "Име", + "networkerrormsg": "Било је проблема са повезивањем на сајт. Проверите везу и покушајте поново.", + "never": "Никад", + "next": "Следећи", + "no": "Не", + "nocomments": "Нема коментара", + "nograde": "Нема оцене", + "none": "Ниједан", + "nopasswordchangeforced": "Не можете наставити без промене своје лозинке.", + "nopermissions": "Жао нам је, али тренутно немате дозволу да то радите ({{$a}})", + "noresults": "Нема резултата", + "notapplicable": "n/a", + "notice": "Напомена", + "notsent": "Није послато", + "now": "сада", + "numwords": "{{$a}} реч(и)", + "offline": "Офлајн", + "online": "Онлајн", + "openfullimage": "Кликните овде да бисте приказали слику у пуној величини", + "openinbrowser": "Отвори у веб читачу", + "othergroups": "Друге групе", + "pagea": "Страница {{$a}}", + "percentagenumber": "{{$a}}%", + "phone": "Телефон", + "pictureof": "Слика {{$a}}", + "previous": "Претходни", + "pulltorefresh": "Повуците за освежавање", + "redirectingtosite": "Бићете преусмерени на сајт.", + "refresh": "Освежи", + "required": "Обавезно", + "requireduserdatamissing": "Овај корисник нема у свом профилу неке неопходне податке. Молимо вас, унесети ове податке у ваш Moodle и покушајте поново.
    {{$a}}", + "retry": "Покушај поново", + "save": "Сачувај", + "search": "Претрага", + "searching": "Претраживање", + "searchresults": "Резултати претраге", + "sec": "сек", + "secs": "s", + "seemoredetail": "Кликните овде за више детеља", + "send": "Пошаљи", + "sending": "Слање", + "serverconnection": "Грешка у повезивању са сервером", + "show": "Прикажи", + "showmore": "Прикажи још...", + "site": "Сајт", + "sitemaintenance": "Сајт је у режиму одржавања и тренутно није доступан", + "sizeb": "бајта", + "sizegb": "Gb", + "sizekb": "Kb", + "sizemb": "Mb", + "sizetb": "TB", + "sorry": "Извините...", + "sortby": "Сортирај по", + "start": "Почетак", + "submit": "Проследи", + "success": "Успешно!", + "tablet": "Таблет", + "teachers": "Предавачи", + "thereisdatatosync": "Број офлајн податак које треба синхронизовати: {{$a}}", + "time": "Време", + "timesup": "Време је истекло!", + "today": "Данас", + "tryagain": "Покушај поново", + "twoparagraphs": "{{p1}}

    {{p2}}", + "uhoh": "Ух!", + "unexpectederror": "Неочекивана грешка. Затворите и поново отворите апликацију како бисте покушали поново.", + "unicodenotsupported": "Неки емотикони нису подржани на овом сајту. Такви карактери ће бити уклоњени приликом слања поруке.", + "unicodenotsupportedcleanerror": "Приликом чишћења Unicode карактера пронађен је празан текст.", + "unknown": "Непознато", + "unlimited": "Неограничено", + "unzipping": "Распакивање", + "upgraderunning": "Сајт се ажурира, молимо покушајте касније", + "userdeleted": "Овај кориснички налог је обрисан", + "userdetails": "Детаљи о кориснику", + "usernotfullysetup": "Корисник није у потпуности подешен", + "users": "Корисници", + "view": "Приказ", + "viewprofile": "Прегледај профил", + "warningofflinedatadeleted": "Офлајн подаци компоненте {{component}} '{{name}}' су обрисани. {{error}}", + "whoops": "Упс!", + "whyisthishappening": "Зашто се ово дешава?", + "windowsphone": "Windows Phone", + "wsfunctionnotavailable": "Функција Webservice није доступна.", + "year": "година", + "years": "година", + "yes": "Да" +} \ No newline at end of file diff --git a/www/core/lang/sr-lt.json b/www/core/lang/sr-lt.json new file mode 100644 index 00000000000..a35a6e51d90 --- /dev/null +++ b/www/core/lang/sr-lt.json @@ -0,0 +1,206 @@ +{ + "accounts": "Nalozi", + "allparticipants": "Svi učesnici", + "android": "Android", + "areyousure": "Da li ste sigurni?", + "back": "Nazad", + "cancel": "Odustani", + "cannotconnect": "Nije moguće uspostaviti vezu. Proverite da li ste uneli ispravnu URL adresu i da li vaš sajt koristi Moodle 2.4 ili noviju verziju.", + "cannotdownloadfiles": "Preuzimanje datoteka je onemogućeno u podešavanjima vašeg mobilnog servisa. Obratite se administratoru sajta.", + "captureaudio": "Snimi audio", + "capturedimage": "Snimljena slika", + "captureimage": "Uslikaj", + "capturevideo": "Snimi video", + "category": "Kategorija", + "choose": "Izaberi", + "choosedots": "Izaberi...", + "clearsearch": "Obriši pretragu", + "clicktohideshow": "Kliknite da biste raširili ili skupili", + "clicktoseefull": "Kliknite da biste videli kompletan sadržaj.", + "close": "Zatvori", + "comments": "Komentari", + "commentscount": "Komentari ({{$a}})", + "commentsnotworking": "Komentari ne mogu da budu preuzeti", + "completion-alt-auto-fail": "Završeno: {{$a}} (nije postignuta prelazna ocena)", + "completion-alt-auto-n": "Nije završeno: {{$a}}", + "completion-alt-auto-pass": "Završeno: {{$a}} (postignuta prelazna ocena)", + "completion-alt-auto-y": "Završeno: {{$a}}", + "completion-alt-manual-n": "Nije završeno: {{$a}}. Izaberite da biste označili kao završeno.", + "completion-alt-manual-y": "Završeno: {{$a}}. Izaberite da biste označili kao nezavršeno.", + "confirmcanceledit": "Da li ste sigurni da želite da napustite ovu stranicu? Sve promene će biti izgubljene.", + "confirmdeletefile": "Da li ste sigurni da želite da obrišete ovu datoteteku?", + "confirmloss": "Da li ste sigurni? Sve promene će biti izgubljene.", + "confirmopeninbrowser": "Da li želite da otvorite u veb čitaču?", + "content": "Sadržaj", + "contenteditingsynced": "Sadržaj koji uređujete je sinhronizovan.", + "continue": "Nastavi", + "copiedtoclipboard": "Tekst kopiran u klipbord", + "course": "Kurs", + "coursedetails": "Podaci o kursevima", + "currentdevice": "Trenutni uređaj", + "datastoredoffline": "Podaci su sačuvani u mobilnom uređaju, zato što ne mogu da se pošalju. Automatski će biti poslati kasnije.", + "date": "Datum", + "day": "dan", + "days": "dan/a", + "decsep": ",", + "delete": "Obriši", + "deleting": "Brisanje", + "description": "Opis", + "dfdaymonthyear": "MM-DD-YYYY", + "dfdayweekmonth": "ddd, D MMM", + "dffulldate": "dddd, D MMMM YYYY h[:]mm A", + "dflastweekdate": "ddd", + "dfmediumdate": "LLL", + "dftimedate": "h[:]mm A", + "discard": "Odbaci", + "dismiss": "Obustavi", + "done": "Urađeno", + "download": "Preuzmi", + "downloading": "Preuzimanje", + "edit": "Uredi", + "emptysplit": "Ova stranica će se pojaviti prazna ukoliko je levi panel prazan ili se učitava.", + "error": "Greška", + "errorchangecompletion": "Došlo je do greške prilikom promene statusa završetka. Molimo, pokušajte ponovo.", + "errordeletefile": "Greška prilikom brisanja datoteke. Molimo, pokušajte ponovo.", + "errordownloading": "Greška prilikom preuzimanja datoteke.", + "errordownloadingsomefiles": "Greška prilikom preuzimanja datoteka modula. Moguće je da neke datoteke nedostaju.", + "errorfileexistssamename": "Već postoji datoteka sa ovim nazivom.", + "errorinvalidform": "Obrazac sadrži neispravne podatke. Uverite se da ste popunili sva neophodna polja i da su podaci ispravni.", + "errorinvalidresponse": "Primljen je neispravan odgovor. Obratite se administratoru vašeg Moodle sajta ako se greška ponovi.", + "errorloadingcontent": "Greška pri učitavanju sadržaja.", + "erroropenfilenoapp": "Greška prilikom otvaranja datoteke: nije pronađena aplikacija koja može da otvori ovaj tip datoteke.", + "erroropenfilenoextension": "Greška prilikom otvaranja datoteke: datoteka nema ekstenziju.", + "erroropenpopup": "Ova aktivnost pokušava da otvori iskačući prozor. Ova aplikacija to ne podržava.", + "errorrenamefile": "Greška prilikom pokušaja promene naziva datoteke. Molimo, pokušajte ponovo.", + "errorsync": "Došlo je do greške prilikom sinhronizaciji. Molimo, pokušajte ponovo.", + "errorsyncblocked": "{{$a}} trenutno ne može da se sinhronizuje zbog tekućeg procesa. Molimo, pokušajte ponovo kasnije. Ako se problem i dalje bude postojao, pokušajte ponovo da pokrenete aplikaciju.", + "filename": "Ime datoteke", + "filenameexist": "Naziv datoteke već postoji: {{$a}}", + "folder": "Direktorijum", + "forcepasswordchangenotice": "Morate promeniti svoju lozinku da biste nastavili", + "fulllistofcourses": "Svi kursevi", + "fullnameandsitename": "{{fullname}} ({{sitename}})", + "groupsseparate": "Odvojene grupe", + "groupsvisible": "Vidljive grupe", + "hasdatatosync": "{{$a}} ima oflajn podatke koje treba sinhronizovati.", + "help": "Pomoć", + "hide": "Sakrij", + "hour": "h", + "hours": "sat/a/i", + "humanreadablesize": "{{size}} {{unit}}", + "image": "Slika", + "imageviewer": "Prikazivač slike", + "info": "Info", + "ios": "iOS", + "labelsep": ":", + "lastdownloaded": "Poslednji put preuzeto", + "lastmodified": "Poslednja izmena", + "lastsync": "Poslednja sinhronizacija", + "listsep": ";", + "loading": "Učitavanje", + "loadmore": "Učitaj još", + "lostconnection": "Vaš token za potvrdu identiteta je nevažeći ili je istekao. Moraćete ponovo da uspostavite vezu sa sajtom.", + "maxsizeandattachments": "Maksimalna veličina za nove datoteke: {{$a.size}}, makisimalan broj priloga: {{$a.attachments}}", + "min": "min", + "mins": "min", + "mod_assign": "Zadatak", + "mod_chat": "Pričaonica", + "mod_choice": "Izbor", + "mod_data": "Baza podataka", + "mod_feedback": "Upitnik (Feedback)", + "mod_forum": "Forum", + "mod_lesson": "Lekcija", + "mod_lti": "Eksterni alat", + "mod_quiz": "Test", + "mod_scorm": "SCORM paket", + "mod_survey": "Upitnik (Survey)", + "mod_wiki": "Wiki", + "moduleintro": "Opis", + "mygroups": "Moje grupe", + "name": "Ime", + "networkerrormsg": "Bilo je problema sa povezivanjem na sajt. Proverite vezu i pokušajte ponovo.", + "never": "Nikad", + "next": "Sledeći", + "no": "Ne", + "nocomments": "Nema komentara", + "nograde": "Nema ocene", + "none": "Nijedan", + "nopasswordchangeforced": "Ne možete nastaviti bez promene svoje lozinke.", + "nopermissions": "Žao nam je, ali trenutno nemate dozvolu da to radite ({{$a}})", + "noresults": "Nema rezultata", + "notapplicable": "n/a", + "notice": "Napomena", + "notsent": "Nije poslato", + "now": "sada", + "numwords": "{{$a}} reč(i)", + "offline": "Oflajn", + "online": "Onlajn", + "openfullimage": "Kliknite ovde da biste prikazali sliku u punoj veličini", + "openinbrowser": "Otvori u veb čitaču", + "othergroups": "Druge grupe", + "pagea": "Stranica {{$a}}", + "percentagenumber": "{{$a}}%", + "phone": "Telefon", + "pictureof": "Slika {{$a}}", + "previous": "Prethodni", + "pulltorefresh": "Povucite za osvežavanje", + "redirectingtosite": "Bićete preusmereni na sajt.", + "refresh": "Osveži", + "required": "Obavezno", + "requireduserdatamissing": "Ovaj korisnik nema u svom profilu neke neophodne podatke. Molimo vas, uneseti ove podatke u vaš Moodle i pokušajte ponovo.
    {{$a}}", + "retry": "Pokušaj ponovo", + "save": "Sačuvaj", + "search": "Pretraga", + "searching": "Pretraživanje", + "searchresults": "Rezultati pretrage", + "sec": "sek", + "secs": "s", + "seemoredetail": "Kliknite ovde za više detelja", + "send": "Pošalji", + "sending": "Slanje", + "serverconnection": "Greška u povezivanju sa serverom", + "show": "Prikaži", + "showmore": "Prikaži još...", + "site": "Sajt", + "sitemaintenance": "Sajt je u režimu održavanja i trenutno nije dostupan", + "sizeb": "bajta", + "sizegb": "Gb", + "sizekb": "Kb", + "sizemb": "Mb", + "sizetb": "TB", + "sorry": "Izvinite...", + "sortby": "Sortiraj po", + "start": "Početak", + "submit": "Prosledi", + "success": "Uspešno!", + "tablet": "Tablet", + "teachers": "Predavači", + "thereisdatatosync": "Broj oflajn podatak koje treba sinhronizovati: {{$a}}", + "time": "Vreme", + "timesup": "Vreme je isteklo!", + "today": "Danas", + "tryagain": "Pokušaj ponovo", + "twoparagraphs": "{{p1}}

    {{p2}}", + "uhoh": "Uh!", + "unexpectederror": "Neočekivana greška. Zatvorite i ponovo otvorite aplikaciju kako biste pokušali ponovo.", + "unicodenotsupported": "Neki emotikoni nisu podržani na ovom sajtu. Takvi karakteri će biti uklonjeni prilikom slanja poruke.", + "unicodenotsupportedcleanerror": "Prilikom čišćenja Unicode karaktera pronađen je prazan tekst.", + "unknown": "Nepoznato", + "unlimited": "Neograničeno", + "unzipping": "Raspakivanje", + "upgraderunning": "Sajt se ažurira, molimo pokušajte kasnije", + "userdeleted": "Ovaj korisnički nalog je obrisan", + "userdetails": "Detalji o korisniku", + "usernotfullysetup": "Korisnik nije u potpunosti podešen", + "users": "Korisnici", + "view": "Prikaz", + "viewprofile": "Pregledaj profil", + "warningofflinedatadeleted": "Oflajn podaci komponente {{component}} '{{name}}' su obrisani. {{error}}", + "whoops": "Ups!", + "whyisthishappening": "Zašto se ovo dešava?", + "windowsphone": "Windows Phone", + "wsfunctionnotavailable": "Funkcija Webservice nije dostupna.", + "year": "godina", + "years": "godina", + "yes": "Da" +} \ No newline at end of file diff --git a/www/core/lang/sv.json b/www/core/lang/sv.json index cfb7c45efd3..7224d074468 100644 --- a/www/core/lang/sv.json +++ b/www/core/lang/sv.json @@ -12,8 +12,8 @@ "clearsearch": "Rensa sökning", "clicktohideshow": "Klicka för att expandera eller fälla ihop", "clicktoseefull": "Klicka för att se hela innehållet", - "close": "Stäng", - "comments": "Dina kommentarer", + "close": "Stäng fönster", + "comments": "Kommentarer", "commentscount": "Kommentarer ({{$a}})", "completion-alt-auto-fail": "Avslutad: {{$a}} (uppnådde inte gräns för godkänd)", "completion-alt-auto-n": "Inte avslutad: {{$a}}", @@ -28,12 +28,12 @@ "course": "Kurs", "coursedetails": "Kursinformation", "date": "Datum", - "day": "dag", - "days": "dagar", + "day": "Dag(ar)", + "days": "Dagar", "decsep": ",", "delete": "Ta bort", "deleting": "ta bort", - "description": "Introduktion", + "description": "Beskrivning", "dfdayweekmonth": "ddd, D MMM", "dflastweekdate": "ddd", "dfmediumdate": "", @@ -42,7 +42,7 @@ "download": "Ladda ner", "downloading": "Laddar ner", "edit": "Redigera", - "error": "Fel", + "error": "Det uppstod ett fel", "errorchangecompletion": "Ett fel uppstod när du ändrade status för fullföljande. Var god försök igen.", "errordownloading": "Fel vid nedladdning av fil", "errordownloadingsomefiles": "Fel vid hämtning av modulens filer. Vissa filer kanske saknas .", @@ -52,7 +52,7 @@ "erroropenpopup": "Aktiviteten försöker öppna en popup . Detta stöds inte i den här appen.", "filename": "Filnamn", "folder": "Katalog", - "forcepasswordchangenotice": "Du måste använda Ditt lösenord för att kunna fortsätta.", + "forcepasswordchangenotice": "Du måste använda ditt lösenord för att kunna fortsätta.", "fulllistofcourses": "Alla kurser", "groupsseparate": "Olika grupper", "groupsvisible": "Synliga grupper", @@ -69,10 +69,10 @@ "lastmodified": "Senast modifierad", "lastsync": "Senaste synkronisering", "listsep": ";", - "loading": "Laddar...", + "loading": "Laddar....", "lostconnection": "Vi förlorade anslutningen. Du måste ansluta igen. Din token är nu ogiltigt.", "maxsizeandattachments": "Maximal storlek för nya filer: {{$a.size}}, max bilagor: {{$a.attachments}}", - "min": "minut", + "min": "Min resultat", "mins": "minuter", "mod_assign": "Uppgift", "mod_assignment": "Uppgift", @@ -105,12 +105,12 @@ "name": "Namn", "networkerrormsg": "Nätverket är inte aktiverat eller fungerar inte", "never": "Aldrig", - "next": "Nästa", - "no": "Nej", - "nocomments": "Inga kommentarer", - "nograde": "Inget betyg", + "next": "Fortsätt", + "no": "Ingen", + "nocomments": "Det finns inga kommentarer", + "nograde": "Inget betyg.", "none": "Ingen", - "nopasswordchangeforced": "Du kan inte gå vidare utan att ändra Ditt lösenord, men det finns inte någon sida tillgänglig för att ändra det. Var snäll och kontakta Din administratör för Moodle.", + "nopasswordchangeforced": "Du kan inte gå vidare utan att ändra ditt lösenord, men det finns inte någon sida tillgänglig för att ändra det. Var snäll och kontakta din administratör för Moodle.", "nopermissions": "Du har tyvärr f.n. inte tillstånd att göra detta ({{$a}})", "noresults": "Inga resultat", "notapplicable": "n/a", @@ -128,17 +128,17 @@ "pictureof": "Bild av {{$a}}", "previous": "Tidigare", "pulltorefresh": "Dra för att uppdatera", - "refresh": "Uppdatera", + "refresh": "Återställ", "required": "Obligatorisk", "requireduserdatamissing": "Den här användaren saknar vissa nödvändiga profildata. Vänligen fyll i uppgifterna i din Moodle och försök igen.
    {{$a}}", "save": "Spara", - "search": "Sök", + "search": "Sök...", "searching": "Söker", "searchresults": "Sökresultat", "sec": "Sekund", "secs": "Sekunder", "seemoredetail": "Klicka här för att se fler detaljer", - "send": "skicka", + "send": "Skicka", "sending": "Skickar", "serverconnection": "Fel vid anslutning till servern", "show": "Visa", @@ -148,8 +148,9 @@ "sizekb": "Kb", "sizemb": "Mb", "sizetb": "Tb", + "sortby": "Sortera enligt", "start": "Starta", - "submit": "Skicka in", + "submit": "Skicka", "success": "Succé!", "tablet": "Tablet", "teachers": "Distanslärare/
    handledare/
    coacher", @@ -170,7 +171,7 @@ "whoops": "Hoppsan!", "windowsphone": "Windows Phone", "wsfunctionnotavailable": "Webbtjänstfunktion är inte tillgänglig.", - "year": "år", + "year": "År", "years": "år", "yes": "Ja" } \ No newline at end of file diff --git a/www/core/lang/tr.json b/www/core/lang/tr.json index 295d277a503..d9ffd4eeb3e 100644 --- a/www/core/lang/tr.json +++ b/www/core/lang/tr.json @@ -11,8 +11,8 @@ "choosedots": "Seçiniz...", "clearsearch": "Aramayı temizle", "clicktohideshow": "Genişlet/Daralt", - "close": "Kapat", - "comments": "Yorumlarınız", + "close": "Pencereyi kapat", + "comments": "Yorumlar", "commentscount": "Yorumlar ({{$a}})", "completion-alt-auto-fail": "Tamamlandı (geçer not almayı başaramadı)", "completion-alt-auto-n": "Tamamlanmadı", @@ -23,21 +23,21 @@ "confirmdeletefile": "Bu dosyayı silmek istediğinize emin misiniz?", "confirmopeninbrowser": "Tarayıcıda açmak istediğine emin misin?", "content": "İçerik", - "continue": "Devam", + "continue": "Devam et", "course": "Ders", "coursedetails": "Ders ayrıntıları", "date": "Tarih", - "day": "gün", - "days": "gün", + "day": "Gün", + "days": "Gün", "decsep": ",", "delete": "Sil", "deleting": "Siliniyor", - "description": "Tanıtım metni", + "description": "Açıklama", "done": "Tamamlandı", "download": "İndir", "downloading": "İndiriliyor...", - "edit": "Düzelt", - "error": "Hata", + "edit": "Düzenle ", + "error": "Hata oluştu", "errordownloading": "Dosya indirmede hata", "filename": "Dosya adı", "folder": "Klasör", @@ -53,13 +53,13 @@ "info": "Bilgi", "ios": "İOS", "labelsep": ":", - "lastmodified": "En son değiştirme", + "lastmodified": "Son değiştirme", "lastsync": "Son senkronizasyon", "listsep": ";", - "loading": "Yükleniyor...", + "loading": "Yükleniyor", "lostconnection": "Bağlantınızı kaybettik, yeniden bağlanmanız gerekiyor. Verileriniz artık geçerli değil.", "maxsizeandattachments": "Yeni dosyalar için en büyük boyut: {{$a.size}}, en fazla ek: {{$a.attachments}}", - "min": "dk", + "min": "Min puan", "mins": "dk", "mod_assign": "Ödev", "mod_book": "Kitap", @@ -88,14 +88,14 @@ "mod_workshop": "Çalıştay", "moduleintro": "Açıklama", "mygroups": "Gruplarım", - "name": "Ad", + "name": "Adı", "networkerrormsg": "Ağ etkin değil ya da çalışmıyor.", - "never": "Hiçbir zaman", - "next": "Sonraki", + "never": "Asla", + "next": "Devam et", "no": "Hayır", - "nocomments": "Yorum yok", - "nograde": "Not yok", - "none": "Yok", + "nocomments": "Hiç yorum yok", + "nograde": "Not yok.", + "none": "Hiçbiri", "nopasswordchangeforced": "Şifrenizi değiştirmeden ilerleyemezsiniz, ancak şifrenizi değiştirmek için bir sayfa yok. Lütfen Moodle Yöneticinizle iletişime geçin.", "nopermissions": "Üzgünüz, şu anda bunu yapmaya yetkiniz yok: {{$a}}", "noresults": "Sonuç yok", @@ -113,7 +113,7 @@ "refresh": "Yenile", "required": "Gerekli", "save": "Kaydet", - "search": "Ara", + "search": "Arama...", "searching": "Aranıyor", "searchresults": "Arama sonuçları", "sec": "sn", @@ -130,12 +130,13 @@ "sizekb": "KB", "sizemb": "MB", "sorry": "Üzgünüz...", + "sortby": "Sıralama ölçütü", "start": "Başla", "submit": "Gönder", "success": "Başarı", "tablet": "Tablet", "teachers": "Eğitimciler", - "time": "Zaman", + "time": "Süre", "timesup": "Süre doldu!", "today": "Bugün", "unexpectederror": "Beklenmeyen hata. Lütfen uygulamanızı yeniden açın ve tekrar deneyin", @@ -146,9 +147,9 @@ "userdetails": "Kullanıcı ayrıntıları", "usernotfullysetup": "Kullanıcı tam kurulum yapmadı", "users": "Kullanıcılar", - "view": "Görüntüle", + "view": "Görünüm", "viewprofile": "Profili görüntüle", - "year": "yıl", + "year": "Yıl", "years": "yıl", "yes": "Evet" } \ No newline at end of file diff --git a/www/core/lang/uk.json b/www/core/lang/uk.json index 2586c68adc3..cfce433c7de 100644 --- a/www/core/lang/uk.json +++ b/www/core/lang/uk.json @@ -1,29 +1,29 @@ { - "accounts": "Акаунти", + "accounts": "Аккаунти", "allparticipants": "Усі учасники", "android": "Android", "areyousure": "Ви впевнені?", "back": "Назад", "cancel": "Скасувати", - "cannotconnect": "Неможливо з'єднатися: Переконайтеся, що ви ввели правильно URL і що сайт використовує Moodle 2.4 або більш пізньої версії.", - "cannotdownloadfiles": "Завантаження файлів відключена у вашій мобільній службі. Будь ласка, зверніться до адміністратора сайту.", + "cannotconnect": "Неможливо з'єднатися: Переконайтеся, що ви ввели правильний URL і що сайт використовує Moodle 2.4 або більш пізню версію.", + "cannotdownloadfiles": "Завантаження файлів відключено у вашій мобільній службі. Будь ласка, зверніться до адміністратора сайту.", "category": "Категорія", "choose": "Вибрати", "choosedots": "Вибрати...", "clearsearch": "Очистити пошук", "clicktohideshow": "Натисніть, щоб розгорнути або згорнути", "clicktoseefull": "Натисніть, щоб побачити весь вміст.", - "close": "Закрити", - "comments": "Ваші коментарі", + "close": "Закрити вікно", + "comments": "Коментарі", "commentscount": "Коментарі ({{$a}})", "commentsnotworking": "Коментар не може бути відновлений", - "completion-alt-auto-fail": "Виконано: {{$a}} (не досягли до рівня зараховання)", + "completion-alt-auto-fail": "Виконано: {{$a}} (не досягли до рівня зарахування)", "completion-alt-auto-n": "Не завершено: {{$a}}", - "completion-alt-auto-pass": "Виконано: {{$a}} (досягагли до рівня зараховано)", + "completion-alt-auto-pass": "Виконано: {{$a}} (досягли до рівня зараховано)", "completion-alt-auto-y": "Завершено: {{$a}}", "completion-alt-manual-n": "Не завершено {{$a}}. Виберіть для відмічення як завершене.", - "completion-alt-manual-y": "Завершено {{$a}}. Виберіть для відмічення як не завершене.", - "confirmcanceledit": "Ви впевнені, що хочете залишити цю сторінку? Всі зміни будуть втрачені.", + "completion-alt-manual-y": "Завершено {{$a}}. Виберіть для відмічення як незавершене.", + "confirmcanceledit": "Ви впевнені що хочете залишити цю сторінку? Всі зміни будуть втрачені.", "confirmdeletefile": "Ви впевнені, що хочете видалити цей файл?", "confirmloss": "Ви впевнені? Всі зміни будуть втрачені.", "confirmopeninbrowser": "Ви хочете відкрити в браузері?", @@ -36,12 +36,12 @@ "currentdevice": "Поточний пристрій", "datastoredoffline": "Дані зберігаються в пристрої, оскільки не можуть бути надіслані. Вони будуть автоматично відправлені пізніше.", "date": "Дата", - "day": "день", - "days": "днів", + "day": "День(ів)", + "days": "Днів", "decsep": ",", - "delete": "Видалити", + "delete": "Вилучити", "deleting": "Видалення", - "description": "Текст вступу", + "description": "Опис", "dfdaymonthyear": "MM-DD-YYYY", "dfdayweekmonth": "ddd, D MMM", "dffulldate": "dddd, D MMMM YYYY h[:]mm A", @@ -55,8 +55,8 @@ "downloading": "Завантаження", "edit": "Редагувати", "emptysplit": "Ця сторінка буде виглядати порожньою, якщо ліва панель порожня або завантажується.", - "error": "Помилка", - "errorchangecompletion": "При зміні стану завершення сталася помилка. Будь ласка спробуйте ще раз.", + "error": "Сталася помилка", + "errorchangecompletion": "При зміні статусу завершення сталася помилка. Будь ласка спробуйте ще раз.", "errordeletefile": "Помилка видалення файлу. Будь ласка спробуйте ще раз.", "errordownloading": "Помилка завантаження файлу.", "errordownloadingsomefiles": "Помилка завантаження модуля файлів. Деякі файли можуть бути відсутні.", @@ -69,7 +69,7 @@ "erroropenpopup": "Ця діяльність намагається відкрити спливаюче вікно. Це не підтримується в цьому додатку.", "errorrenamefile": "Помилка перейменування файлу. Будь ласка спробуйте ще раз.", "errorsync": "Під час синхронізації сталася помилка. Будь ласка спробуйте ще раз.", - "errorsyncblocked": "Це {{$a}} не може бути синхронізований прямо зараз через триваючого процесу. Будь-ласка спробуйте пізніше. Якщо питання залишається невирішеним, спробуйте перезапустити програму.", + "errorsyncblocked": "{{$a}} не може бути синхронізований прямо зараз через навантаження на сервер. Будь-ласка спробуйте пізніше. Якщо питання залишається невирішеним, спробуйте перезапустити програму.", "filename": "Ім’я файлу", "filenameexist": "Файл вже існує: {{$a}}", "folder": "Тека", @@ -89,14 +89,14 @@ "info": "Інфо", "ios": "iOS", "labelsep": ":", - "lastmodified": "Остання зміна", + "lastmodified": "Востаннє змінено", "lastsync": "Остання синхронізація", "listsep": ";", "loading": "Завантаження...", - "loadmore": "Завнтажити більше", + "loadmore": "Завантажити більше", "lostconnection": "Ваш маркер аутентифікації недійсний або закінчився, вам доведеться підключитися до сайту.", "maxsizeandattachments": "Макс. обсяг для нових файлів: {{$a.size}}, макс. кількість прикріплених файлів: {{$a.attachments}}", - "min": "хв", + "min": "Мін.оцінка", "mins": "хв", "mod_assign": "Завдання", "mod_chat": "Чат", @@ -112,17 +112,17 @@ "mod_wiki": "Вікі", "moduleintro": "Опис", "mygroups": "Мої групи", - "name": "Ім'я", + "name": "Назва", "networkerrormsg": "Мережа не включена або не працює.", "never": "Ніколи", - "next": "Далі", + "next": "Вперед", "no": "Ні", - "nocomments": "Немає коментарів", - "nograde": "Без оцінки", - "none": "Не вибрано", + "nocomments": "Коментарів немає", + "nograde": "Немає оцінки.", + "none": "Немає", "nopasswordchangeforced": "Ви не можете продовжити без зміни пароля.", "nopermissions": "Вибачте, але ваші поточні права не дозволяють вам цього робити ({{$a}})", - "noresults": "Без результатів", + "noresults": "Результат відсутній", "notapplicable": "n/a", "notice": "Помітити", "notsent": "Не відправлено", @@ -141,17 +141,17 @@ "pulltorefresh": "Потягніть щоб оновити", "redirectingtosite": "Ви будете перенаправлені на сайт.", "refresh": "Оновити", - "required": "Необхідні", + "required": "Необхідне", "requireduserdatamissing": "Цей користувач не має деяких необхідних даних в профілі. Заповніть, будь ласка, ці дані у вашому профілі Moodle і спробуйте ще раз.
    {{$a}}", "retry": "Повторити", "save": "Зберегти", - "search": "Знайти", + "search": "Пошук", "searching": "Пошук", "searchresults": "Результати пошуку", "sec": "сек", "secs": "сек", "seemoredetail": "Деталі...", - "send": "Відіслати", + "send": "надіслати", "sending": "Відправка", "serverconnection": "Помилка з’єднання з сервером", "show": "Показати", @@ -164,10 +164,11 @@ "sizemb": "Мб", "sizetb": "TB", "sorry": "Вибачте...", + "sortby": "Сортувати за", "start": "Початок", - "submit": "Прийняти", + "submit": "Надіслати", "success": "Успіх!", - "tablet": "пЛАНШЕТ", + "tablet": "Планшет", "teachers": "Викладачі", "thereisdatatosync": "Офлайн {{$a}} повинні бути синхронізовані.", "time": "Час", @@ -177,7 +178,7 @@ "twoparagraphs": "{{p1}}

    {{p2}}", "uhoh": "Опана...", "unexpectederror": "Неочікувана помилка. Будь ласка, закрийте і знову відкрийте додаток, щоб спробувати ще раз", - "unicodenotsupported": "Деякі Emojis не підтримуються на цьому сайті. Такі символи будуть видалені, коли повідомлення було відправлено.", + "unicodenotsupported": "Деякі Emoji не підтримуються на цьому сайті. Такі символи будуть видалені, коли повідомлення буде відправлено.", "unicodenotsupportedcleanerror": "Порожній текст був знайдений при чищенні Unicode символів.", "unknown": "Невідомо", "unlimited": "Не обмежено", @@ -188,12 +189,12 @@ "users": "Користувачі", "view": "Перегляд", "viewprofile": "Переглянути профіль", - "warningofflinedatadeleted": "Offline дані {{component}} '{{name}}' були видалений. {{error}}", + "warningofflinedatadeleted": "Offline дані {{component}} '{{name}}' були видалені. {{error}}", "whoops": "Упс!", "whyisthishappening": "Чому це відбувається?", "windowsphone": "Windows Phone", "wsfunctionnotavailable": "Функція веб-сервіс не доступна.", - "year": "рік", + "year": "Роки", "years": "роки", "yes": "Так" } \ No newline at end of file diff --git a/www/core/lang/zh-cn.json b/www/core/lang/zh-cn.json index 61789cfd747..8009b06ed9f 100644 --- a/www/core/lang/zh-cn.json +++ b/www/core/lang/zh-cn.json @@ -4,12 +4,12 @@ "back": "返回", "cancel": "取消", "cannotconnect": "无法连接:请确认您已经正确输入网址,并且您的网站使用了Moodle 2.4或更高版本。", - "category": "课程分类", + "category": "类别", "choose": "选择", "choosedots": "选择...", "clicktohideshow": "点击来展开或折叠", - "close": "关闭", - "comments": "您的评价", + "close": "关闭窗口", + "comments": "评论", "commentscount": "评论({{$a}})", "completion-alt-auto-fail": "已完成:{{$a}}(未及格)", "completion-alt-auto-n": "未完成:{{$a}}", @@ -24,15 +24,15 @@ "coursedetails": "课程详情", "date": "日期", "day": "天", - "days": "天", + "days": "天数", "decsep": ".", "delete": "删除", "deleting": "删除中", - "description": "简要描述", + "description": "描述", "done": "完成", "download": "下载", "edit": "编辑", - "error": "错误", + "error": "发生了错误", "errordownloading": "下载文件时出错", "filename": "文件名", "folder": "文件夹", @@ -46,12 +46,12 @@ "hours": "小时", "info": "信息", "labelsep": ":", - "lastmodified": "最后修改", + "lastmodified": "最近修改", "listsep": ",", - "loading": "载入中", + "loading": "加载中...", "lostconnection": "我们失去了连接,因此您需要重新连接。您现在的令牌是无效的。", "maxsizeandattachments": "新文件的最大尺寸: {{$a.size}} ,最多附件:{{$a.attachments}}", - "min": "分钟", + "min": "最低分值", "mins": "分钟", "mod_assign": "作业", "mod_chat": "聊天", @@ -66,31 +66,31 @@ "mod_survey": "问卷调查", "mod_wiki": "Wiki协作", "moduleintro": "描述", - "name": "名字", + "name": "名称", "networkerrormsg": "网络未启用或不工作。", - "never": "从未", - "next": "向后", + "never": "从不", + "next": "下一步", "no": "否", - "nocomments": "无评论", - "nograde": "没有分数", - "none": "无", + "nocomments": "没有评论", + "nograde": "没有成绩。", + "none": "没有", "nopasswordchangeforced": "在您更改密码前不能继续操作,但系统找不到用来更改密码的页面,请与管理员联系。", "nopermissions": "很抱歉,您没有相应权限({{$a}})", "noresults": "没有结果", "notice": "注意", "now": "现在", "numwords": "{{$a}}单词", - "offline": "不需要在线提交", + "offline": "离线", "online": "在线", "pagea": "页码 {{$a}}", "phone": "电话", "pictureof": "{{$a}}的头像", "previous": "向前", "refresh": "刷新", - "required": "必需的", + "required": "必须回答", "save": "保存", "search": "搜索", - "searching": "搜索", + "searching": "搜索中……", "searchresults": "搜索结果", "sec": "秒", "secs": "秒", @@ -104,11 +104,12 @@ "sizegb": "GB", "sizekb": "KB", "sizemb": "MB", + "sortby": "排序", "start": "开始", "submit": "提交", "success": "成功", "teachers": "教师", - "time": "用时", + "time": "时间", "timesup": "时间到!", "today": "今天", "unexpectederror": "意外出错。请关闭并重新打开APP再试一次", @@ -118,7 +119,7 @@ "userdeleted": "该用户帐号已被删除", "userdetails": "用户细节", "users": "用户", - "view": "浏览", + "view": "查看", "viewprofile": "查看个人资料", "year": "年", "years": "年", diff --git a/www/core/lang/zh-tw.json b/www/core/lang/zh-tw.json index d0608dfbea4..a7cb5cac958 100644 --- a/www/core/lang/zh-tw.json +++ b/www/core/lang/zh-tw.json @@ -7,22 +7,22 @@ "cancel": "取消", "cannotconnect": "無法連接:請確認您輸入之網址正確,且您的位置使用的是Moodle2.4版或更新版本。", "cannotdownloadfiles": "在您的行動服務中禁用檔案下載. 請與您的網站管理員聯繫.", - "category": "類別", + "category": "類目", "choose": "選擇", "choosedots": "選擇...", "clearsearch": "清除搜尋", "clicktohideshow": "點按展開或縮合", "clicktoseefull": "點擊以看到詳細內容", - "close": "關閉", - "comments": "評論", + "close": "關閉視窗", + "comments": "您的評語", "commentscount": "評論數({{$a}})", "commentsnotworking": "無法取得評論資料", - "completion-alt-auto-fail": "已完成: {{$a}} (did not achieve pass grade)", - "completion-alt-auto-n": "未完成: {{$a}}", - "completion-alt-auto-pass": "已完成: {{$a}} (achieved pass grade)", - "completion-alt-auto-y": "已完成: {{$a}}", - "completion-alt-manual-n": "未完成: {{$ a}}. 選擇標記為完成.", - "completion-alt-manual-y": "已完成: {{$ a}}. 選擇標記為未完成.", + "completion-alt-auto-fail": "已完成:{{$a}} (不及格)", + "completion-alt-auto-n": "尚未完成:{{$a}}", + "completion-alt-auto-pass": "已經完成:{{$a}} (及格)", + "completion-alt-auto-y": "已經完成:{{$a}}", + "completion-alt-manual-n": "未完成:{{$a}} 。點選標記為完成。", + "completion-alt-manual-y": "已完成:{{$a}} 。點選標記為未完成。", "confirmcanceledit": "您確定要離開此頁面嗎? 所有的修改將會遺失.", "confirmdeletefile": "你確定要刪除這一檔案?", "confirmopeninbrowser": "你想要在瀏覽器內開啟嗎?", @@ -35,12 +35,12 @@ "datastoredoffline": "儲存在設備中的資料,因為它之前無法發送. 它稍後將自動發送.", "date": "日期", "day": "日", - "days": "日", + "days": "天數", "decsep": ".", "defaultvalue": "預設 ({{$a}})", "delete": "刪除", "deleting": "刪除中", - "description": "簡介文字", + "description": "說明", "dfdaymonthyear": "MM-DD-YYYY", "dfdayweekmonth": "ddd, D MMM", "dflastweekdate": "ddd", @@ -51,8 +51,8 @@ "done": "完成", "download": "下載", "downloading": "下載中", - "edit": "編修", - "error": "錯誤", + "edit": "編輯", + "error": "發生錯誤", "errorchangecompletion": "更改完成狀態時發生錯誤. 請再試一次.", "errordeletefile": "刪除檔案時出錯. 請再試一次.", "errordownloading": "下載檔案時發生錯誤", @@ -75,7 +75,7 @@ "groupsseparate": "分隔群組", "groupsvisible": "可視群組", "hasdatatosync": "此{{$ a}}有離線資料要同步.", - "help": "輔助說明", + "help": "幫助", "hide": "隱藏", "hour": "小時", "hours": "小時", @@ -88,10 +88,10 @@ "lastmodified": "最後修改", "lastsync": "最後同步", "listsep": ",", - "loading": "裝載中", + "loading": "載入中...", "lostconnection": "我們已斷了線,您需重新連線。您的口令目前是無效的。", "maxsizeandattachments": "新檔案的最大容量: {{$a.size}} ,最多附件:{{$a.attachments}}", - "min": "分鐘", + "min": "最低分", "mins": "分鐘", "mod_assign": "分配", "mod_assignment": "分配", @@ -123,12 +123,12 @@ "mygroups": "我的群組", "name": "名稱", "networkerrormsg": "網路未啟用或未運作。", - "never": "從不", - "next": "往後", + "never": "從未", + "next": "下一步", "no": "否", "nocomments": "沒有評論", - "nograde": "沒有成績", - "none": "無", + "nograde": "沒有成績。", + "none": "沒有", "nopasswordchangeforced": "你若沒有更新密碼無法進行此處理", "nopermissions": "抱歉,但是您目前沒有權限執行({{$a}})", "noresults": "沒有結果", @@ -149,18 +149,18 @@ "previous": "向前", "pulltorefresh": "拖曳更新", "redirectingtosite": "您將被重定向到網站.", - "refresh": "更新", - "required": "必須的", + "refresh": "重新整理", + "required": "必答", "requireduserdatamissing": "此使用者缺少一些必需的配置資料. 請在您的Moodle中填寫此數據, 然後重試.
    {{$ a}}", "retry": "重試", "save": "儲存", - "search": "搜尋", + "search": "搜尋中...", "searching": "搜尋中", "searchresults": "搜尋結果", "sec": "秒", "secs": "秒", "seemoredetail": "按此以觀看更多細節", - "send": "傳送", + "send": "送出", "sending": "傳送中", "serverconnection": "連結到伺服器時發生錯誤", "show": "顯示", @@ -173,9 +173,10 @@ "sizemb": "MB", "sizetb": "TB", "sorry": "抱歉...", + "sortby": "排序依據", "start": "開始", - "submit": "提交", - "success": "成功!", + "submit": "送出", + "success": "成功", "tablet": "平板", "teachers": "教師", "thereisdatatosync": "有離線的{{$ a}}要同步", @@ -194,7 +195,7 @@ "userdetails": "用戶的詳細資料", "usernotfullysetup": "用戶沒有完全設定好", "users": "用戶", - "view": "瀏覽", + "view": "檢視", "viewprofile": "瀏覽個人資料", "warningofflinedatadeleted": "離線資料 {{component}} '{{name}}' 已被刪除. {{error}}", "whoops": "糟糕!", diff --git a/www/core/lib/app.js b/www/core/lib/app.js index 5a2884c2594..be75fa0233e 100644 --- a/www/core/lib/app.js +++ b/www/core/lib/app.js @@ -103,6 +103,30 @@ angular.module('mm.core') self = {}, ssoAuthenticationDeferred; + /** + * Check if the browser supports mediaDevices.getUserMedia. + * + * @module mm.core + * @ngdoc method + * @name $mmApp#canGetUserMedia + * @return {Boolean} Whether the function is supported. + */ + self.canGetUserMedia = function() { + return !!(navigator && navigator.mediaDevices && navigator.mediaDevices.getUserMedia); + }; + + /** + * Check if the browser supports MediaRecorder. + * + * @module mm.core + * @ngdoc method + * @name $mmApp#canRecordMedia + * @return {Boolean} Whether the function is supported. + */ + self.canRecordMedia = function() { + return !!window.MediaRecorder; + }; + /** * Create a new state in the UI-router. * @@ -186,6 +210,18 @@ angular.module('mm.core') return $ionicPlatform.ready(); }; + /** + * Checks if the app is running in a desktop environment (not browser). + * + * @module mm.core + * @ngdoc method + * @name $mmApp#isDesktop + * @return {Bool} Whether the app is running in a desktop environment (not browser). + */ + self.isDesktop = function() { + return !!(window.process && window.process.versions && typeof window.process.versions.electron != 'undefined'); + }; + /** * Checks if the app is running in a real device with cordova-plugin-device installed. * diff --git a/www/core/lib/cron.js b/www/core/lib/cron.js index 4ef83d830c2..b9405333e49 100644 --- a/www/core/lib/cron.js +++ b/www/core/lib/cron.js @@ -16,6 +16,7 @@ angular.module('mm.core') .constant('mmCoreCronInterval', 3600000) // Default interval is 1 hour. .constant('mmCoreCronMinInterval', 300000) // Minimum interval is 5 minutes. +.constant('mmCoreCronDesktopMinInterval', 60000) // Minimum interval in desktop is 1 minute. .constant('mmCoreCronMaxTimeProcess', 120000) // Max time a process can block the queue. Defaults to 2 minutes. .constant('mmCoreCronStore', 'cron') @@ -37,7 +38,7 @@ angular.module('mm.core') * @name $mmCronDelegate */ .factory('$mmCronDelegate', function($log, $mmConfig, $mmApp, $timeout, $q, $mmUtil, mmCoreCronInterval, mmCoreCronStore, - mmCoreSettingsSyncOnlyOnWifi, mmCoreCronMinInterval, mmCoreCronMaxTimeProcess) { + mmCoreSettingsSyncOnlyOnWifi, mmCoreCronMinInterval, mmCoreCronMaxTimeProcess, mmCoreCronDesktopMinInterval) { $log = $log.getInstance('$mmCronDelegate'); @@ -190,8 +191,9 @@ angular.module('mm.core') return mmCoreCronInterval; } - // Don't allow intervals lower than 5 minutes. - return Math.max(mmCoreCronMinInterval, parseInt(hooks[name].instance.getInterval(), 10)); + // Don't allow intervals lower than the minimum. + var minInterval = $mmApp.isDesktop() ? mmCoreCronDesktopMinInterval : mmCoreCronMinInterval; + return Math.max(minInterval, parseInt(hooks[name].instance.getInterval(), 10)); }; /** diff --git a/www/core/lib/emulator.js b/www/core/lib/emulator.js deleted file mode 100644 index 7e610270a04..00000000000 --- a/www/core/lib/emulator.js +++ /dev/null @@ -1,140 +0,0 @@ -// (C) Copyright 2015 Martin Dougiamas -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -angular.module('mm.core') - -/** - * @ngdoc service - * @name $mmEmulatorManager - * @module mm.core - * @description - * This service handles the emulation of Cordova plugins in other environments like browser. - */ -.factory('$mmEmulatorManager', function($log, $q, $http, $mmFS, $window) { - - $log = $log.getInstance('$mmEmulatorManager'); - - var self = {}; - - /** - * Loads HTML API to simulate Cordova APIs. Reserved for core use. - * - * @module mm.core - * @ngdoc method - * @name $mmEmulatorManager#loadHTMLAPI - * @return {Promise} Promise resolved when the API is loaded. - * @protected - */ - self.loadHTMLAPI = function() { - - if ($mmFS.isAvailable()) { - $log.debug('Stop loading HTML API, it was already loaded or the environment doesn\'t need it.'); - return $q.when(); - } - - var deferred = $q.defer(), - basePath; - - $log.debug('Loading HTML API.'); - - // File API. - $window.requestFileSystem = $window.requestFileSystem || $window.webkitRequestFileSystem; - $window.resolveLocalFileSystemURL = $window.resolveLocalFileSystemURL || $window.webkitResolveLocalFileSystemURL; - - $window.LocalFileSystem = { - PERSISTENT: 1 - }; - - // FileTransfer API. - $window.FileTransfer = function() {}; - - $window.FileTransfer.prototype.download = function(url, filePath, successCallback, errorCallback) { - $http.get(url, {responseType: 'blob'}).then(function(data) { - if (!data || !data.data) { - errorCallback(); - } else { - filePath = filePath.replace(basePath, ''); // Remove basePath from the filePath. - filePath = filePath.replace(/%20/g, ' '); // Replace all %20 with spaces. - $mmFS.writeFile(filePath, data.data).then(function(e) { - successCallback(e); - }).catch(function(error) { - errorCallback(error); - }); - } - }).catch(function(error) { - errorCallback(error); - }); - }; - - // Cordova ZIP plugin. - $window.zip = { - unzip: function(source, destination, callback, progressCallback) { - // Remove basePath from the source and destination. - source = source.replace(basePath, ''); - source = source.replace(/%20/g, ' '); // Replace all %20 with spaces. - destination = destination.replace(basePath, ''); - destination = destination.replace(/%20/g, ' '); // Replace all %20 with spaces. - - $mmFS.readFile(source, $mmFS.FORMATARRAYBUFFER).then(function(data) { - var zip = new JSZip(data), - promises = []; - - angular.forEach(zip.files, function(file, name) { - var filepath = $mmFS.concatenatePaths(destination, name), - type; - - if (!file.dir) { - // It's a file. Get the mimetype and write the file. - type = $mmFS.getMimeType($mmFS.getFileExtension(name)); - promises.push($mmFS.writeFile(filepath, new Blob([file.asArrayBuffer()], {type: type}))); - } else { - // It's a folder, create it if it doesn't exist. - promises.push($mmFS.createDir(filepath)); - } - }); - - return $q.all(promises).then(function() { - // Success. - callback(0); - }); - }).catch(function() { - // Error. - callback(-1); - }); - } - }; - - // @todo: Implement FileTransfer.upload. - - // Request 500MB. - $window.webkitStorageInfo.requestQuota(PERSISTENT, 500 * 1024 * 1024, function(granted) { - $window.requestFileSystem(PERSISTENT, granted, function(entry) { - basePath = entry.root.toURL(); - $mmFS.setHTMLBasePath(basePath); - deferred.resolve(); - }, deferred.reject); - }, deferred.reject); - - return deferred.promise; - }; - - return self; -}) - -.config(function($mmInitDelegateProvider, mmInitDelegateMaxAddonPriority) { - if (!ionic.Platform.isWebView()) { - $mmInitDelegateProvider.registerProcess('mmEmulator', '$mmEmulatorManager.loadHTMLAPI', - mmInitDelegateMaxAddonPriority + 500, true); - } -}); diff --git a/www/core/lib/filesession.js b/www/core/lib/filesession.js new file mode 100644 index 00000000000..1bcded70804 --- /dev/null +++ b/www/core/lib/filesession.js @@ -0,0 +1,174 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.core') + +/** + * Helper to store some temporary data for file submission. + * + * It uses siteId and component name to index the files. + * Every component can provide a File area identifier to indentify every file list on the session. + * This value can be the activity id or a mix of name and numbers. + * + * @module mm.core + * @ngdoc service + * @name $mmFileSession + */ +.factory('$mmFileSession', function($mmSite) { + + var self = {}, + files = {}; + + /** + * Initializes the filearea to store the file. + * + * @param {String} component Component Name. + * @param {String|Number} id File area identifier. + * @param {String} [siteId] Site ID. If not defined, current site. + */ + function initFileArea(component, id, siteId) { + if (!files[siteId]) { + files[siteId] = {}; + } + + if (!files[siteId][component]) { + files[siteId][component] = {}; + } + + if (!files[siteId][component][id]) { + files[siteId][component][id] = []; + } + } + + /** + * Add a file to the session. + * + * @module mm.core + * @ngdoc method + * @name $mmFileSession#addFile + * @param {String} component Component Name. + * @param {String|Number} id File area identifier. + * @param {Object} file File to add. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Void} + */ + self.addFile = function(component, id, file, siteId) { + siteId = siteId || $mmSite.getId(); + + initFileArea(component, id, siteId); + + files[siteId][component][id].push(file); + }; + + /** + * Clear files stored in session. + * + * @module mm.core + * @ngdoc method + * @name $mmFileSession#clearFiles + * @param {String} component Component Name. + * @param {String|Number} id File area identifier. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Void} + */ + self.clearFiles = function(component, id, siteId) { + siteId = siteId || $mmSite.getId(); + if (files[siteId] && files[siteId][component] && files[siteId][component][id]) { + files[siteId][component][id] = []; + } + }; + + /** + * Get files stored in session. + * + * @module mm.core + * @ngdoc method + * @name $mmFileSession#getFiles + * @param {String} component Component Name. + * @param {String|Number} id File area identifier. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Array} Array of files in session. + */ + self.getFiles = function(component, id, siteId) { + siteId = siteId || $mmSite.getId(); + if (files[siteId] && files[siteId][component] && files[siteId][component][id]) { + return files[siteId][component][id]; + } + return []; + }; + + /** + * Remove a file stored in session. + * + * @module mm.core + * @ngdoc method + * @name $mmFileSession#removeFile + * @param {String} component Component Name. + * @param {String|Number} id File area identifier. + * @param {Object} file File to remove. The instance should be exactly the same as the one stored in session. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Void} + */ + self.removeFile = function(component, id, file, siteId) { + siteId = siteId || $mmSite.getId(); + if (files[siteId] && files[siteId][component] && files[siteId][component][id]) { + var position = files[siteId][component][id].indexOf(file); + if (position != -1) { + files[siteId][component][id].splice(position, 1); + } + } + }; + + /** + * Remove a file stored in session. + * + * @module mm.core + * @ngdoc method + * @name $mmFileSession#removeFileByIndex + * @param {String} component Component Name. + * @param {String|Number} id File area identifier. + * @param {Number} index Position of the file to remove. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Void} + */ + self.removeFileByIndex = function(component, id, index, siteId) { + siteId = siteId || $mmSite.getId(); + if (files[siteId] && files[siteId][component] && files[siteId][component][id] && index >= 0 && + index < files[siteId][component][id].length) { + files[siteId][component][id].splice(index, 1); + } + }; + + /** + * Set a group of files in the session. + * + * @module mm.core + * @ngdoc method + * @name $mmFileSession#setFiles + * @param {String} component Component Name. + * @param {String|Number} id File area identifier. + * @param {Object[]} newFiles Files to set. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Void} + */ + self.setFiles = function(component, id, newFiles, siteId) { + siteId = siteId || $mmSite.getId(); + + initFileArea(component, id, siteId); + + files[siteId][component][id] = newFiles; + }; + + return self; +}); diff --git a/www/core/lib/fs.js b/www/core/lib/fs.js index 63de16de91c..30f4435d8ba 100644 --- a/www/core/lib/fs.js +++ b/www/core/lib/fs.js @@ -24,7 +24,8 @@ angular.module('mm.core') * @description * This service handles the interaction with the FileSystem. */ -.factory('$mmFS', function($ionicPlatform, $cordovaFile, $log, $q, $http, $cordovaZip, $mmText, mmFsSitesFolder, mmFsTmpFolder) { +.factory('$mmFS', function($ionicPlatform, $cordovaFile, $log, $q, $http, $cordovaZip, $mmText, mmFsSitesFolder, mmFsTmpFolder, + $mmApp) { $log = $log.getInstance('$mmFS'); @@ -412,7 +413,7 @@ angular.module('mm.core') * * @module mm.core * @ngdoc method - * @name $mmFS#getFileSizeFromFileEntry + * @name $mmFS#getFileObjectFromFileEntry * @param {String} path Relative path to the file. * @return {Promise} Promise to be resolved when the size is calculated. */ @@ -591,7 +592,7 @@ angular.module('mm.core') return self.init().then(function() { // Create file (and parent folders) to prevent errors. return self.createFile(path).then(function(fileEntry) { - if (isHTMLAPI && typeof data == 'string') { + if (isHTMLAPI && !$mmApp.isDesktop() && (typeof data == 'string' || data.toString() == '[object ArrayBuffer]')) { // We need to write Blobs. var type = self.getMimeType(self.getFileExtension(path)); data = new Blob([data], {type: type || 'text/plain'}); @@ -674,6 +675,24 @@ angular.module('mm.core') }); }; + /** + * Get the base path where the application files are stored. Returns the value instantly, without waiting for it to be ready. + * + * @module mm.core + * @ngdoc method + * @name $mmFS#getBasePathInstant + * @return {String} Base path. If the service hasn't been initialized it will return an invalid value. + */ + self.getBasePathInstant = function() { + if (!basePath) { + return basePath; + } else if (basePath.slice(-1) == '/') { + return basePath; + } else { + return basePath + '/'; + } + }; + /** * Get temporary directory path. * @@ -746,41 +765,23 @@ angular.module('mm.core') from = self.removeStartingSlash(from.replace(basePath, '')); to = self.removeStartingSlash(to.replace(basePath, '')); + var fromFileAndDir = self.getFileAndDirectoryFromPath(from), + toFileAndDir = self.getFileAndDirectoryFromPath(to); + return self.init().then(function() { + if (toFileAndDir.directory) { + // Create the target directory if it doesn't exist. + return self.createDir(toFileAndDir.directory); + } + }).then(function() { if (isHTMLAPI) { - // In Cordova API we need to calculate the longest matching path to make it work. - // $cordovaFile.copyFile('a/', 'b/c.ext', 'a/', 'b/d.ext') doesn't work. - // cordovaFile.copyFile('a/b/', 'c.ext', 'a/b/', 'd.ext') works. - var commonPath = basePath, - dirsA = from.split('/'), - dirsB = to.split('/'); - - for (var i = 0; i < dirsA.length; i++) { - var dir = dirsA[i]; - if (dirsB[i] === dir) { - // Found a common folder, add it to common path and remove it from each specific path. - dir = dir + '/'; - commonPath = self.concatenatePaths(commonPath, dir); - from = from.replace(dir, ''); - to = to.replace(dir, ''); - } else { - // Folder doesn't match, stop searching. - break; - } - } + // In HTML API, the file name cannot include a directory, otherwise it fails. + var fromDir = self.concatenatePaths(basePath, fromFileAndDir.directory), + toDir = self.concatenatePaths(basePath, toFileAndDir.directory); - return $cordovaFile.copyFile(commonPath, from, commonPath, to); + return $cordovaFile.copyFile(fromDir, fromFileAndDir.name, toDir, toFileAndDir.name); } else { - // Check if to contains a directory. - var toFile = self.getFileAndDirectoryFromPath(to); - if (toFile.directory == '') { - return $cordovaFile.copyFile(basePath, from, basePath, to); - } else { - // Ensure directory is created. - return self.createDir(toFile.directory).then(function() { - return $cordovaFile.copyFile(basePath, from, basePath, to); - }); - } + return $cordovaFile.copyFile(basePath, from, basePath, to); } }); }; @@ -851,8 +852,8 @@ angular.module('mm.core') * @return {String} Internal URL. */ self.getInternalURL = function(fileEntry) { - if (isHTMLAPI) { - // HTML API doesn't implement toInternalURL. + if (!fileEntry.toInternalURL) { + // File doesn't implement toInternalURL, use toURL. return fileEntry.toURL(); } return fileEntry.toInternalURL(); diff --git a/www/core/lib/groups.js b/www/core/lib/groups.js index 651af503e29..e549a5866dd 100644 --- a/www/core/lib/groups.js +++ b/www/core/lib/groups.js @@ -93,6 +93,7 @@ angular.module('mm.core') * @name $mmGroups#getActivityGroupInfo * @param {Number} cmId Course Module Id of the feedback. * @param {Boolean} [addAllParts=true] True to add the all participants option, false otherwise. + * Always true for visible groups. * @param {Number} [userId] User ID. If not defined, use current user. * @param {String} [siteId] Site ID. If not defined, current site. * @return {Object} Containing the group info related to the activity. @@ -120,7 +121,7 @@ angular.module('mm.core') groupInfo.separateGroups = false; groupInfo.visibleGroups = false; } else { - if (addAllParts) { + if (addAllParts || groupInfo.visibleGroups) { groupInfo.groups = [ {'id': 0, 'name': $translate.instant('mm.core.allparticipants')} ]; diff --git a/www/core/lib/localnotif.js b/www/core/lib/localnotif.js index e2300fed332..a585573832c 100644 --- a/www/core/lib/localnotif.js +++ b/www/core/lib/localnotif.js @@ -106,7 +106,7 @@ angular.module('mm.core') } return db.get(store, id).then(function(entry) { - var code = parseInt(entry.code); + var code = parseInt(entry.code, 10); codes[key] = code; return code; }, function() { @@ -114,7 +114,7 @@ angular.module('mm.core') return db.query(store, undefined, 'code', true).then(function(entries) { var newCode = 0; if (entries.length > 0) { - newCode = parseInt(entries[0].code) + 1; + newCode = parseInt(entries[0].code, 10) + 1; } return db.insert(store, {id: id, code: newCode}).then(function() { codes[key] = newCode; @@ -167,7 +167,7 @@ angular.module('mm.core') return getSiteCode(siteid).then(function(sitecode) { return getComponentCode(component).then(function(componentcode) { // We use the % operation to keep the number under Android's limit. - return (sitecode * 100000000 + componentcode * 10000000 + parseInt(notificationid)) % 2147483647; + return (sitecode * 100000000 + componentcode * 10000000 + parseInt(notificationid, 10)) % 2147483647; }); }); } @@ -300,7 +300,7 @@ angular.module('mm.core') * @return {Boolean} True when local notifications plugin is installed. */ self.isAvailable = function() { - return window.plugin && window.plugin.notification && window.plugin.notification.local ? true: false; + return $mmApp.isDesktop() || !!(window.plugin && window.plugin.notification && window.plugin.notification.local); }; /** @@ -528,11 +528,11 @@ angular.module('mm.core') self.showNotificationPopover(notification); } - var id = parseInt(notification.id); + var id = parseInt(notification.id, 10); if (!isNaN(id)) { return $mmApp.getDB().insert(mmCoreNotificationsTriggeredStore, { id: id, - at: parseInt(notification.at) + at: parseInt(notification.at, 10) }); } else { return $q.reject(); diff --git a/www/core/lib/sitesmanager.js b/www/core/lib/sitesmanager.js index fe6b6e3c2f5..a51f329e830 100644 --- a/www/core/lib/sitesmanager.js +++ b/www/core/lib/sitesmanager.js @@ -913,7 +913,7 @@ angular.module('mm.core') // Check if URL has http(s) protocol. if (!url.match(/^https?:\/\//i)) { // URL doesn't have http(s) protocol. Check if it has any protocol. - if (url.match(/^[^:]{2,10}:\/\//i)) { + if ($mmUtil.isAbsoluteURL(url)) { // It has some protocol. Return empty array. return $q.when([]); } else { diff --git a/www/core/lib/util.js b/www/core/lib/util.js index 0edb004b4b3..b35f16f21cb 100644 --- a/www/core/lib/util.js +++ b/www/core/lib/util.js @@ -199,6 +199,19 @@ angular.module('mm.core') return url && url.indexOf('/pluginfile.php') !== -1; }; + /** + * Returns if a URL has any protocol, if not is a relative URL. + * + * @module mm.core + * @ngdoc method + * @name $mmUtil#isAbsoluteURL + * @param {String} url The url to test against the pattern + * @return {Boolean} TRUE if the url is absolute. FALSE if it is relative. + */ + self.isAbsoluteURL = function(url) { + return /^[^:]{2,10}:\/\//i.test(url) || /^(tel:|mailto:|geo:)/.test(url); + }; + /** * Returns if a URL is a theme image URL. * @@ -292,7 +305,12 @@ angular.module('mm.core') self.openFile = function(path) { var deferred = $q.defer(); - if (window.plugins) { + if ($mmApp.isDesktop()) { + // It's a desktop app, send an event so the file is opened. It has to be done with an event + // because opening the file from here (renderer process) doesn't focus the opened app. + require('electron').ipcRenderer.send('openItem', path); + deferred.resolve(); + } else if (window.plugins) { var extension = $mmFS.getFileExtension(path), mimetype = $mmFS.getMimeType(extension); @@ -378,7 +396,16 @@ angular.module('mm.core') * @return {Void} */ self.openInBrowser = function(url) { - window.open(url, '_system'); + if ($mmApp.isDesktop()) { + // It's a desktop app, use Electron shell library to open the browser. + var shell = require('electron').shell; + if (!shell.openExternal(url)) { + // Open browser failed, open a new window in the app. + window.open(url, '_system'); + } + } else { + window.open(url, '_system'); + } }; /** @@ -419,10 +446,17 @@ angular.module('mm.core') * @module mm.core * @ngdoc method * @name $mmUtil#closeInAppBrowser + * @param {Boolean} [closeAll] Desktop only. True to close all secondary windows, false to close only the "current" one. * @return {Void} */ - self.closeInAppBrowser = function() { - $cordovaInAppBrowser.close(); + self.closeInAppBrowser = function(closeAll) { + // Use try/catch because it will fail if there is no opened InAppBrowser. + try { + $cordovaInAppBrowser.close(); + if (closeAll && $mmApp.isDesktop()) { + require('electron').ipcRenderer.send('closeSecondaryWindows'); + } + } catch(ex) {} }; /** @@ -717,7 +751,8 @@ angular.module('mm.core') }; function getErrorTitle(message) { - if (message == $translate.instant('mm.core.networkerrormsg')) { + if (message == $translate.instant('mm.core.networkerrormsg') || + message == $translate.instant('mm.fileuploader.errormustbeonlinetoupload')) { return '\ '; } diff --git a/www/core/lib/ws.js b/www/core/lib/ws.js index 84b5f214d1e..c6b4a2382fc 100644 --- a/www/core/lib/ws.js +++ b/www/core/lib/ws.js @@ -326,6 +326,10 @@ angular.module('mm.core') self.downloadFile = function(url, path, addExtension) { $log.debug('Downloading file', url, path, addExtension); + if (!$mmApp.isOnline()) { + return $mmLang.translateAndReject('mm.core.networkerrormsg'); + } + // Use a tmp path to download the file and then move it to final location.This is because if the download fails, // the local file is deleted. var tmpPath = path + '.tmp'; @@ -399,6 +403,10 @@ angular.module('mm.core') return $q.reject(); } + if (!$mmApp.isOnline()) { + return $mmLang.translateAndReject('mm.core.networkerrormsg'); + } + var ftOptions = {}, uploadUrl = preSets.siteurl + '/webservice/upload.php'; diff --git a/www/core/main.js b/www/core/main.js index 3436248ff2c..7889fd96dfa 100644 --- a/www/core/main.js +++ b/www/core/main.js @@ -277,6 +277,7 @@ angular.module('mm.core', ['pascalprecht.translate']) } } }); + $window.addEventListener('native.keyboardhide', function(e) { $mmEvents.trigger(mmCoreEventKeyboardHide, e); @@ -285,6 +286,17 @@ angular.module('mm.core', ['pascalprecht.translate']) ionic.trigger('resize'); } }); + + // In desktop, re-define getParentOrSelfWithClass to allow scrolling with trackpad when hovering deep elements. + // In iOS, re-define getParentWithClass to prevent the keyboard to hide deep input elements. + var fnName = !$mmApp.isDevice() ? 'getParentOrSelfWithClass' : (ionic.Platform.isIOS() ? 'getParentWithClass' : ''); + if (fnName) { + var originalFunction = ionic.DomUtil[fnName]; + ionic.DomUtil[fnName] = function(e, className, depth) { + depth = depth || 20; + return originalFunction(e, className, depth); + }; + } }); // Send event when device goes online. diff --git a/www/core/scss/fontawesome.scss b/www/core/scss/fontawesome.scss new file mode 100644 index 00000000000..ced2f2e1e7d --- /dev/null +++ b/www/core/scss/fontawesome.scss @@ -0,0 +1,48 @@ +/** This file is intended to translate fontawesome to ionicons while the font is not supported */ + +.fa.icon { + @extend .ion; +} + +.fa { + font-size: $button-icon-size; + width: $button-icon-size; + height: $button-icon-size; +} + +/** Fixed width */ +.fa-fw { + width: (18em / 14); + text-align: center; +} + +/** Uncomment for dev purposes, it will show an asterisk in red where a missing icon is */ +/*.fa:before { + color: red !important; + content: $ionicon-var-asterisk; +}*/ + +/** Icons translation */ +.fa-search-plus:before { + content: $ionicon-var-ios-search-strong; +} + +.fa-cog:before { + content: $ionicon-var-gear-b; +} + +.fa-trash:before { + content: $ionicon-var-trash-a; +} + +.fa-thumbs-up:before { + content: $ionicon-var-thumbsup; +} + +.fa-thumbs-down:before { + content: $ionicon-var-thumbsdown; +} + +.fa-ban:before { + content: $ionicon-var-minus-circled; +} \ No newline at end of file diff --git a/www/core/scss/styles.scss b/www/core/scss/styles.scss index ac1142effc1..9abc3227855 100644 --- a/www/core/scss/styles.scss +++ b/www/core/scss/styles.scss @@ -52,9 +52,9 @@ $item-input-padding: 16px !default; * App Branding */ .mm-bglogo { - background-color: #ff5c00; /* Change this to add a bg image or change color */ - background: -webkit-radial-gradient(#ff7600, #ff5c00); - background: radial-gradient(#ff7600, #ff5c00); + background-color: $mm-color-init-screen; /* Change this to add a bg image or change color */ + background: -webkit-radial-gradient($mm-color-init-screen-alt, $mm-color-init-screen); + background: radial-gradient($mm-color-init-screen-alt, $mm-color-init-screen); background-repeat: no-repeat; background-position: center center; position: absolute; @@ -73,17 +73,17 @@ $item-input-padding: 16px !default; } img { - width: 60%; - max-width: 300px; + width: $mm-init-screen-logo-width; + max-width: $mm-init-screen-logo-max-width; display: block; margin: 0 auto; margin-bottom: 30px; } .spinner { - color: white; - stroke: white; - fill: white; + color: $mm-init-screen-spinner-color; + stroke: $mm-init-screen-spinner-color; + fill: $mm-init-screen-spinner-color; } } @@ -353,6 +353,13 @@ p.item-text-wrap { height: 100%; border-radius: 50%; } +.avatar-round { + max-width: 40px; + max-height: 40px; + width: 100%; + height: 100%; + border-radius: 50%; +} // Split pane. .mm-split-pane { @@ -972,6 +979,23 @@ mm-timer { background: transparent; } +mm-multiple-select { + cursor: pointer; + + .item-stacked-label { + ion-label.input-label, p { + padding-right: 30px; + white-space: normal; + } + } + .icon.ion-android-arrow-dropdown { + font-size: 21px; + color: #999999; + right: 5px; + } + +} + .button.mm-button-icon-small { padding: 0 3px; min-height: $mm-button-icon-small-height; @@ -1632,4 +1656,34 @@ h2.invert { &.ng-leave.ng-leave-active { opacity: 0; } -} \ No newline at end of file +} + +// Textarea to copy text in browser or desktop. Don't use display none because otherwise it can't be selected. +.mm-browser-copy-area { + position: absolute; + left: -10000px; +} + +// Full screen modal. +.modal-wrapper .modal.mm-fullscreen-modal { + width: 100%; + height: 100%; + left: 0; + top: 0; + bottom: 0; + right: 0 +} + +// Buttons in header in modals. +.modal .bar-header .button { + border-color: transparent; + background: none; +} + +::-webkit-calendar-picker-indicator, ::-webkit-inner-spin-button, ::-webkit-clear-button { + display: none; +} + +*[ng-click] { + cursor: pointer; +} diff --git a/www/core/templates/multipleselect.html b/www/core/templates/multipleselect.html index 95bc57a20c6..485ae0be922 100644 --- a/www/core/templates/multipleselect.html +++ b/www/core/templates/multipleselect.html @@ -1,5 +1,6 @@
    {{ title }}

    {{ selectedOptions }}

    +
    \ No newline at end of file diff --git a/www/electron.js b/www/electron.js new file mode 100644 index 00000000000..7f7c6b03bdf --- /dev/null +++ b/www/electron.js @@ -0,0 +1,139 @@ + +const {app, BrowserWindow, ipcMain, shell} = require('electron'); +const path = require('path'); +const url = require('url'); +const fs = require('fs'); + +// Keep a global reference of the window object, if you don't, the window will +// be closed automatically when the JavaScript object is garbage collected. +let mainWindow; + +function createWindow() { + // Create the browser window. + var width = 800, + height = 600; + + const screen = require('electron').screen; + if (screen) { + const display = screen.getPrimaryDisplay(); + if (display && display.workArea) { + width = display.workArea.width || width; + height = display.workArea.height || height; + } + } + + mainWindow = new BrowserWindow({ + width: width, + height: height, + minWidth: 400, + minHeight: 400, + textAreasAreResizable: false, + plugins: true, + show: false // Don't show it until it's ready to prevent showing a blank screen. + }); + + // And load the index.html of the app. + mainWindow.loadURL(url.format({ + pathname: path.join(__dirname, 'index.html'), + protocol: 'file:', + slashes: true + })); + + mainWindow.once('ready-to-show', () => { + mainWindow.show(); + mainWindow.maximize(); + }); + + // Emitted when the window is closed. + mainWindow.on('closed', () => { + // Dereference the window object. + mainWindow = null + }); +} + +// This method will be called when Electron has finished initialization and is ready to create browser windows. +// Some APIs can only be used after this event occurs. +app.on('ready', function() { + createWindow(); +}); + +// Quit when all windows are closed. +app.on('window-all-closed', () => { + app.exit(); +}); + +app.on('activate', () => { + // On macOS it's common to re-create a window in the app when the dock icon is clicked and there are no other windows open. + if (mainWindow === null) { + createWindow(); + } +}); + +// Read the config.json file to set app's protocol (custom URL scheme). +fs.readFile(path.join(__dirname, 'config.json'), 'utf8', (err, data) => { + var ssoScheme = 'moodlemobile'; // Default value. + if (!err) { + try { + data = JSON.parse(data); + ssoScheme = data.customurlscheme; + } catch(ex) {} + } + + app.setAsDefaultProtocolClient(ssoScheme); +}); + +// Make sure that only a single instance of the app is running. +var shouldQuit = app.makeSingleInstance((argv, workingDirectory) => { + // Another instance was launched. If it was launched with a URL, it should be in the second param. + if (argv && argv[1]) { + appLaunched(argv[1]); + } else { + focusApp(); + } +}); + +// For some reason, shouldQuit is always true in signed Mac apps so we should ingore it. +if (shouldQuit && os.platform().indexOf('darwin') == -1) { + // It's not the main instance of the app, kill it. + app.exit(); + return; +} + +// Listen for open-url events (Mac OS only). +app.on('open-url', (event, url) => { + event.preventDefault(); + appLaunched(url); +}); + +function appLaunched(url) { + // App was launched again with a URL. Focus the main window and send an event to treat the URL. + if (mainWindow) { + focusApp(); + mainWindow.webContents.send('mmAppLaunched', url); // Send an event to the main window. + } +} + +function focusApp() { + if (mainWindow) { + if (mainWindow.isMinimized()) { + mainWindow.restore(); + } + mainWindow.focus(); + } +} + +// Listen for events sent by the renderer processes (windows). +ipcMain.on('openItem', (event, path) => { + shell.openItem(path); +}); + +ipcMain.on('closeSecondaryWindows', () => { + var windows = BrowserWindow.getAllWindows(); + for (var i = 0; i < windows.length; i++) { + if (!mainWindow || windows[i].id != mainWindow.id) { + windows[i].close(); + } + } +}); + +ipcMain.on('focusApp', focusApp); diff --git a/www/errorreport.js b/www/errorreport.js index e1301956fd9..5b16567c8a5 100644 --- a/www/errorreport.js +++ b/www/errorreport.js @@ -16,7 +16,7 @@ // Using JS confirm function we are sure that the user get notified in a Mobile device. // This script should be added at the begining of the index.html and it should only use native javascript functions. -var appVersion = '3.3.0 (2018)', +var appVersion = '3.3.1 (2019)', reportInBackgroundName = 'mmCoreReportInBackground', errors = [], ignoredFiles = ['www/index.html#/site/mod_page', 'www/index.html#/site/mod_resource', 'www/index.html#/site/mm_course-section'], diff --git a/www/img/moodle.png b/www/img/logo.png similarity index 100% rename from www/img/moodle.png rename to www/img/logo.png diff --git a/www/img/moodle_white.png b/www/img/logo_white.png similarity index 100% rename from www/img/moodle_white.png rename to www/img/logo_white.png diff --git a/www/index.html b/www/index.html index ffd50b38ce0..a3bea4024f6 100644 --- a/www/index.html +++ b/www/index.html @@ -3,8 +3,8 @@ - - + + Moodle Desktop