Bläddra i källkod

Merge branch 'master' of github.com:chamilo/chamilo-lms

Julio Montoya 6 år sedan
förälder
incheckning
569a36a3d9

+ 9 - 5
main/inc/ajax/agenda.ajax.php

@@ -19,6 +19,8 @@ if ($type == 'course') {
 }
 
 $agenda = new Agenda($type);
+// get filtered type
+$type = $agenda->getType();
 
 switch ($action) {
     case 'add_event':
@@ -26,15 +28,17 @@ switch ($action) {
             break;
         }
         $add_as_announcement = isset($_REQUEST['add_as_annonuncement']) ? $_REQUEST['add_as_annonuncement'] : null;
-        $comment = isset($_REQUEST['comment']) ? $_REQUEST['comment'] : null;
+        $title = isset($_REQUEST['title']) ? Security::remove_XSS($_REQUEST['title']) : null;
+        $content = isset($_REQUEST['content']) ? Security::remove_XSS($_REQUEST['content']) : null;
+        $comment = isset($_REQUEST['comment']) ? Security::remove_XSS($_REQUEST['comment']) : null;
         $userToSend = isset($_REQUEST['users_to_send']) ? $_REQUEST['users_to_send'] : [];
 
         echo $agenda->addEvent(
             $_REQUEST['start'],
             $_REQUEST['end'],
             $_REQUEST['all_day'],
-            $_REQUEST['title'],
-            $_REQUEST['content'],
+            $title,
+            $content,
             $userToSend,
             $add_as_announcement,
             null, //$parentEventId = null,
@@ -54,8 +58,8 @@ switch ($action) {
             $_REQUEST['start'],
             $_REQUEST['end'],
             $_REQUEST['all_day'],
-            $_REQUEST['title'],
-            $_REQUEST['content']
+            $title,
+            $content
         );
         break;
     case 'delete_event':

+ 12 - 0
main/inc/lib/agenda.lib.php

@@ -160,6 +160,18 @@ class Agenda
         }
     }
 
+    /**
+     * Returns the type previously set (and filtered) through setType
+     * If setType() was not called, then type defaults to "personal" as
+     * set in the class definition.
+     */
+    public function getType()
+    {
+        if (isset($this->type)) {
+            return $this->type;
+        }
+    }
+
     /**
      * @param int $id
      */

+ 1 - 0
main/inc/lib/document.lib.php

@@ -6352,6 +6352,7 @@ class DocumentManager
             'dropboxusercontent.com',
             'fileserve.com',
             'drive.google.com',
+            'docs.google.com',
             'icloud.com',
             'mediafire.com',
             'mega.nz',

+ 20 - 6
main/inc/lib/template.lib.php

@@ -1646,20 +1646,25 @@ class Template
                     $course = api_get_course_entity($courseId);
                     // @TODO: support right-to-left in title
                     $socialMeta .= '<meta property="og:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
+                    $socialMeta .= '<meta property="twitter:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
                     $socialMeta .= '<meta property="og:url" content="'.api_get_course_url($course->getCode()).'" />'."\n";
 
                     $metaDescription = api_get_setting('meta_description');
                     if (!empty($course->getDescription())) {
-                        $socialMeta .= '<meta property="og:description" content="'.$course->getDescription().'" />'."\n";
+                        $socialMeta .= '<meta property="og:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
+                        $socialMeta .= '<meta property="twitter:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
                     } elseif (!empty($metaDescription)) {
                         $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
+                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
                     }
 
                     $picture = CourseManager::getPicturePath($course, true);
                     if (!empty($picture)) {
                         $socialMeta .= '<meta property="og:image" content="'.$picture.'" />'."\n";
+                        $socialMeta .= '<meta property="twitter:image" content="'.$picture.'" />'."\n";
+                        $socialMeta .= '<meta property="twitter:image:alt" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
                     } else {
-                        $socialMeta .= $this->getMetaPortalImagePath();
+                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
                     }
                 } elseif ($sessionId !== 0) {
                     // If we are on a session "about" screen, publish info about the session
@@ -1667,6 +1672,7 @@ class Template
                     $session = $em->find('ChamiloCoreBundle:Session', $sessionId);
 
                     $socialMeta .= '<meta property="og:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
+                    $socialMeta .= '<meta property="twitter:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
                     $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH)."session/{$session->getId()}/about/".'" />'."\n";
 
                     $sessionValues = new ExtraFieldValue('session');
@@ -1676,19 +1682,23 @@ class Template
                     if (!empty($sessionImage) && is_file($sessionImageSysPath)) {
                         $sessionImagePath = api_get_path(WEB_UPLOAD_PATH).$sessionImage;
                         $socialMeta .= '<meta property="og:image" content="'.$sessionImagePath.'" />'."\n";
+                        $socialMeta .= '<meta property="twitter:image" content="'.$sessionImagePath.'" />'."\n";
+                        $socialMeta .= '<meta property="twitter:image:alt" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
                     } else {
-                        $socialMeta .= $this->getMetaPortalImagePath();
+                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
                     }
                 } else {
                     // Otherwise (not a course nor a session, nor a user, nor a badge), publish portal info
                     $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
+                    $socialMeta .= '<meta property="twitter:title" content="'.$metaTitle.'" />'."\n";
                     $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
 
                     $metaDescription = api_get_setting('meta_description');
                     if (!empty($metaDescription)) {
                         $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
+                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
                     }
-                    $socialMeta .= $this->getMetaPortalImagePath();
+                    $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
                 }
             }
         }
@@ -1700,10 +1710,10 @@ class Template
 
     /**
      * Get platform meta image tag (check meta_image_path setting, then use the logo).
-     *
+     * @param string $imageAlt The alt attribute for the image
      * @return string The meta image HTML tag, or empty
      */
-    private function getMetaPortalImagePath()
+    private function getMetaPortalImagePath($imageAlt = '')
     {
         // Load portal meta image if defined
         $metaImage = api_get_setting('meta_image_path');
@@ -1713,11 +1723,15 @@ class Template
         if (!empty($metaImage)) {
             if (is_file($metaImageSysPath)) {
                 $portalImageMeta = '<meta property="og:image" content="'.$metaImageWebPath.'" />'."\n";
+                $portalImageMeta .= '<meta property="twitter:image" content="'.$metaImageWebPath.'" />'."\n";
+                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
             }
         } else {
             $logo = ChamiloApi::getPlatformLogoPath($this->theme);
             if (!empty($logo)) {
                 $portalImageMeta = '<meta property="og:image" content="'.$logo.'" />'."\n";
+                $portalImageMeta .= '<meta property="twitter:image" content="'.$logo.'" />'."\n";
+                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
             }
         }
 

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 6 - 6
main/lang/brazilian/trad4all.inc.php


+ 2 - 1
main/lang/catalan/trad4all.inc.php

@@ -6469,7 +6469,8 @@ $CourseRequestLegalNote = "La informació d'aquesta sol·licitud de formació é
 $EnableCourseValidation = "Sol·licitud de cursos";
 $EnableCourseValidationComment = "Quan la sol·licitud de cursos està activada, un professor no podrà crear un curs per si mateix sinó que haurà d'emplenar una sol·licitud. L'administrador de la plataforma revisarà la sol·licitud i l'aprovarà o refusarà. Aquesta funcionalitat es basa en missatges de correu electrònic automàtics pel que s'ha d'assegurar que la seva instal·lació de Chamilo utilitza un servidor de correu i una adreça de correu electrònic dedicada a aquest fet.";
 $CourseRequestAskInfoEmailSubject = "%s Sol·licitud d'informació %s";
-$CourseRequestAskInfoEmailText = "Hem rebut la seva sol·licitud per a la creació d'un curs amb el codi %s. Abans de considerar la seva aprovació necessitem alguna informació addicional. \n\ nFeu una breu descripció del contingut del curs, els objectius i els estudiants o un altre tipus d'usuaris que hagin de participar. Si és el cas, esmenti el nom de la institució o òrgan en nom de la qual Vostè ha fet la sol·licitud.";
+$CourseRequestAskInfoEmailText = "Hem rebut la seva sol·licitud per a la creació d'un curs amb el codi %s. Abans de considerar la seva aprovació necessitem alguna informació addicional.\n\n
+Feu una breu descripció del contingut del curs, els objectius i els estudiants o un altre tipus d'usuaris que hagin de participar. Si és el cas, esmenti el nom de la institució o òrgan en nom de la qual Vostè ha fet la sol·licitud.";
 $CourseRequestAcceptedEmailSubject = "%s La petició del curs %s ha estat aprovada";
 $CourseRequestAcceptedEmailText = "La vostra sol·licitud del curs %s ha estat aprovada. Un curs nou %s ha estat creat i heu quedat inscrit a ell com a professor.\n\nPodreu accedir al curs creat des de: %s";
 $CourseRequestRejectedEmailSubject = "%s La sol·licitud del curs %s ha estat denegada";

+ 1 - 1
main/lang/english/trad4all.inc.php

@@ -7582,7 +7582,7 @@ $SkillProfile = "Skill profile";
 $AchievedSkills = "Achieved skills";
 $BusinessCard = "Business card";
 $BadgeDetails = "Badge details";
-$TheUserXNotYetAchievedTheSkillX = "The user %s not yet achieved the skill \"%s\"";
+$TheUserXNotYetAchievedTheSkillX = "The user %s has not achieved the skill \"%s\" yet";
 $IssuedBadgeInformation = "Issued badge information";
 $RecipientDetails = "Recipient details";
 $SkillAcquiredAt = "Skill acquired at";

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2 - 1
main/lang/galician/trad4all.inc.php


+ 9 - 8
main/lang/german/trad4all.inc.php

@@ -21,7 +21,7 @@ $SkillsReport = "Fähigkeitenübersicht";
 $AssignedUsersListToStudentBoss = "User nach zugeordnetem Vorgesetzten";
 $AssignUsersToBoss = "User Vorgesetzten zuordnen";
 $RoleStudentBoss = "Vorgesetzter der Studenten";
-$CosecantCsc = "Kosekans:\t\t\t\csc(x)";
+$CosecantCsc = "Kosekans:\t\t\t\tcsc(x)";
 $HyperbolicCosecantCsch = "Hyperbelartige kosekans:\t\tcsch(x)";
 $ArccosecantArccsc = "Arkuskosekans:\t\t\tarccsc(x)";
 $HyperbolicArccosecantArccsch = "Hyperbelartige Arkuskosekans:\t\tarccsch(x)";
@@ -1509,7 +1509,7 @@ $RegistrationRequiredFormsTitle = "Erforderliche Angaben bei der Regsitrierung";
 $RegistrationRequiredFormsComment = "Welche Angaben sind erforderlich (ausser Nachname, Vorname, Benutzername und Kennwort)";
 $DefaultGroupQuotumTitle = "Standard Speicherplatz für Gruppen";
 $DefaultGroupQuotumComment = "Standard Speicherplatz für Dokumente innerhalb von Gruppen?";
-$AllowLostPasswordTitle = "\Passwort vergessen\"- Funktion";
+$AllowLostPasswordTitle = "\"Passwort vergessen\"- Funktion";
 $AllowLostPasswordComment = "Darf der Nutzer sein vergessenes Kennwort anfordern?";
 $AllowRegistrationTitle = "Selbst-Registrierung";
 $AllowRegistrationComment = "Sollen sich neue Benutzer selbst registrieren können?";
@@ -7978,9 +7978,10 @@ $GoToSurvey = "Zur Umfrage";
 $OralExpressionHelpText = "Du kannst während der Aufnahme auf « Aufnahme anhalten » klicken. Wenn du nicht zufrieden bist, nimm dich erneut auf. Dies wird die vorherige Aufnahme überschreiben. Zufrieden? Um deine Aufnahme zu senden, klick einfach auf « Übung beenden ».";
 $MyGeneralCertificate = "Mein Zertifikat";
 $BossAlertMsgSentToUserXTitle = "Follow-up Nachricht über Lernende %s";
-$BossAlertUserXSentMessageToUserYWithLinkZ = "Hallo,<br/><br/>Benutzer %s hat eine Follow-up-Nachricht zum Lernenden %s gesendet.<br/><br/>Die Nachricht ist an %s sichtbar";
-$WhyYouWantToDeleteYourLegalAgreement = "Sie können unten einen Löschantrag stellen, um die erteilte Zustimmung zurückzuziehen oder Ihr Konto zu löschen.</br>Nachdem Sie die Zustimmung zu unseren Nutzungsbedingungen zurückgezogen haben, müssen Sie beim nächsten Login diese erneut zustimmen, denn wir Ihnen keinen Zugang zu Ihrem persönlichen Lernpfad ermöglichen können, wenn wir Ihre persönlichen Daten nicht verarbeiten dürfen.</br>Nachdem Sie den Löschantrag gestellt haben, wird Ihr Konto tatsächlich gelöscht, inklusiv alle besuchte Insel und kontobezogene Daten. Deswegen bitten wir Sie, diese Möglichkeit nach reifer Überlegung zu nutzen.</br>In beiden Fällen werden die Administratorinnen und Administratoren dieser Seite Ihre Anfrage überprüfen, um jegliches Missverständnis und den ungewollten unwiederunflichen Verlust Ihrer Daten zu vermeiden";
-$ExplanationDeleteLegal = "Bitte Begünden Sie kurz, warum Sie diesen Löschantrag stellen, damit wir das Löschen bestmöglich veranlassen können.";
-$DeleteAccount = "konto löschen";
-$ExplanationDeleteAccount = "Bitte Begünden Sie kurz, warum Sie diesen Löschantrag stellen, damit wir das Löschen bestmöglich veranlassen können.";
-?>
+$BossAlertUserXSentMessageToUserYWithLinkZ = "Hallo,<br/><br/>
+
+Benutzer %s hat eine Follow-up-Nachricht zum Lernenden %s gesendet.<br/><br/>
+
+Die Nachricht ist an %s sichtbar";
+$PersonalDataReport = "Persönliche Daten";
+?>

+ 3 - 99
main/lang/italian/trad4all.inc.php

@@ -7656,103 +7656,7 @@ $LastXDays = "Ultimi %s giorni";
 $ExportBadges = "Esporta i badge";
 $LanguagesDisableAllExceptDefault = "Abilita solo la lingua d default della piattaforma";
 $ThereAreUsersUsingThisLanguagesDisableItManually = "Alcuni utenti usano questa lingua: è necessario disabilitarla manualmente";
+$FollowedStudentBosses = "Tutor che ha seguito gli studenti";
+$AdditionallyYouHaveObtainedTheFollowingSkills = "Hai inoltre acquisito le seguenti competenze";
 $ExportToChamiloFormat = "Esporta un Modulo didattico";
-$AdditionallyYouHaveObtainedTheFollowingSkills="Hai inoltre acquisito le seguenti competenze";
-$AssignmentLinkstoStudentsPage="Accesso al lavoro redatto dagli studenti";
-$AssignCoach="Assegnare un tutor";
-$AssignSkill="Assegna l''abilità";
-$AssignedTo="Assegnato a";
-$AssignUser="Assegnare l''utente";
-$Assign="Assegnare";
-$AssignedTo="Assegnato a";
-$CalendarStartDate="Data di inizio";
-$Contacts="Contatti";
-$ContactsList="Lista di contatti";
-$Contact="Contatto";
-$CurrentPasswordEmptyOrIncorrect="La password inserita è errata";
-$CurrentPassword="Password attuale";
-$DearXComma="Caro/Cara %s,";
-$DocumentAutoLaunch="Collegamento a Documenti";
-$DoubleValidationMessage="Conferma di voler aderire alla presente piattaforma";
-$FilesUpload="documenti inviati";
-$FollowedStudentBosses="Tutor che ha seguito gli studenti";
-$HisProfileIs="Il suo profilo è";
-$LastConnection="Ultima connessione";
-$LegalAccepted="Accordo legale accettato";
-$Map="Carta";
-$MyGeneralCertificate="Il mio certificato generale";
-$MyLocation="La mia posizione";
-$NewPasswordRequirementsNotMatched="La nuova password non rispetta i prerequisiti minimi di sicurezza";
-$OralExpressionHelpText="Durante la registrazione, puoi fare una pausa quando desideri. Se non sei soddisfatto, registrati di nuovo. La nuova registrazione si sovrascriverà a quella precedente. Soddisfatto? Per trasmettere la registrazione clicca su « Salva audio registrato ».";
-$PasswordVeryWeak="Molto debole";
-$PauseRecordingAudio="Interrompere la registrazione";
-$PersonalEmail="Indirizzo e-mail personale";
-$PlayRecordingAudio="Riprendere la registrazione";
-$PriorityNormal="Normale";
-$PriorityHigh="Alta";
-$PriorityLow="Bassa";
-$Priority="Priorità";
-$PriorityHigh="Alta";
-$PriorityLow="Bassa";
-$PriorityNormal="Normale";
-$ProfileIsNotCompleted="Per continuare è necessario completare il profilo";
-$QuoteMessage="Cita questo messaggio";
-$ReadingComprehension="Comprensione della lettura";
-$ReadingComprehensionLevelX="%s di parole al minuto";
-$ReadingComprehensionLevelX="%s di parole al minuto";
-$ReadingQuestionCongratsSpeedXNotReachedForYWords="Purtroppo, sembra che la velocità di %s parole/minuto sia troppo rapida per te al momento, questa volta su un testo di %s parole.";
-$ReadingQuestionCongratsSpeedXReachedForYWords="Congratulazioni, hai raggiunto la velocità %s parole/minuto comprendendo correttamente un testo di %s parole.";
-$RecordAudio="Registrazione audio";
-$RegistrationConfirmation="Conferma dell''iscrizione";
-$RegistrationConfirmationEmailMessage="Per completare la tua iscrizione alla piattaforma, è necessario confermare il tuo account cliccando sul seguente link";
-$RegistrationConfirmationEmailMessage="Per completare la tua iscrizione alla piattaforma, è necessario confermare il tuo account cliccando sul seguente link";
-$RegistrationRoleFollowCourses="Seguire delle lezioni";
-$RegistrationRoleTeachCourses="Insegnare";
-$RegistrationRoleWhatDoYouWantToDo="Che cosa desideri fare?";
-$RemainingXAttempts="Numero di tentativi rimasti: %s";
-$ReSendConfirmationMail="Inviare una nuova mail di conferma";
-$SaveRecordedAudio="Salvare l''audio registrato";
-$ScoreNote="Nota";
-$ScoreTest="Test";
-$SelectWeeksSpan="Seleziona la durata in settimane";
-$SendLegal="Invia l''accordo legale";
-$SendLegalDescriptionToUrlX="Sottoscrivi le nostre condizioni legali qui: %s";
-$SendTermsDescriptionToUrlX="Buongiorno, <br />Il tuo tutor ti ha inviato l''accordo legale. Lo puoi firmare seguendo la URL: %s";
-$SendTermsSubject="Il tuo accordo legale sta per essere firmato.";
-$SessionDurationNotStartedMaxX="Questa sessione ha una durata massima di %s giorni.";
-$SessionDurationXDaysTotal="Questa sessione ha una durata limitata a %s giorni.";
-$ShortName="Nome abbreviato";
-$SrcEmail="E-mail";
-$SrcPhone="Telefono";
-$StartRecordingAudio="Inizio della registrazione";
-$StudentCourseProgressX="Progresso: %s % %";
-$StudentCourseScoreX="Punteggio: %s % %";
-$StudentHadEnoughSkills="Lo studente ha ottenuto il numero di competenze secondarie necessarie a convalidare la competenza principale.";
-$StudentXHadEnoughSkillsToGetSkillXToAssignClickHereX="Lo studente %s ha ottenuto il numero sufficiente di competenze secondarie per ottenere la competenza %s. Per assegnargliela cliccare qui: %s";
-$StudentXIsNotSubscribedToCourse="Lo/La studente/ssa %s non è iscritto/a a questo corso";
-$TeacherPicture="Fotografia del docente";
-$TemplateCertificateComment="Esempio di certificato";
-$TemplateCertificateTitle="Certificato";
-$TemplateTitleAssigment="Descrizione dell''attività";
-$TemplateTitleFAQ="Domande frequenti";
-$TemplateTitleGlossary="Glossario";
-$TemplateTitleCertificateDescription="Attestato di fine corso";
-$TermYourProfileIsNotCompleted="Per abilitare la convalida dell''accordo legale devi competare il tuo profilo.";
-$TicketEnrollment="Iscrizione";
-$UserXHasBeenAssignedToBoss="L''allievo %s ti è stato assegnato";
-$UserXHasBeenAssignedToBossWithUrlX="Sei stato assegnato come tutor per l''allievo %s.<br/>";
-$UserXHasFilledTheDiagnosis="L''utente %s ha completato la diagnosi";
-$UserXHasFilledTheDiagnosisDescription="L''utente %s ha completato la diagnosi sulla piattaforma e attende una tua revisione.";
-$UserXSignedTheAgreement="L''utente %s ha firmato l''accordo legale.";
-$UserXSignedTheAgreementTheY="L''utente %s ha firmato l''accordo legale il %s.";
-$UseThisBadge="Usa questo simbolo";
-$VideoConference="Videoconferenza";
-$WebRTCDialogHelp="Per attivare la videochat sul tuo browser (se è supportata), assicurati di cliccare sull''icona nella parte sinistra della barra degli indirizzi del browser, e quindi permetti l''uso della webcam e del microfono.";
-$YouNeedConfirmYourAccountViaEmailToAccessThePlatform="Per accedere alla piattaforma devi confermare via e-mail il tuo account";
-$YouNeedToConfirmYourAgreementCheckYourEmail="Per poter procedere devi confermare l''approvazione delle nostre condizioni di utilizzo. Controlla il tuo indirizzo e-mail.";
-$YourChoice="La tua scelta";
-$YourPasswordCannotBeTheSameAsYourEmail="La tua password deve essere diversa dal tuo indirizzo e-mail";
-$YourSessionTimeHasExpired="Sei già registrato ma il tuo periodo di accesso al corso è scaduto.";
-$YourSessionTimeIsExpired="La sessione è scaduta.";
-$YouWillReceivedASecondEmail="Riceverai una nuova mail con la tua password.";
-?>
+?>

+ 10 - 95
main/lang/polish/trad4all.inc.php

@@ -420,7 +420,12 @@ $ThisItemIsInvisibleForStudentsButYouHaveAccessAsTeacher = "Ten element jest nie
 $EnableIframeInclusionComment = "Zezwalając na użycie ramek Iframe wewnątrz edytora HTML ulepszysz możliwości edycji dla użytkowników, ale wiąże się to z pewnym ryzykiem. Upewnij się, że możesz zaufać swoim użytkownikom (np. Jeśli wiesz kim są) przed włączeniem tego rozszerzenia.";
 $AddedToLPCannotBeAccessed = "Ćwiczenie zostało włączone do ścieżki nauki, nie może być dostępne bezpośrednio stąd. Jeśli chcesz udostępnić to samo ćwiczenie poprzez narzędzie ćwiczeń, należy zrobić kopię obecnego zadania przy użyciu ikony kopiowania.";
 $EnableIframeInclusionTitle = "Zezwól na użycie ramek Iframe w edytorze HTML";
-$MailTemplateRegistrationMessage = "Szanowny/a ((firstname)) ((lastname)),\ n\nJesteś zarejestrowany na ((sitename)) z następującymi ustawieniami:\n\nNazwa użytkownika: ((username))\nHasło: ((password))\n\nAdres strony ((sitename)) to:. ((url))\n\nln W przypadku jakichkolwiek problemów, prosimy o kontakt.\n\nAdministrator\n((admin_name)) ((admin_surname)).";
+$MailTemplateRegistrationMessage = "Szanowny/a ((firstname)) ((lastname)),\n\n
+Jesteś zarejestrowany na ((sitename)) z następującymi ustawieniami:\n\n
+Nazwa użytkownika: ((username))\nHasło: ((password))\n\n
+Adres strony ((sitename)) to:. ((url))\n\n
+ln W przypadku jakichkolwiek problemów, prosimy o kontakt.\n\n
+Administrator\n((admin_name)) ((admin_surname)).";
 $Explanation = "Kliknięcie OK spowoduje utworzenie stron kursu z Forum, Terminarzem, Obszarem dokumentów itd. Tylko Ty, jako twórca kursu możesz te strony modyfikować";
 $CodeTaken = "Kod kursu jest już podany.
 Użyj przycisku Wstecz i spróbuj jeszcze raz";
@@ -3453,7 +3458,7 @@ $Preserved = "Chroniony";
 $ConfirmUnsubscribe = "Potwierdź usunięcie użytkownika";
 $See = "Idź do";
 $LastVisits = "Moje ostatnie logowania";
-$IfYouWantToAddManyUsers = "Jeśli chcesz dodać listę użytkowników do szkolenia \t\t\, skontaktuj się z administratorem.";
+$IfYouWantToAddManyUsers = "Jeśli chcesz dodać listę użytkowników do szkolenia, skontaktuj się z administratorem.";
 $PassTooEasy = "to hasło jest zbyt proste. Zobacz przykład poniżej";
 $AddedToCourse = "jest już zarejestrowany w kursie";
 $UserAlreadyRegistered = "Użytkownik o tej nazwie jest już zarejestrowany w tym kursie.";
@@ -5689,7 +5694,8 @@ $OnlyAccessFromYourGroup = "Dostępne tylko z grupy";
 $CreateAssignmentPage = "To utworzy specjalną stronę wiki, na której nauczyciel może opisać zadanie. Zostanie ona automatycznie połączona ze stronami Wiki, gdzie uczniowie wykonują zadanie. Zarówno strony Trenera jak i studentów są tworzone automatycznie. W tych zadaniach, studenci mogą tylko edytować i przeglądać swoje strony. Można jednak to zmienić, jeśli będzie taka potrzeba.";
 $UserFolders = "Foldery użytkowników";
 $UserFolder = "Katalog użytkownika";
-$HelpUsersFolder = "INFORMACJE WIDOCZNE tylko dla nauczyciela: \ nFolder użytkowników zawiera folder każdego użytkownika, który ma dostęp do niego przez narzędzie dokumentów, lub gdy jakiś plik został przesłany w kursie za pośrednictwem internetowego edytora. Jeśli nie doszło do żadnych okoliczności, to nie powstał żaden folder użytkownika. W przypadku grup, pliki, które są wysyłane za pośrednictwem edytora zostaną dodane w folderze każdej grupy, który jest dostępny tylko dla studentów z tej grupy.
+$HelpUsersFolder = "INFORMACJE WIDOCZNE tylko dla nauczyciela:\n
+Folder użytkowników zawiera folder każdego użytkownika, który ma dostęp do niego przez narzędzie dokumentów, lub gdy jakiś plik został przesłany w kursie za pośrednictwem internetowego edytora. Jeśli nie doszło do żadnych okoliczności, to nie powstał żaden folder użytkownika. W przypadku grup, pliki, które są wysyłane za pośrednictwem edytora zostaną dodane w folderze każdej grupy, który jest dostępny tylko dla studentów z tej grupy.
 
 Folder użytkowników i każdy z zawartych w nim folderów będą domyślnie ukryte dla wszystkich studentów, ale każdy student może zobaczyć zawartość jego/jej katalogu poprzez internetowy edytor. Jeśli jednak student zna adres pliku lub folderu innego studenta, może uzyskać do niego dostęp.
 
@@ -6684,95 +6690,4 @@ $DataTableSearch = "Szukaj";
 $HideColumn = "Ukryj kolumnę";
 $DisplayColumn = "Pokaż kolumnę";
 $LegalAgreementAccepted = "Regulamin zaakceptowany";
-$AdditionallyYouHaveObtainedTheFollowingSkills="Dodatkowo zdobyłeś następujące umiejętności";
-$AssignmentLinkstoStudentsPage="Dostęp do materiałów przygotowanych przez uczniów";
-$AssignCoach="Przydziel trenera";
-$AssignSkill="Przydziel umiejętność";
-$AssignedTo="Przydzielony do";
-$AssignUser="Przydzielony użytkownik";
-$Assign="Przydziel";
-$AssignedTo="Przydzielony do";
-$AssignSkill="Przydziel umiejętność";
-$CalendarStartDate="Data rozpoczęcia";
-$Contacts="Kontakty";
-$ContactsList="Lista kontaktów";
-$CurrentPasswordEmptyOrIncorrect="Aktualne hasło jest niepoprawne";
-$CurrentPassword="Aktualne hasło";
-$DearXComma="Drogi %=";
-$DoubleValidationMessage="Potwierd= czy naprawdę chcesz zarejestrować się do platformy";
-$FilesUpload="dokumenty";
-$FollowedStudentBosses="Nauczyciel";
-$FromDateXToDateY="Od %s do %s";
-$LastConnection="Ostatnie połączenie";
-$LegalAccepted="Prawnie zaakceptowany";
-$Map="Mapa";
-$MyGeneralCertificate="Certyfikat końcowy";
-$MyLocation="Moja lokalizacja";
-$NewPasswordRequirementsNotMatched="Nowe hasło nie spełnia podstawowych wymogów zabezpieczeń";
-$OralExpressionHelpText="Możesz przerwać nagrywanie w dowolnym momencie. Jeśli nie jesteś zadowolon= nagraj się ponownie. Poprzednia wersja zostanie nadpisana. Jesteś zadowolony? Aby przesłać nagranie kliknij \"Zapisz nagranie\".";
-$PasswordVeryWeak="Bardzo słabe";
-$PauseRecordingAudio="Zatrzymaj nagrywanie";
-$PersonalEmail="Adres e-mail";
-$PlayRecordingAudio="Wznów nagrywanie";
-$PriorityNormal="Normalny";
-$PriorityHigh="Wysoki";
-$PriorityLow="Niski";
-$Priority="Priorytet";
-$PriorityHigh="Wysoki";
-$PriorityLow="Niski";
-$PriorityNormal="Normalny";
-$ProfileIsNotCompleted="Aby kontynuować uzupełnij swój profil";
-$ReadingComprehension="Rozumienie tekstu czytanego";
-$ReadingComprehensionLevelX="%s słów na minutę";
-$ReadingComprehensionLevelX="%s słów na minutę";
-$ReadingQuestionCongratsSpeedXNotReachedForYWords="Niestet= wygląda na t= że prędkość %s słów/minutę była zbyt szybka dla tekstu o długości %s słów.";
-$ReadingQuestionCongratsSpeedXReachedForYWords="Gratulacj= osiągnąłeś prędkość %s słów na minutę i poprawnie zrozumiałeś tekst o całkowitej długości %s słów.";
-$RecordAudio="Nagrywanie";
-$RegistrationConfirmation="Potwierdzenie rejestracji";
-$RegistrationConfirmationEmailMessage="Aby ukończyć rejestrację na platformie musisz potwierdzić swoje konto klikając w następujący link";
-$RegistrationConfirmationEmailMessage="Aby ukończyć rejestrację na platformie musisz potwierdzić swoje konto klikając w następujący link";
-$RegistrationRoleFollowCourses="Zapisz się na kursy";
-$RegistrationRoleTeachCourses="Poprowadź kursy";
-$RegistrationRoleWhatDoYouWantToDo="Co chcesz zrobić?";
-$RemainingXAttempts="Pozostało %d prób";
-$ReSendConfirmationMail="Ponownie wyślij potwierdzenie";
-$SaveRecordedAudio="Zapisz nagranie";
-$ScoreNote="Notatki";
-$ScoreTest="Test";
-$SelectWeeksSpan="Wybierz tygodniowy przedział czasowy";
-$SendLegal="Wyślij umowę";
-$SendLegalDescriptionToUrlX="Zaakceptuj warunki prawne tutaj: %s";
-$SendLegalDescriptionToUrlX="Zaakceptuj warunki prawne tutaj: %s";
-$SendTermsDescriptionToUrlX="Cześ=<br/> Twój nauczyciel przesłał Ci regulamin. Możesz podpisać je tutaj URL:%s";
-$SendTermsSubject="Regulamin został już podpisany";
-$ShortName="Nazwa użytkownika";
-$SrcEmail="Adres e-mail";
-$SrcPhone="Telefon";
-$StartRecordingAudio="Rozpocznij nagrywanie";
-$StudentCourseProgressX="Postęp: %s%%";
-$StudentCourseScoreX="Wynik: %s%%";
-$StudentHadEnoughSkills="Uczeń nabył wiele dodatkowych umiejętnośc= które pozwalają ocenić znajomość języka ojczystego.";
-$StudentXIsNotSubscribedToCourse="Uczeń %s nie jest zapisany na ten kurs";
-$TemplateTitleAssigment="Opis zadania";
-$TemplateTitleFAQ="Często zadawane pytania";
-$TemplateTitleGlossary="Słowniczek";
-$TemplateTitleCertificateDescription="Pojawi się na zakończenie kursu";
-$TermYourProfileIsNotCompleted="Najpierw uzupełnij swój profi= aby móc potwierdzić regulamin.";
-$TicketEnrollment="Zapisy";
-$UserXHasBeenAssignedToBoss="Przydzielono Ci ucznia %s";
-$UserXHasBeenAssignedToBossWithUrlX="Zostałeś przydzielony jako nauczyciel uczniowi %s. %s <br/>";
-$UserXHasFilledTheDiagnosis="Użytkownik %s uzupełnił diagnozę";
-$UserXHasFilledTheDiagnosisDescription="Użytkownik %s uzupełnił diagnozę na platformie i jest ona gotowa do sprawdzenia";
-$UserXSignedTheAgreement="Użytkownik %s podpisał umowę.";
-$UserXSignedTheAgreementTheY="Użytkownik podpisał umowę z %s";
-$UseThisBadge="Użyj odznaki";
-$VideoConference="Wideokonferencja";
-$WebRTCDialogHelp="Aby włączyć wideo czat w przeglądarce (jeśli go wspiera= upewnij si= że klikasz w ikonę informacji po lewej stronie od adresu UR= a następnie zaakceptuj korzystanie z kamery internetowej oraz mikrofonu.";
-$YouNeedConfirmYourAccountViaEmailToAccessThePlatform="Musisz potwierdzić swoje konto poprzez adres e-mai= aby otrzymać dostęp do platformy";
-$YouNeedToConfirmYourAgreementCheckYourEmail="W pierwszej kolejności musisz potwierdzi= iż zaakceptowałeś nasz regulamin. Sprawdź swoją skrzynkę mailową.";
-$YourChoice="Twój wybór";
-$YourPasswordCannotBeTheSameAsYourEmail="Twoje hasło nie może być takie samo jak adres e-mail";
-$YourSessionTimeHasExpired="Jesteś już zarejestrowan= ale Twój dostęp wygasł.";
-$YourSessionTimeIsExpired="Twoja sesja wygasła";
-$YouWillReceivedASecondEmail="Otrzymasz wiadomość e-mail z Twoim hasłem";
-?>
+?>

+ 3 - 1
main/lang/romanian/trad4all.inc.php

@@ -23,7 +23,9 @@ $AssignUsersToBoss = "Atribuirea utilizatorilor la superior";
 $RoleStudentBoss = "Superior de elev(i)";
 $CosecantCsc = "Cosecant:\t\t\t\tcsc(x)";
 $HyperbolicCosecantCsch = "Cosecant hiperbolic:\t\tcsch(x)";
-$HelpCookieUsageValidation = "Pentru buna funcționare a acestui site și măsurare utilizarii sale, această platformă foloseste cookie-uri.<br /><br />\nDacă consideră necesar, secțiunea de ajutor a browser-ului dumneavoastră vă va spune despre prcedimientos pentru a seta cookie-uri.<br /><br />\ nPentru mai multe informații cu privire la cookie-uri, puteți vizita site-ul <a href=\"http://www.aboutcookies.org/\">Despre cookie-urile</a> (în limba engleză) sau echivalent  in spaniolă.";
+$HelpCookieUsageValidation = "Pentru buna funcționare a acestui site și măsurare utilizarii sale, această platformă foloseste cookie-uri.<br /><br />\n
+Dacă consideră necesar, secțiunea de ajutor a browser-ului dumneavoastră vă va spune despre prcedimientos pentru a seta cookie-uri.<br /><br />\n
+Pentru mai multe informații cu privire la cookie-uri, puteți vizita site-ul <a href=\"http://www.aboutcookies.org/\">Despre cookie-urile</a> (în limba engleză) sau echivalent in spaniolă.";
 $YouAcceptCookies = "Prin utilizarea acestui site, acceptă utilizarea cookie-urilor.";
 $TemplateCertificateComment = "Exemplu de certificat";
 $TemplateCertificateTitle = " Certificat";

+ 2 - 1
main/lang/spanish/trad4all.inc.php

@@ -6104,7 +6104,8 @@ $CourseRequestLegalNote = "La información de esta solicitud de formación es co
 $EnableCourseValidation = "Solicitud de cursos";
 $EnableCourseValidationComment = "Cuando la solicitud de cursos está activada, un profesor no podrá crear un curso por si mismo sino que tendrá que rellenar una solicitud. El administrador de la plataforma revisará la solicitud y la aprobará o rechazará. Esta funcionalidad se basa en mensajes de correo electrónico automáticos por lo que debe asegurarse de que su instalación de Chamilo usa un servidor de correo y una dirección de correo dedicada a ello.";
 $CourseRequestAskInfoEmailSubject = "%s Solicitud de informacion %s";
-$CourseRequestAskInfoEmailText = "Hemos recibido su solicitud para la creación de un curso con el código% s. Antes de considerar su aprobación necesitamos alguna información adicional. \ N \ nPor favor, realice una breve descripción del contenido del curso, los objetivos y los estudiantes u otro tipo de usuarios que vayan a participar. Si es su caso, mencione el nombre de la institución u órgano en nombre de la cual Usted ha hecho la solicitud.";
+$CourseRequestAskInfoEmailText = "Hemos recibido su solicitud para la creación de un curso con el código %s. Antes de considerar su aprobación necesitamos alguna información adicional.\n\n
+Por favor, realice una breve descripción del contenido del curso, los objetivos y los estudiantes u otro tipo de usuarios que vayan a participar. Si es su caso, mencione el nombre de la institución u órgano en nombre de la cual Usted ha hecho la solicitud.";
 $CourseRequestAcceptedEmailSubject = "%s La petición del curso %s ha sido aprobada";
 $CourseRequestAcceptedEmailText = "Su solicitud del curso %s ha sido aprobada. Un nuevo curso %s ha sido creado y Usted ha quedado inscrito en él como profesor.\n\nPodrá acceder al curso creado desde: %s";
 $CourseRequestRejectedEmailSubject = "%s La solicitud del curso %s ha sido rechazada";

+ 1 - 1
main/lang/tagalog/trad4all.inc.php

@@ -1340,7 +1340,7 @@ $ExamPassX = "Pasado sa minimum na %s";
 $ExamFail = "Bagsak";
 $ExamTracking = "Pagsusubaybay sa pagsusulit";
 $EnableCourseValidation = "Balidasyon ng mga kurso";
-$EnableCourseValidationComment = "Kapag ang tampok na \Balidasyon ng kurso\" ay pinagana, ang isang guro ay hindi maaaring makapaglikha ng isang kurso nang nag-iisa. Siya ay dapat magsulat ng isang kahilingan sa kurso. Ang tagapangasiwa ng platform ay niriripaso ang kahilingan at aaprubahan ito o tatanggihan.<br />Ang tampok na ito ay umaasa sa 'automated e-mail messaing'; i-set ang Chamilo upang mag-access sa isang server ng email at gumamit ng isang nakatalagang e-mail account.";
+$EnableCourseValidationComment = "Kapag ang tampok na 'Balidasyon ng kurso' ay pinagana, ang isang guro ay hindi maaaring makapaglikha ng isang kurso nang nag-iisa. Siya ay dapat magsulat ng isang kahilingan sa kurso. Ang tagapangasiwa ng platform ay niriripaso ang kahilingan at aaprubahan ito o tatanggihan.<br />Ang tampok na ito ay umaasa sa 'automated e-mail messaing'; i-set ang Chamilo upang mag-access sa isang server ng email at gumamit ng isang nakatalagang e-mail account.";
 $CourseValidationTermsAndConditionsLink = "Balidasyon ng kurso - isang link sa mga takda at mga kondisyon";
 $CourseValidationTermsAndConditionsLinkComment = "Ito ang URL sa \"Mga Takda at Mga Kondisyon\" na dokumento na balido sa pagagawa ng kahilingan sa kurso. Kung ang address ay naitakda rito, ang gumagamit ay dapat basahin at sumang-ayon sa mga takda at mga kondisyon bago ipadala ang isang kahilingan sa kurso.<br />Kung iyong pagganahin ang module ng \"Mga Takda at Mga Kondisyon\" at kung nais mong gamitin ang URL nito, hayaang walang laman ang setting na ito.";
 $EnabledSVGTitle = "Lumikha at mag-edit ng mga SVG file";

+ 9 - 1
tests/behat/features/bootstrap/FeatureContext.php

@@ -358,10 +358,18 @@ class FeatureContext extends MinkContext
      */
     public function waitForThePageToBeLoaded()
     {
-        //$this->getSession()->wait(10000, "document.readyState === 'complete'");
         $this->getSession()->wait(3000);
     }
 
+    /**
+     * @When /^wait very long for the page to be loaded$/
+     */
+    public function waitVeryLongForThePageToBeLoaded()
+    {
+        //$this->getSession()->wait(10000, "document.readyState === 'complete'");
+        $this->getSession()->wait(6000);
+    }
+
     /**
      * @When /^I check the "([^"]*)" radio button$/
      */

+ 2 - 2
tests/behat/features/toolExercise.feature

@@ -384,7 +384,7 @@ Feature: Exercise tool
       | none          | 80 / 60        | 133.33%        |
       | Total         | 190 / 190      | 100%           |
 
-  Scenario: Teacher see exercise results by categories
+  Scenario: Teacher looks at exercise results by categories
     Given I am on "/user_portal.php"
     And I am on course "TEMP" homepage in session "Session Exercise"
     Then I should see "TEMP (Session Exercise)"
@@ -392,7 +392,7 @@ Feature: Exercise tool
     And I follow "Exercise for Behat test"
     And I follow "Results and feedback"
     Then I should see "Learner score"
-    And wait for the page to be loaded
+    And wait very long for the page to be loaded
     And I follow "Grade activity"
     Then I should see "Score for the test: 190 / 190"
     And I should see the table "#category_results":

+ 63 - 40
tests/scripts/lang/generate_gettext_files.php

@@ -34,13 +34,15 @@ foreach ($languagesListFull as $language) {
  * Get English language terms (the main source of terms)
  */
 $path = $langPath.'english';
-$terms = [];
+$terms = $originalTerms = [];
 $file = $path.'/trad4all.inc.php';
 if (is_file($file)) {
-    $terms = SubLanguageManager::get_all_language_variable_in_file($file, true);
+    $originalTerms = SubLanguageManager::get_all_language_variable_in_file($file, true);
 }
-foreach ($terms as $index => $translation) {
-    $terms[$index] = trim(rtrim($translation, ';'), '"');
+foreach ($originalTerms as $index => $translation) {
+    if (!isset($terms[$index])) {
+        $terms[$index] = trim(rtrim($translation, ';'), '"');
+    }
 }
 // get only the array keys (the language variables defined in language files)
 //$definedTerms = array_flip(array_keys($terms));
@@ -48,43 +50,43 @@ echo count($terms)." terms were found in language files".PHP_EOL;
 
 // make sure we have an ISO 639-1 (or-2 if no -1) to give the gettext file
 $langToIso639v1 = [
-    'arabic'  => 'ar_AR',
+    'arabic'  => 'ar',
     'asturian' => 'ast_ES',
     'basque'  => 'eu_ES',
     'bengali' => 'bn_BD',
     'bosnian' => 'bs_BA',
     'brazilian' => 'pt_BR',
     'bulgarian' => 'bg_BG',
-    'catalan' => 'ca_ES',
+    'catalan' => 'ca',
     'croatian' => 'hr_HR',
     'czech'   => 'cs_CZ',
-    'danish'  => 'da_DK',
-    'dari'    => 'prs_AF',
-    'dutch'   => 'nl_NL',
+    'danish'  => 'da',
+    'dari'    => 'fa_AF',
+    'dutch'   => 'nl',
     'english' => 'en_US',
     'esperanto' => 'eo',
     'faroese' => 'fo_FO',
     'finnish' => 'fi_FI',
     'french'  => 'fr_FR',
-    'friulian' => 'fur_IT',
-    'galician' => 'gl_ES',
+    'friulian' => 'fur',
+    'galician' => 'gl',
     'georgian' => 'ka_GE',
-    'german'  => 'de_DE',
-    'greek'   => 'el_GR',
+    'german'  => 'de',
+    'greek'   => 'el',
     'hebrew'  => 'he_IL',
-    'hindi'   => 'hi_IN',
+    'hindi'   => 'hi',
     'hungarian' => 'hu_HU',
     'indonesian' => 'id_ID',
-    'italian' => 'it_IT',
-    'japanese' => 'ja_JP',
+    'italian' => 'it',
+    'japanese' => 'ja',
     'korean'  => 'ko_KR',
     'latvian' => 'lv_LV',
     'lithuanian' => 'lt_LT',
     'macedonian' => 'mk_MK',
     'malay' => 'ms_MY',
     'norwegian' => 'nn_NO',
-    'occitan' => 'oc_FR',
-    'pashto' => 'ps_AF',
+    'occitan' => 'oc',
+    'pashto' => 'ps',
     'persian' => 'fa_IR',
     'polish' => 'pl_PL',
     'portuguese' => 'pt_PT',
@@ -96,15 +98,15 @@ $langToIso639v1 = [
     'slovak' => 'sk_SK',
     'slovenian' => 'sl_SI',
     'somali' => 'so_SO',
-    'spanish' => 'es_ES',
+    'spanish' => 'es',
     'spanish_latin' => 'es_MX',
     'swahili' => 'sw_KE',
     'swedish' => 'sv_SE',
     'tagalog' => 'tl_PH',
-    'thai' => 'th_TH',
+    'thai' => 'th',
     'tibetan' => 'bo_CN',
     'trad_chinese' => 'zh_TW',
-    'turkish' => 'tr_TR',
+    'turkish' => 'tr',
     'ukrainian' => 'uk_UA',
     'vietnamese' => 'vi_VN',
     'xhosa' => 'xh_ZA',
@@ -122,20 +124,20 @@ $langToPOFilename = [
     'croatian' => 'hr',
     'czech'   => 'cs',
     'danish'  => 'da',
-    'dari'    => 'prs_AF',
+    'dari'    => 'fa_AF',
     'dutch'   => 'nl',
     'english' => 'en',
     'esperanto' => 'eo',
-    'faroese' => 'fo_FO',
+    'faroese' => 'fo',
     'finnish' => 'fi',
     'french'  => 'fr',
     'friulian' => 'fur_IT',
     'galician' => 'gl_ES',
-    'georgian' => 'ka_GE',
+    'georgian' => 'ka',
     'german'  => 'de',
     'greek'   => 'el',
     'hebrew'  => 'he',
-    'hindi'   => 'hi_IN',
+    'hindi'   => 'hi',
     'hungarian' => 'hu',
     'indonesian' => 'id',
     'italian' => 'it',
@@ -144,34 +146,34 @@ $langToPOFilename = [
     'latvian' => 'lv',
     'lithuanian' => 'lt',
     'macedonian' => 'mk',
-    'malay' => 'ms_MY',
+    'malay' => 'ms',
     'norwegian' => 'nn',
     'occitan' => 'oc_FR',
-    'pashto' => 'ps_AF',
-    'persian' => 'fa_IR',
+    'pashto' => 'ps',
+    'persian' => 'fa',
     'polish' => 'pl',
     'portuguese' => 'pt',
-    'quechua_cusco' => 'quz_PE',
+    'quechua_cusco' => 'qu',
     'romanian' => 'ro',
     'russian' => 'ru',
-    'serbian' => 'sr_RS',
+    'serbian' => 'sr',
     'simpl_chinese' => 'zh_CN',
     'slovak' => 'sk',
     'slovenian' => 'sl',
     'somali' => 'so',
     'spanish' => 'es',
     'spanish_latin' => 'es_MX',
-    'swahili' => 'sw_KE',
+    'swahili' => 'sw',
     'swedish' => 'sv',
-    'tagalog' => 'tl_PH',
+    'tagalog' => 'tl',
     'thai' => 'th',
-    'tibetan' => 'bo_CN',
+    'tibetan' => 'bo',
     'trad_chinese' => 'zh_TW',
     'turkish' => 'tr',
-    'ukrainian' => 'uk_UA',
+    'ukrainian' => 'uk',
     'vietnamese' => 'vi',
-    'xhosa' => 'xh_ZA',
-    'yoruba' => 'yo_NG',
+    'xhosa' => 'xh',
+    'yoruba' => 'yo',
 ];
 
 /**
@@ -190,7 +192,7 @@ $destinationDir .= '/';
 $destinationFilePot = $destinationDir.'/'.$baseFilename.'/'.$baseFilename.'.pot';
 
 foreach ($languagesList as $language) {
-    $termsInLanguage = [];
+    $termsInLanguage = $originalTermsInLanguage = [];
     $file = $langPath.$language.'/trad4all.inc.php';
     $languageCode = $langToIso639v1[$language];
     $languageFilename = $langToPOFilename[$language];
@@ -202,17 +204,24 @@ foreach ($languagesList as $language) {
         '"Content-Transfer-Encoding: 8bit\n"'."\n\n";
     file_put_contents($destinationFile, $header);
 
-    $termsInLanguage = SubLanguageManager::get_all_language_variable_in_file(
+    $originalTermsInLanguage = SubLanguageManager::get_all_language_variable_in_file(
         $file,
         true
     );
-    foreach ($termsInLanguage as $id => $content) {
-        $termsInLanguage[$id] = trim(rtrim($content, ';'), '"');
+    foreach ($originalTermsInLanguage as $id => $content) {
+        if (!isset($termsInLanguage[$id])) {
+            $termsInLanguage[$id] = trim(rtrim($content, ';'), '"');
+        }
     }
 
     $bigString = '';
     $bigStringPot = '';
+    $doneTranslations = [];
     foreach ($terms as $term => $englishTranslation) {
+        if (isset($doneTranslations[$englishTranslation])) {
+            continue;
+        }
+        $doneTranslations[$englishTranslation] = true;
         $translatedTerm = '';
         if (!empty($termsInLanguage[$term])) {
             $translatedTerm = $termsInLanguage[$term];
@@ -222,6 +231,20 @@ foreach ($languagesList as $language) {
                 continue;
             }
         }
+        // Here we apply a little correction to avoid unterminated strings
+        // when a string ends with a \"
+        if (preg_match('/\\\$/', $englishTranslation)) {
+            $englishTranslation .= '"';
+        }
+        $englishTranslation2 = '';
+        $search = ['\\{', '\\}', '\\(', '\\)', '\\;'];
+        $replace = ['\\\\{', '\\\\}', '\\\\(', '\\\\)', '\\\\;'];
+        $englishTranslation = str_replace($search, $replace, $englishTranslation);
+        if (preg_match('/\\\$/', $translatedTerm)) {
+            $translatedTerm .= '"';
+        }
+        $translatedTerm = str_replace($search, $replace, $translatedTerm);
+        // Now build the line
         $bigString .= 'msgid "'.$englishTranslation.'"'."\n".'msgstr "'.$translatedTerm.'"'."\n\n";
         if ($language === 'english') {
             //$bigStringPot .= 'msgid "'.$term.'"'."\n".'msgstr ""'."\n\n";

Vissa filer visades inte eftersom för många filer har ändrats