Merge branch 'MDL-68271-master' of git://github.com/sarjona/moodle
authorAndrew Nicols <andrew@nicols.co.uk>
Mon, 11 May 2020 01:10:40 +0000 (09:10 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Mon, 11 May 2020 01:10:40 +0000 (09:10 +0800)
h5p/classes/core.php
h5p/classes/editor_ajax.php
h5p/classes/editor_framework.php
h5p/classes/helper.php
h5p/tests/editor_ajax_test.php
h5p/tests/editor_framework_test.php
h5p/tests/generator/lib.php
lang/en/cache.php
lib/db/caches.php

index e76d6b2..4fb007b 100644 (file)
@@ -377,4 +377,19 @@ class core extends \H5PCore {
     public static function validToken($action, $token) {
         return confirm_sesskey($token);
     }
+
+    /**
+     * Get the library string from a DB library record.
+     *
+     * @param  stdClass $record The DB library record.
+     * @param  bool $foldername If true, use hyphen instead of space in returned string.
+     * @return string The string name on the form {machineName} {majorVersion}.{minorVersion}.
+     */
+    public static function record_to_string(stdClass $record, bool $foldername = false): string {
+        return static::libraryToString([
+            'machineName' => $record->machinename,
+            'majorVersion' => $record->majorversion,
+            'minorVersion' => $record->minorversion,
+        ], $foldername);
+    }
 }
index dc1291b..e1090eb 100644 (file)
@@ -25,6 +25,7 @@
 namespace core_h5p;
 
 use H5PEditorAjaxInterface;
+use core\dml\table as dml_table;
 
 /**
  * Moodle's implementation of the H5P Editor Ajax interface.
@@ -110,7 +111,95 @@ class editor_ajax implements H5PEditorAjaxInterface {
      * @return array Translations in $languagecode available for libraries $libraries
      */
     public function getTranslations($libraries, $languagecode): array {
-        // To be implemented when translations are introduced.
-        return [];
+        $translations = [];
+        $langcache = \cache::make('core', 'h5p_content_type_translations');
+
+        $missing = [];
+        foreach ($libraries as $libstring) {
+            // Check if this library has been saved previously into the cache.
+            $librarykey = helper::get_cache_librarykey($libstring);
+            $cachekey = "{$librarykey}/{$languagecode}";
+            $libtranslation = $langcache->get($cachekey);
+            if ($libtranslation) {
+                // The library has this language stored into the cache.
+                $translations[$libstring] = $libtranslation;
+            } else {
+                // This language for the library hasn't been stored previously into the cache, so we need to get it from DB.
+                $missing[] = $libstring;
+            }
+        }
+
+        // Get all language files for libraries which aren't stored into the cache and merge them with the cache ones.
+        return array_merge(
+            $translations,
+            $this->get_missing_translations($missing, $languagecode)
+        );
+    }
+
+    /**
+     * Get translation for $language for libraries in $missing.
+     *
+     * @param  array  $missing  An array of libraries, in the form "<machineName> <majorVersion>.<minorVersion>
+     * @param  string $language Language code
+     * @return array  Translations in $language available for libraries $missing
+     */
+    protected function get_missing_translations(array $missing, string $language): array {
+        global $DB;
+
+        if (empty($missing)) {
+            return [];
+        }
+
+        $wheres = [];
+        $params = [
+            file_storage::COMPONENT,
+            file_storage::LIBRARY_FILEAREA,
+        ];
+        $sqllike = $DB->sql_like('f.filepath', '?');
+        $params[] = '%language%';
+
+        foreach ($missing as $library) {
+            $librarydata = core::libraryFromString($library);
+            $wheres[] = '(h.machinename = ? AND h.majorversion = ? AND h.minorversion = ?)';
+            $params[] = $librarydata['machineName'];
+            $params[] = $librarydata['majorVersion'];
+            $params[] = $librarydata['minorVersion'];
+        }
+        $params[] = "{$language}.json";
+        $wheresql = implode(' OR ', $wheres);
+
+        $filestable = new dml_table('files', 'f', 'f_');
+        $filestableselect = $filestable->get_field_select();
+
+        $libtable = new dml_table('h5p_libraries', 'h', 'h_');
+        $libtableselect = $libtable->get_field_select();
+
+        $sql = "SELECT {$filestableselect}, {$libtableselect}
+                  FROM {h5p_libraries} h
+             LEFT JOIN {files} f
+                    ON h.id = f.itemid AND f.component = ?
+                   AND f.filearea = ? AND $sqllike
+                 WHERE ($wheresql) AND f.filename = ?";
+
+        // Get the content of all these language files and put them into the translations array.
+        $langcache = \cache::make('core', 'h5p_content_type_translations');
+        $fs = get_file_storage();
+        $translations = [];
+        $results = $DB->get_recordset_sql($sql, $params);
+        $toset = [];
+        foreach ($results as $result) {
+            $file = $fs->get_file_instance($filestable->extract_from_result($result));
+            $library = $libtable->extract_from_result($result);
+            $libstring = core::record_to_string($library);
+            $librarykey = helper::get_cache_librarykey($libstring);
+            $translations[$libstring] = $file->get_content();
+            $cachekey = "{$librarykey}/{$language}";
+            $toset[$cachekey] = $translations[$libstring];
+        }
+        $langcache->set_many($toset);
+
+        $results->close();
+
+        return $translations;
     }
 }
index c3eb18c..bac7950 100644 (file)
@@ -51,8 +51,54 @@ class editor_framework implements H5peditorStorage {
      * @return string|boolean Translation in JSON format if available, false otherwise
      */
     public function getLanguage($name, $major, $minor, $lang) {
-        // To be implemented when translations are introduced.
-        return false;
+        global $DB;
+
+        // Check if this information has been saved previously into the cache.
+        $langcache = \cache::make('core', 'h5p_content_type_translations');
+        $library = new stdClass();
+        $library->machinename = $name;
+        $library->majorversion = $major;
+        $library->minorversion = $minor;
+        $librarykey = helper::get_cache_librarykey(core::record_to_string($library));
+        $cachekey = "{$librarykey}/{$lang}";
+        $translation = $langcache->get($cachekey);
+        if ($translation) {
+            return $translation;
+        }
+
+        // Get the language file for this library.
+        $params = [
+            file_storage::COMPONENT,
+            file_storage::LIBRARY_FILEAREA,
+        ];
+        $sqllike = $DB->sql_like('f.filepath', '?');
+        $params[] = '%language%';
+
+        $sql = "SELECT hl.id, f.pathnamehash
+                  FROM {h5p_libraries} hl
+             LEFT JOIN {files} f
+                    ON hl.id = f.itemid AND f.component = ? AND f.filearea = ? AND $sqllike
+                 WHERE ((hl.machinename = ? AND hl.majorversion = ? AND hl.minorversion = ?)
+                   AND f.filename = ?)
+              ORDER BY hl.patchversion DESC";
+        $params[] = $name;
+        $params[] = $major;
+        $params[] = $minor;
+        $params[] = $lang.'.json';
+
+        $result = $DB->get_record_sql($sql, $params);
+
+        if (!empty($result)) {
+            // If the JS language file exists, its content should be returned.
+            $fs = get_file_storage();
+            $file = $fs->get_file_by_hash($result->pathnamehash);
+            $translation = $file->get_content();
+        }
+
+        // Save translation into the cache (even if there is no translation for this language).
+        $langcache->set($cachekey, $translation);
+
+        return $translation;
     }
 
     /**
@@ -67,13 +113,77 @@ class editor_framework implements H5peditorStorage {
      * @return array List of possible language codes
      */
     public function getAvailableLanguages($machinename, $major, $minor): array {
+        global $DB;
+
+        // Check if this information has been saved previously into the cache.
+        $langcache = \cache::make('core', 'h5p_content_type_translations');
+        $library = new stdClass();
+        $library->machinename = $machinename;
+        $library->majorversion = $major;
+        $library->minorversion = $minor;
+        $librarykey = helper::get_cache_librarykey(core::record_to_string($library));
+        $languages = $langcache->get($librarykey);
+        if ($languages) {
+            // This contains a list of all of the available languages for the library.
+            return $languages;
+        }
+
+        // Get the language files for this library.
+        $params = [
+            file_storage::COMPONENT,
+            file_storage::LIBRARY_FILEAREA,
+        ];
+        $filepathsqllike = $DB->sql_like('f.filepath', '?');
+        $params[] = '%language%';
+        $filenamesqllike = $DB->sql_like('f.filename', '?');
+        $params[] = '%.json';
+
+        $sql = "SELECT DISTINCT f.filename
+                           FROM {h5p_libraries} hl
+                      LEFT JOIN {files} f
+                             ON hl.id = f.itemid AND f.component = ? AND f.filearea = ?
+                            AND $filepathsqllike AND $filenamesqllike
+                          WHERE hl.machinename = ? AND hl.majorversion = ? AND hl.minorversion = ?";
+        $params[] = $machinename;
+        $params[] = $major;
+        $params[] = $minor;
+
         $defaultcode = 'en';
-        $codes = [];
+        $languages = [];
+
+        $results = $DB->get_recordset_sql($sql, $params);
+        if ($results->valid()) {
+            // Extract the code language from the JS language files.
+            foreach ($results as $result) {
+                if (!empty($result->filename)) {
+                    $lang = substr($result->filename, 0, -5);
+                    $languages[$lang] = $languages;
+                }
+            }
+            $results->close();
+
+            // Semantics is 'en' by default. It has to be added always.
+            if (!array_key_exists($defaultcode, $languages)) {
+                $languages = array_keys($languages);
+                array_unshift($languages, $defaultcode);
+            }
+        } else {
+            $results->close();
+            $params = [
+                'machinename' => $machinename,
+                'majorversion' => $major,
+                'minorversion' => $minor,
+            ];
+            if ($DB->record_exists('h5p_libraries', $params)) {
+                // If the library exists (but it doesn't contain any language file), at least defaultcode should be returned.
+                $languages[] = $defaultcode;
+            }
+        }
 
-        // Semantics is 'en' by default.
-        array_unshift($codes, $defaultcode);
+        // Save available languages into the cache.
+        $langcache->set($librarykey, $languages);
 
-        return $codes;
+        return $languages;
     }
 
     /**
index f34236e..b2adca6 100644 (file)
@@ -399,4 +399,15 @@ class helper {
 
         return $settings;
     }
+
+    /**
+     * Prepare the library name to be used as a cache key (remove whitespaces and replace dots to underscores).
+     *
+     * @param  string $library Library name.
+     * @return string Library name in a cache simple key format (a-zA-Z0-9_).
+     */
+    public static function get_cache_librarykey(string $library): string {
+        // Remove whitespaces and replace '.' to '_'.
+        return str_replace('.', '_', str_replace(' ', '', $library));
+    }
 }
index 573289a..9ae0ae2 100644 (file)
@@ -96,4 +96,168 @@ class editor_ajax_testcase extends \advanced_testcase {
         $this->assertTrue($invalidaction);
         $this->assertFalse($invalidtoken);
     }
+
+    /**
+     * Test that the method getTranslations retrieves the translations of several libraries.
+     *
+     * @dataProvider  get_translations_provider
+     *
+     * @param  array  $datalibs      Libraries to create
+     * @param  string $lang          Language to get the translations
+     * @param  bool   $emptyexpected True if empty translations are expected; false otherwise
+     * @param  array  $altstringlibs When defined, libraries are no created and the content here is used to call the method
+     */
+    public function test_get_translations(array $datalibs, string $lang, bool $emptyexpected, ?array $altstringlibs = []): void {
+        $this->resetAfterTest();
+
+        // Fetch generator.
+        $generator = \testing_util::get_data_generator();
+        $h5pgenerator = $generator->get_plugin_generator('core_h5p');
+
+        $h5pfilestorage = new file_storage();
+        $h5ptempath = $h5pfilestorage->getTmpPath();
+
+        if (!empty($altstringlibs)) {
+            // Libraries won't be created and the getTranslation method will be called with this $altstringlibs.
+            $stringlibs = $altstringlibs;
+        } else {
+            $stringlibs = [];
+            foreach ($datalibs as $datalib) {
+                // Create DB entry for this library.
+                $tmplib = $h5pgenerator->create_library_record($datalib['machinename'], $datalib['title'], $datalib['majorversion'],
+                    $datalib['minorversion']);
+                // Create the files for this libray.
+                [$library, $files] = $h5pgenerator->create_library($h5ptempath, $tmplib->id, $datalib['machinename'],
+                    $datalib['majorversion'], $datalib['minorversion'], $datalib['translation']);
+                $h5pfilestorage->saveLibrary($library);
+                $stringlibs[] = \H5PCore::libraryToString($library);
+            }
+        }
+
+        $translations = $this->editorajax->getTranslations($stringlibs, $lang);
+
+        if ($emptyexpected) {
+            $this->assertEmpty($translations);
+        } else {
+            foreach ($translations as $stringlib => $translation) {
+                $this->assertEquals($datalibs[$stringlib]['translation'][$lang], $translation);
+            }
+        }
+    }
+
+    /**
+     * Data provider for test_get_translations().
+     *
+     * @return array
+     */
+    public function get_translations_provider(): array {
+        return [
+            'No library' => [
+                [],
+                'es',
+                true,
+                ['Library1 1.2']
+            ],
+            'One library with existing translation (es)' => [
+                [
+                    'Library1 1.2' => [
+                        'machinename' => 'Library1',
+                        'title' => 'Lib1',
+                        'majorversion' => 1,
+                        'minorversion' => 2,
+                        'translation' => [
+                            'es' => '{"libraryStrings": {"key": "valor"}}',
+                            'fr' => '{"libraryStrings": {"key": "valeur"}}',
+                        ],
+                    ]
+                ],
+                'es',
+                false
+            ],
+            'One library with existing translation (fr)' => [
+                [
+                    'Library1 1.2' => [
+                        'machinename' => 'Library1',
+                        'title' => 'Lib1',
+                        'majorversion' => 1,
+                        'minorversion' => 2,
+                        'translation' => [
+                            'es' => '{"libraryStrings": {"key": "valor"}}',
+                            'fr' => '{"libraryStrings": {"key": "valeur"}}',
+                        ],
+                    ]
+                ],
+                'fr',
+                false
+            ],
+            'One library with unexisting translation (de)' => [
+                [
+                    'Library1 1.2' => [
+                        'machinename' => 'Library1',
+                        'title' => 'Lib1',
+                        'majorversion' => 1,
+                        'minorversion' => 2,
+                        'translation' => [
+                            'es' => '{"libraryStrings": {"key": "valor"}}',
+                            'fr' => '{"libraryStrings": {"key": "valeur"}}',
+                        ],
+                    ]
+                ],
+                'de',
+                true
+            ],
+            'Two libraries with existing translation (es)' => [
+                [
+                    'Library1 1.2' => [
+                        'machinename' => 'Library1',
+                        'title' => 'Lib1',
+                        'majorversion' => 1,
+                        'minorversion' => 2,
+                        'translation' => [
+                            'es' => '{"libraryStrings": {"key": "valor"}}',
+                            'fr' => '{"libraryStrings": {"key": "valeur"}}',
+                        ],
+                    ],
+                    'Library2 3.4' => [
+                        'machinename' => 'Library2',
+                        'title' => 'Lib1',
+                        'majorversion' => 3,
+                        'minorversion' => 4,
+                        'translation' => [
+                            'es' => '{"libraryStrings": {"key": "valor"}}',
+                            'fr' => '{"libraryStrings": {"key": "valeur"}}',
+                        ],
+                    ]
+                ],
+                'es',
+                false
+            ],
+            'Two libraries with unexisting translation (de)' => [
+                [
+                    'Library1 1.2' => [
+                        'machinename' => 'Library1',
+                        'title' => 'Lib1',
+                        'majorversion' => 1,
+                        'minorversion' => 2,
+                        'translation' => [
+                            'es' => '{"libraryStrings": {"key": "valor"}}',
+                            'fr' => '{"libraryStrings": {"key": "valeur"}}',
+                        ],
+                    ],
+                    'Library2 3.4' => [
+                        'machinename' => 'Library2',
+                        'title' => 'Lib1',
+                        'majorversion' => 3,
+                        'minorversion' => 4,
+                        'translation' => [
+                            'es' => '{"libraryStrings": {"key": "valor"}}',
+                            'fr' => '{"libraryStrings": {"key": "valeur"}}',
+                        ],
+                    ]
+                ],
+                'de',
+                true
+            ],
+        ];
+    }
 }
index 27f485e..1dd6b8c 100644 (file)
@@ -53,6 +53,301 @@ class editor_framework_testcase extends \advanced_testcase {
         $this->editorframework = new editor_framework();
     }
 
+    /**
+     * Test that the method getLanguage retrieves the translation of a library in the requested language.
+     *
+     * @dataProvider  get_language_provider
+     *
+     * @param  array  $datalib        Library data to create
+     * @param  string $lang           Language to retrieve the translation
+     * @param  bool   $emptyexpected  True when false value is expected; false, otherwise
+     * @param  string $machinename    The machine readable name of the library(content type)
+     * @param  int    $majorversion   Major part of version number
+     * @param  int    $minorversion   Minor part of version number
+     */
+    public function test_get_language(array $datalib, string $lang, ?bool $emptyexpected = false, ?string $machinename = '',
+            ?int $majorversion = 1, ?int $minorversion = 0): void {
+        $this->resetAfterTest(true);
+
+        // Fetch generator.
+        $generator = \testing_util::get_data_generator();
+        $h5pgenerator = $generator->get_plugin_generator('core_h5p');
+
+        $h5pfilestorage = new file_storage();
+        $h5ptempath = $h5pfilestorage->getTmpPath();
+
+        $expectedresult = '';
+        if ($datalib) {
+            $translations = [];
+            if (array_key_exists('translation', $datalib)) {
+                $translations = $datalib['translation'];
+            }
+            // Create DB entry for this library.
+            $tmplib = $h5pgenerator->create_library_record($datalib['machinename'], $datalib['title'], $datalib['majorversion'],
+                $datalib['minorversion']);
+            // Create the files for this libray.
+            [$library, $files] = $h5pgenerator->create_library($h5ptempath, $tmplib->id, $datalib['machinename'],
+                $datalib['majorversion'], $datalib['minorversion'], $translations);
+            $h5pfilestorage->saveLibrary($library);
+
+            // If machinename, majorversion or minorversion are empty, use the value in datalib.
+            if (empty($machinename)) {
+                $machinename = $datalib['machinename'];
+            }
+            if (empty($majorversion)) {
+                $majorversion = $datalib['majorversion'];
+            }
+            if (empty($minorversion)) {
+                $minorversion = $datalib['minorversion'];
+            }
+            if (!$emptyexpected && array_key_exists($lang, $translations)) {
+                $expectedresult = $translations[$lang];
+            }
+        }
+
+        // Get Language.
+        $json = $this->editorframework->getLanguage($machinename, $majorversion, $minorversion, $lang);
+
+        if ($emptyexpected) {
+            $this->assertFalse($json);
+        } else {
+            $this->assertEquals($expectedresult, $json);
+        }
+    }
+
+    /**
+     * Data provider for test_get_language().
+     *
+     * @return array
+     */
+    public function get_language_provider(): array {
+        return [
+            'No library' => [
+                [],
+                'en',
+                true,
+                'Library1',
+                1,
+                2,
+            ],
+            'One library created but getting translation from an unexisting one' => [
+                'Library1 1.2' => [
+                    'machinename' => 'Library1',
+                    'title' => 'Lib1',
+                    'majorversion' => 1,
+                    'minorversion' => 2,
+                    'translation' => [
+                        'es' => '{"libraryStrings": {"key": "valor"}}',
+                        'fr' => '{"libraryStrings": {"key": "valeur"}}',
+                    ],
+                ],
+                'es',
+                true,
+                'AnotherLibrary',
+            ],
+            'One library without any translation' => [
+                'Library1 1.2' => [
+                    'machinename' => 'Library1',
+                    'title' => 'Lib1',
+                    'majorversion' => 1,
+                    'minorversion' => 2,
+                ],
+                'es',
+                true,
+            ],
+            'One library with 2 translations (es and fr) - es' => [
+                'Library1 1.2' => [
+                    'machinename' => 'Library1',
+                    'title' => 'Lib1',
+                    'majorversion' => 1,
+                    'minorversion' => 2,
+                    'translation' => [
+                        'es' => '{"libraryStrings": {"key": "valor"}}',
+                        'fr' => '{"libraryStrings": {"key": "valeur"}}',
+                    ],
+                ],
+                'es',
+            ],
+            'One library with 2 translations (es and fr) - fr' => [
+                'Library1 1.2' => [
+                    'machinename' => 'Library1',
+                    'title' => 'Lib1',
+                    'majorversion' => 1,
+                    'minorversion' => 2,
+                    'translation' => [
+                        'es' => '{"libraryStrings": {"key": "valor"}}',
+                        'fr' => '{"libraryStrings": {"key": "valeur"}}',
+                    ],
+                ],
+                'fr',
+            ],
+            'One library with 2 translations (es and fr) - unexisting translation (de)' => [
+                'Library1 1.2' => [
+                    'machinename' => 'Library1',
+                    'title' => 'Lib1',
+                    'majorversion' => 1,
+                    'minorversion' => 2,
+                    'translation' => [
+                        'es' => '{"libraryStrings": {"key": "valor"}}',
+                        'fr' => '{"libraryStrings": {"key": "valeur"}}',
+                    ],
+                ],
+                'de',
+                true
+            ],
+            'One library with 3 translations (one of them English) - fr' => [
+                'Library1 1.2' => [
+                    'machinename' => 'Library1',
+                    'title' => 'Lib1',
+                    'majorversion' => 1,
+                    'minorversion' => 2,
+                    'translation' => [
+                        'en' => '{"libraryStrings": {"key": "value"}}',
+                        'es' => '{"libraryStrings": {"key": "valor"}}',
+                        'fr' => '{"libraryStrings": {"key": "valeur"}}',
+                    ],
+                ],
+                'fr',
+            ],
+            'One library with 3 translations (one of them English) - en' => [
+                'Library1 1.2' => [
+                    'machinename' => 'Library1',
+                    'title' => 'Lib1',
+                    'majorversion' => 1,
+                    'minorversion' => 2,
+                    'translation' => [
+                        'en' => '{"libraryStrings": {"key": "value"}}',
+                        'es' => '{"libraryStrings": {"key": "valor"}}',
+                        'fr' => '{"libraryStrings": {"key": "valeur"}}',
+                    ],
+                ],
+                'en',
+            ],
+        ];
+    }
+
+    /**
+     * Test that the method getAvailableLanguages retrieves all the language available of a library.
+     *
+     * @dataProvider  get_available_languages_provider
+     *
+     * @param  array  $datalib        Library data to create
+     * @param  array  $expectedlangs  Available languages expected.
+     * @param  string $machinename    The machine readable name of the library(content type)
+     * @param  int    $majorversion   Major part of version number
+     * @param  int    $minorversion   Minor part of version number
+     */
+    public function test_get_available_languages(array $datalib, ?array $expectedlangs = null, ?string $machinename = '',
+            ?int $majorversion = 1, ?int $minorversion = 0): void {
+        $this->resetAfterTest(true);
+
+        // Fetch generator.
+        $generator = \testing_util::get_data_generator();
+        $h5pgenerator = $generator->get_plugin_generator('core_h5p');
+
+        $h5pfilestorage = new file_storage();
+        $h5ptempath = $h5pfilestorage->getTmpPath();
+
+        $translations = [];
+        if ($datalib) {
+            if (array_key_exists('translation', $datalib)) {
+                $translations = $datalib['translation'];
+            }
+            // Create DB entry for this library.
+            $tmplib = $h5pgenerator->create_library_record($datalib['machinename'], $datalib['title'], $datalib['majorversion'],
+                $datalib['minorversion']);
+            // Create the files for this libray.
+            [$library, $files] = $h5pgenerator->create_library($h5ptempath, $tmplib->id, $datalib['machinename'],
+                $datalib['majorversion'], $datalib['minorversion'], $translations);
+            $h5pfilestorage->saveLibrary($library);
+
+            if (empty($machinename)) {
+                $machinename = $datalib['machinename'];
+            }
+            if (empty($majorversion)) {
+                $majorversion = $datalib['majorversion'];
+            }
+            if (empty($minorversion)) {
+                $minorversion = $datalib['minorversion'];
+            }
+        }
+
+        // Get available languages.
+        $langs = $this->editorframework->getAvailableLanguages($machinename, $majorversion, $minorversion);
+
+        $this->assertCount(count($expectedlangs), $langs);
+        $this->assertEquals(ksort($expectedlangs), ksort($langs));
+    }
+
+    /**
+     * Data provider for test_get_available_languages().
+     *
+     * @return array
+     */
+    public function get_available_languages_provider(): array {
+        return [
+            'No library' => [
+                [],
+                [],
+                'Library1',
+                1,
+                2,
+            ],
+            'One library created but getting available from an unexisting one' => [
+                'Library1 1.2' => [
+                    'machinename' => 'Library1',
+                    'title' => 'Lib1',
+                    'majorversion' => 1,
+                    'minorversion' => 2,
+                    'translation' => [
+                        'es' => '{"libraryStrings": {"key": "valor"}}',
+                        'fr' => '{"libraryStrings": {"key": "valeur"}}',
+                    ],
+                ],
+                [],
+                'Library2',
+                1,
+                2,
+            ],
+            'One library without any translation' => [
+                'Library1 1.2' => [
+                    'machinename' => 'Library1',
+                    'title' => 'Lib1',
+                    'majorversion' => 1,
+                    'minorversion' => 2,
+                ],
+                ['en'],
+            ],
+            'One library with 2 translations (es and fr)' => [
+                'Library1 1.2' => [
+                    'machinename' => 'Library1',
+                    'title' => 'Lib1',
+                    'majorversion' => 1,
+                    'minorversion' => 2,
+                    'translation' => [
+                        'es' => '{"libraryStrings": {"key": "valor"}}',
+                        'fr' => '{"libraryStrings": {"key": "valeur"}}',
+                    ],
+                ],
+                ['en', 'es', 'fr'],
+            ],
+            'One library with 3 translations (one of them English)' => [
+                'Library1 1.2' => [
+                    'machinename' => 'Library1',
+                    'title' => 'Lib1',
+                    'majorversion' => 1,
+                    'minorversion' => 2,
+                    'translation' => [
+                        'en' => '{"libraryStrings": {"key": "value"}}',
+                        'es' => '{"libraryStrings": {"key": "valor"}}',
+                        'fr' => '{"libraryStrings": {"key": "valeur"}}',
+                    ],
+                ],
+                ['en', 'es', 'fr'],
+            ],
+        ];
+    }
+
     /**
      * Test that the method getLibraries get the specified libraries or all the content types (runnable = 1).
      */
index c23baba..9cf4313 100644 (file)
@@ -76,15 +76,19 @@ class core_h5p_generator extends \component_generator_base {
      * @param  string $machinename     Name for this library.
      * @param  int    $majorversion    Major version (any number will do).
      * @param  int    $minorversion    Minor version (any number will do).
+     * @param  array  $langs           Languages to be included into the library.
      * @return array A list of library data and files that the core API will understand.
      */
     public function create_library(string $uploaddirectory, int $libraryid, string $machinename, int $majorversion,
-            int $minorversion): array {
-        /** @var array $files an array used in the cache tests. */
-        $files = ['scripts' => [], 'styles' => []];
+            int $minorversion, ?array $langs = []): array {
+        // Array $files used in the cache tests.
+        $files = ['scripts' => [], 'styles' => [], 'language' => []];
 
         check_dir_exists($uploaddirectory . '/' . 'scripts');
         check_dir_exists($uploaddirectory . '/' . 'styles');
+        if (!empty($langs)) {
+            check_dir_exists($uploaddirectory . '/' . 'language');
+        }
 
         $jsonfile = $uploaddirectory . '/' . 'library.json';
         $jsfile = $uploaddirectory . '/' . 'scripts/testlib.min.js';
@@ -92,6 +96,10 @@ class core_h5p_generator extends \component_generator_base {
         $this->create_file($jsonfile);
         $this->create_file($jsfile);
         $this->create_file($cssfile);
+        foreach ($langs as $lang => $value) {
+            $jsonfile = $uploaddirectory . '/' . 'language/' . $lang . '.json';
+            $this->create_file($jsonfile, $value);
+        }
 
         $lib = [
             'title' => 'Test lib',
@@ -120,6 +128,10 @@ class core_h5p_generator extends \component_generator_base {
         $this->add_libfile_to_array('scripts', $path, $version, $files);
         $path = '/' . 'libraries' . '/' . $libraryid .'/' . $libname . '/' . 'styles' . '/' . 'testlib.min.css';
         $this->add_libfile_to_array('styles', $path, $version, $files);
+        foreach ($langs as $lang => $notused) {
+            $path = '/' . 'libraries' . '/' . $libraryid . '/' . $libname . '/' . 'language' . '/' . $lang . '.json';
+            $this->add_libfile_to_array('language', $path, $version, $files);
+        }
 
         return [$lib, $files];
     }
index eb3dc7b..cb59517 100644 (file)
@@ -57,6 +57,7 @@ $string['cachedef_externalbadges'] = 'External badges for particular user';
 $string['cachedef_fontawesomeiconmapping'] = 'Mapping of icons for font awesome';
 $string['cachedef_suspended_userids'] = 'List of suspended users per course';
 $string['cachedef_groupdata'] = 'Course group information';
+$string['cachedef_h5p_content_type_translations'] = 'H5P content-type libraries translations';
 $string['cachedef_htmlpurifier'] = 'HTML Purifier - cleaned content';
 $string['cachedef_langmenu'] = 'List of available languages';
 $string['cachedef_message_time_last_message_between_users'] = 'Time created for most recent message in a conversation';
index fc05d97..a5bd37e 100644 (file)
@@ -446,4 +446,12 @@ $definitions = array(
         'simpledata' => true,
         'staticacceleration' => true,
     ],
+
+    // Language strings for H5P content-type libraries.
+    // Key "{$libraryname}/{$language}"" contains translations for a given library and language.
+    // Key "$libraryname" has a list of all of the available languages for the library.
+    'h5p_content_type_translations' => [
+        'mode' => cache_store::MODE_APPLICATION,
+        'simpledata' => true,
+    ],
 );