diff --git a/assets/translate.js b/assets/translate.js index 11296942..66140f07 100644 --- a/assets/translate.js +++ b/assets/translate.js @@ -9,22 +9,29 @@ $( function () { return; } function onSelectTargetLang( language ) { - // Save the language name and code in the widget. + var $imgElement, newImageUrl; + // 1. Save the language name and code in the widget. this.setLabel( $.uls.data.languages[ language ][ 2 ] ); this.setData( language ); - // Also switch what's displayed in the form when a new language is selected in the ULS. + this.setValue( language ); + // 2. Switch what's displayed in the form when a new language is selected in the ULS. $( '.translation-fields .oo-ui-fieldLayout' ).each( function () { - var field = OO.ui.infuse( $( this ) ).getField(); - if ( appConfig.translations[ field.data.nodeId ] && - appConfig.translations[ field.data.nodeId ][ language ] + var field = OO.ui.infuse( $( this ) ).getField(), + tspanId = field.data[ 'tspan-id' ]; + if ( appConfig.translations[ tspanId ] && + appConfig.translations[ tspanId ][ language ] ) { // If there's a translation available, set the field's value. - field.setValue( appConfig.translations[ field.data.nodeId ][ language ].text ); + field.setValue( appConfig.translations[ tspanId ][ language ].text ); } else { // Otherwise, blank the field. field.setValue( '' ); } } ); + // 3. Update the image. + $imgElement = $( '.image img' ); + newImageUrl = $imgElement.attr( 'src' ).replace( /[a-z_-]*\.png.*$/, language + '.png' ); + $imgElement.attr( 'src', newImageUrl ); } targetLangButton = OO.ui.infuse( $targetLangButton ); targetLangButton.$element.uls( { @@ -68,3 +75,42 @@ $( function () { } ); } ); } ); + +/** + * When a translation field is changed, update the image preview. + */ +$( function () { + $( '.translation-fields .oo-ui-fieldLayout .oo-ui-inputWidget' ).each( function () { + var inputWiget = OO.ui.infuse( $( this ) ), + $imgElement = $( '.image img' ), + targetLangWidget = OO.ui.infuse( $( '.target-lang-widget' ) ), + targetLangCode = targetLangWidget.getValue(), + requestParams = {}, + updatePreviewImage = function () { + // Go through all fields and construct the request parameters. + $( '.translation-fields .oo-ui-fieldLayout' ).each( function () { + var fieldLayout = OO.ui.infuse( $( this ) ), + tspanId = fieldLayout.getField().data[ 'tspan-id' ]; + requestParams[ tspanId ] = fieldLayout.getField().getValue(); + } ); + // Update the image. + $.ajax( { + type: 'POST', + url: appConfig.baseUrl + 'api/translate/' + $imgElement.data( 'filename' ) + '/' + targetLangCode, + data: requestParams, + success: function ( result ) { + $imgElement.attr( 'src', result.imageSrc ); + }, + error: function () { + OO.ui.alert( $.i18n( 'preview-error-occurred' ) ); + } + } ); + }; + // Update the preview image on field blur and after two seconds of no typing. + inputWiget.$input.on( 'blur', updatePreviewImage ); + inputWiget.on( 'change', OO.ui.debounce( updatePreviewImage, 2000 ) ); + } ); + // Trigger a change, to force a refresh of the preview on page load (to catch browser-cached + // input values). + $( '.translation-fields .oo-ui-fieldLayout .oo-ui-inputWidget input' ).trigger( 'blur' ); +} ); diff --git a/i18n/en.json b/i18n/en.json index 00a13333..89f5a266 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -33,6 +33,7 @@ "download-button-label": "Download", "download-or-upload": "or", "translation-image-alt": "The image that's currently being translated. No description available.", + "preview-error-occurred": "An error occurred when fetching the preview. Please continue translating, but if this error persists do report a bug (via the link in the footer below).", "download-icon-alt": "An icon indicating file-download", "pick-an-image-title": "Pick an image", diff --git a/i18n/qqq.json b/i18n/qqq.json index 95fccc99..f2199a43 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -33,6 +33,7 @@ "download-button-label": "Label for the button that downloads the translated SVG to the user's local computer.", "download-or-upload": "Label positioned between the download and the upload buttons.", "translation-image-alt": "Alt text for the image that's currently being translated. Doesn't explain the image, just explains that we don't explain it.", + "preview-error-occurred": "Error message displayed in a popup when fetching a preview failed. The only option is 'OK' to close the popup.", "download-icon-alt": "Alt text for the download icon.", "pick-an-image-title": "The title of the 'pick an image' step of the tutorial box.", diff --git a/public/assets/app.bd58f67a.js b/public/assets/app.b885261f.js similarity index 99% rename from public/assets/app.bd58f67a.js rename to public/assets/app.b885261f.js index 3f9ff770..b66d8b4e 100644 --- a/public/assets/app.bd58f67a.js +++ b/public/assets/app.b885261f.js @@ -62,7 +62,7 @@ function(t){var e,i,n,o,s,a,r,l,u,c,h,d,p,g,f,m,y,b,v,w="sizzle"+1*new Date,x=t. * @licence GNU General Public Licence 2.0 or later * @licence MIT License */ -!function(t){"use strict";var e,i,n,o=Array.prototype.slice;(e=function(i){this.options=t.extend({},e.defaults,i),this.parser=this.options.parser,this.locale=this.options.locale,this.messageStore=this.options.messageStore,this.languages={}}).prototype={localize:function(e){var i,n,o,s,a,r;for(o=this.locale,s=0;o;){n=(i=o.split("-")).length;do{if(a=i.slice(0,n).join("-"),r=this.messageStore.get(a,e))return r;n--}while(n);if("en"===o)break;o=t.i18n.fallbacks[this.locale]&&t.i18n.fallbacks[this.locale][s]||this.options.fallbackLocale,t.i18n.log("Trying fallback locale for "+this.locale+": "+o+" ("+e+")"),s++}return""},destroy:function(){t.removeData(document,"i18n")},load:function(e,i){var n,o,s,a={};if(e||i||(e="i18n/"+t.i18n().locale+".json",i=t.i18n().locale),"string"==typeof e&&"json"!==e.split("?")[0].split(".").pop()){for(a[i]=e+"/"+i+".json",n=(t.i18n.fallbacks[i]||[]).concat(this.options.fallbackLocale),o=0;o-1)return!0;for(n=0;n1},setGroupByRegionOverride:function(t){this.groupByRegionOverride=t},render:function(){var t,i=this.buildQuicklist(),n=[],o={all:"All languages",WW:"Worldwide",SP:"Special",AM:"America",EU:"Europe",ME:"Middle East",AS:"Asia",AF:"Africa",PA:"Pacific"};i.length?n.push(i):this.$element.addClass("uls-lcd--no-quicklist"),this.options.showRegions.forEach(function(i){this.regionLanguages[i]=[],t=e("
").addClass("uls-lcd-region-section hide").attr("data-region",i),e("

").attr("data-i18n","uls-region-"+i).addClass("uls-lcd-region-title").text(o[i]).appendTo(t),n.push(t)}.bind(this)),this.$element.append(n),this.i18n()},renderRegions:function(){var t,i=this;this.$element.removeClass("uls-no-results"),this.$element.children(".uls-lcd-region-section").each(function(){var n=e(this),o=n.data("region");n.is(".uls-lcd-quicklist")||(n.children(".uls-language-block").remove(),(t=i.regionLanguages[o])&&0!==t.length?(i.renderRegion(n,t,i.options.itemsPerColumn,i.options.columns),n.removeClass("hide"),i.regionLanguages[o]=[]):n.addClass("hide"))})},renderRegion:function(t,i,n,o){var s,a,r,l,u,c,h=i.length,d=[],p=[],g=[];if(i=e.uls.data.sortByScriptGroup(i.sort(e.uls.data.sortByAutonym)),s=1===o?"twelve columns":2===o?"six columns":"three columns",1===this.options.columns){for(a=0;a").addClass(s).append(d)),g.push(e("
").addClass("row uls-language-block").append(p))}else for(a=0;a1&&(c=!0):l=e.uls.data.getScriptGroupOfLanguage(i[a]),l=u,d.push(this.renderItem(i[a])),(d.length>=n||r||c)&&(p.push(e("
    ").addClass(s).append(d)),d=[],(p.length>=o||r)&&(g.push(e("
    ").addClass("row uls-language-block").append(p)),p=[]));t.append(g)},renderItem:function(t){var i,n,o,s;return n=this.options.languages[t],o=e.uls.data.getAutonym(t)||n||t,(s=document.createElement("li")).title=n,s.setAttribute("data-code",t),(i=document.createElement("a")).appendChild(document.createTextNode(o)),i.className="autonym",i.lang=t,i.dir=e.uls.data.getDir(t),s.appendChild(i),this.options.languageDecorator&&this.options.languageDecorator(e(i),t),s},i18n:function(){this.$element.find("[data-i18n]").i18n()},quicklist:function(){this.$element.find(".uls-lcd-quicklist").removeClass("hide")},buildQuicklist:function(){var t,i,n;return null!==this.cachedQuicklist?this.cachedQuicklist:(e.isFunction(this.options.quickList)&&(this.options.quickList=this.options.quickList()),this.options.quickList.length?((t=(t=this.options.quickList).slice(0,16)).sort(e.uls.data.sortByAutonym),i=e("
    ").addClass("uls-lcd-region-section uls-lcd-quicklist"),n=e("

    ").attr("data-i18n","uls-common-languages").addClass("uls-lcd-region-title").text("Suggested languages"),i.append(n),this.renderRegion(i,t,this.options.itemsPerColumn,this.options.columns),n.i18n(),this.cachedQuicklist=i,this.cachedQuicklist):(this.cachedQuicklist=e([]),this.cachedQuicklist))},show:function(){this.regionDivs||this.render()},empty:function(){this.$element.addClass("uls-lcd--no-quicklist"),this.$element.find(".uls-lcd-quicklist").addClass("hide")},focus:function(){this.$element.focus()},noResults:function(e,i){var n;if(this.$element.addClass("uls-no-results"),this.$element.find(".uls-no-results-view").remove(),"function"==typeof this.options.noResultsTemplate)n=this.options.noResultsTemplate.call(this,i.query);else{if(!(this.options.noResultsTemplate instanceof t))throw new Error("noResultsTemplate option must be either jQuery or function returning jQuery");n=this.options.noResultsTemplate}this.$element.append(n.addClass("uls-no-results-view").i18n())},listen:function(){var t=this;this.options.clickhandler&&this.$element.on("click",".row li",function(i){t.options.clickhandler.call(this,e(this).data("code"),i)})}},e.fn.lcd=function(t){return this.each(function(){var n=e(this),o=n.data("lcd"),s="object"==typeof t&&t;o||n.data("lcd",o=new i(this,s)),"string"==typeof t&&o[t]()})},e.fn.lcd.defaults={languages:[],showRegions:["WW","AM","EU","ME","AF","AS","PA"],groupByRegion:"auto",itemsPerColumn:8,columns:4,languageDecorator:void 0,quickList:[],clickhandler:void 0,noResultsTemplate:function(){var t,i=e('
    \t\t

    No results found

    \t\t
    \t\t
    \t\t
    You can search by language name, script name, ISO code of language or you can browse by region.
    \t\t
    ');return(t=this.buildQuicklist().clone()).removeClass("hide").find("h3").data("i18n","uls-no-results-suggestion-title").text("You may be interested in:").i18n(),i.find(".uls-no-results-suggestions").append(t),i}}}(t)}).call(this,i("EVdn"))},ML86:function(t,e,i){},Mh5E:function(t,e,i){(function(t){var e;!function(){return function t(i,n,o){function s(r,l){if(!n[r]){if(!i[r]){if(!l&&"function"==typeof e&&e)return e(r,!0);if(a)return a(r,!0);var u=new Error("Cannot find module '"+r+"'");throw u.code="MODULE_NOT_FOUND",u}var c=n[r]={exports:{}};i[r][0].call(c.exports,function(t){return s(i[r][1][t]||t)},c,c.exports,t,i,n,o)}return n[r].exports}for(var a="function"==typeof e&&e,r=0;r-1)return!0;for(n=0;n1},setGroupByRegionOverride:function(t){this.groupByRegionOverride=t},render:function(){var t,i=this.buildQuicklist(),n=[],o={all:"All languages",WW:"Worldwide",SP:"Special",AM:"America",EU:"Europe",ME:"Middle East",AS:"Asia",AF:"Africa",PA:"Pacific"};i.length?n.push(i):this.$element.addClass("uls-lcd--no-quicklist"),this.options.showRegions.forEach(function(i){this.regionLanguages[i]=[],t=e("
    ").addClass("uls-lcd-region-section hide").attr("data-region",i),e("

    ").attr("data-i18n","uls-region-"+i).addClass("uls-lcd-region-title").text(o[i]).appendTo(t),n.push(t)}.bind(this)),this.$element.append(n),this.i18n()},renderRegions:function(){var t,i=this;this.$element.removeClass("uls-no-results"),this.$element.children(".uls-lcd-region-section").each(function(){var n=e(this),o=n.data("region");n.is(".uls-lcd-quicklist")||(n.children(".uls-language-block").remove(),(t=i.regionLanguages[o])&&0!==t.length?(i.renderRegion(n,t,i.options.itemsPerColumn,i.options.columns),n.removeClass("hide"),i.regionLanguages[o]=[]):n.addClass("hide"))})},renderRegion:function(t,i,n,o){var s,a,r,l,u,c,h=i.length,d=[],p=[],g=[];if(i=e.uls.data.sortByScriptGroup(i.sort(e.uls.data.sortByAutonym)),s=1===o?"twelve columns":2===o?"six columns":"three columns",1===this.options.columns){for(a=0;a").addClass(s).append(d)),g.push(e("
    ").addClass("row uls-language-block").append(p))}else for(a=0;a1&&(c=!0):l=e.uls.data.getScriptGroupOfLanguage(i[a]),l=u,d.push(this.renderItem(i[a])),(d.length>=n||r||c)&&(p.push(e("
      ").addClass(s).append(d)),d=[],(p.length>=o||r)&&(g.push(e("
      ").addClass("row uls-language-block").append(p)),p=[]));t.append(g)},renderItem:function(t){var i,n,o,s;return n=this.options.languages[t],o=e.uls.data.getAutonym(t)||n||t,(s=document.createElement("li")).title=n,s.setAttribute("data-code",t),(i=document.createElement("a")).appendChild(document.createTextNode(o)),i.className="autonym",i.lang=t,i.dir=e.uls.data.getDir(t),s.appendChild(i),this.options.languageDecorator&&this.options.languageDecorator(e(i),t),s},i18n:function(){this.$element.find("[data-i18n]").i18n()},quicklist:function(){this.$element.find(".uls-lcd-quicklist").removeClass("hide")},buildQuicklist:function(){var t,i,n;return null!==this.cachedQuicklist?this.cachedQuicklist:(e.isFunction(this.options.quickList)&&(this.options.quickList=this.options.quickList()),this.options.quickList.length?((t=(t=this.options.quickList).slice(0,16)).sort(e.uls.data.sortByAutonym),i=e("
      ").addClass("uls-lcd-region-section uls-lcd-quicklist"),n=e("

      ").attr("data-i18n","uls-common-languages").addClass("uls-lcd-region-title").text("Suggested languages"),i.append(n),this.renderRegion(i,t,this.options.itemsPerColumn,this.options.columns),n.i18n(),this.cachedQuicklist=i,this.cachedQuicklist):(this.cachedQuicklist=e([]),this.cachedQuicklist))},show:function(){this.regionDivs||this.render()},empty:function(){this.$element.addClass("uls-lcd--no-quicklist"),this.$element.find(".uls-lcd-quicklist").addClass("hide")},focus:function(){this.$element.focus()},noResults:function(e,i){var n;if(this.$element.addClass("uls-no-results"),this.$element.find(".uls-no-results-view").remove(),"function"==typeof this.options.noResultsTemplate)n=this.options.noResultsTemplate.call(this,i.query);else{if(!(this.options.noResultsTemplate instanceof t))throw new Error("noResultsTemplate option must be either jQuery or function returning jQuery");n=this.options.noResultsTemplate}this.$element.append(n.addClass("uls-no-results-view").i18n())},listen:function(){var t=this;this.options.clickhandler&&this.$element.on("click",".row li",function(i){t.options.clickhandler.call(this,e(this).data("code"),i)})}},e.fn.lcd=function(t){return this.each(function(){var n=e(this),o=n.data("lcd"),s="object"==typeof t&&t;o||n.data("lcd",o=new i(this,s)),"string"==typeof t&&o[t]()})},e.fn.lcd.defaults={languages:[],showRegions:["WW","AM","EU","ME","AF","AS","PA"],groupByRegion:"auto",itemsPerColumn:8,columns:4,languageDecorator:void 0,quickList:[],clickhandler:void 0,noResultsTemplate:function(){var t,i=e('
      \t\t

      No results found

      \t\t
      \t\t
      \t\t
      You can search by language name, script name, ISO code of language or you can browse by region.
      \t\t
      ');return(t=this.buildQuicklist().clone()).removeClass("hide").find("h3").data("i18n","uls-no-results-suggestion-title").text("You may be interested in:").i18n(),i.find(".uls-no-results-suggestions").append(t),i}}}(t)}).call(this,i("EVdn"))},ML86:function(t,e,i){},Mh5E:function(t,e,i){(function(t){var e;!function(){return function t(i,n,o){function s(r,l){if(!n[r]){if(!i[r]){if(!l&&"function"==typeof e&&e)return e(r,!0);if(a)return a(r,!0);var u=new Error("Cannot find module '"+r+"'");throw u.code="MODULE_NOT_FOUND",u}var c=n[r]={exports:{}};i[r][0].call(c.exports,function(t){return s(i[r][1][t]||t)},c,c.exports,t,i,n,o)}return n[r].exports}for(var a="function"==typeof e&&e,r=0;rserveContent($this->cache->getPath($filename), $lang); + $content = $this->svgRenderer->render($this->cache->getPath($filename), $lang); + return new Response($content, 200, [ + 'Content-Type' => 'image/png', + 'X-File-Hash' => sha1($content), + ]); } /** - * Serve a PNG rendering of the given SVG in the given language, based on the POSTed translations. - * @Route("/api/file/{filename}/{lang}.png", name="api_file_translated", methods="POST") - * @param string $filename - * @param Request $request - * @return Response + * Get a full filesystem path to a temporary PNG file. + * @param string $filename The base SVG filename. + * @param string $key They unique key to append to the filename. + * @return string */ - public function getFileWithTranslations(string $filename, string $lang, Request $request): Response + protected function getTempPngFilename(string $filename, string $key): string { - $filename = Title::normalize($filename); - $json = $request->getContent(); - if ('' === $json) { - return $this->getFile($filename, $lang); - } + return $this->cache->fullPath($filename.'_'.$key.'.png'); + } - $translations = \GuzzleHttp\json_decode($json, true); + /** + * Take POST data, write new translations into the SVG file, render a resultant PNG out to the + * filesystem, and return an identifier for that PNG file. + * + * @Route("/api/translate/{filename}/{lang}", name="api_file_request", methods="POST") + */ + public function requestFileWithTranslations(string $filename, string $lang, Request $request): Response + { + // Get the SVG file, and add in the new translations. + $filename = Title::normalize($filename); $path = $this->cache->getPath($filename); $file = new SvgFile($path); - $file->switchToTranslationSet($translations); - - // Write SVG file to filesystem, so it can be converted by rsvg. Use a unique filename - // because multiple users can be translating the same file at the same time (whereas - // getFile() above only ever serves the one version of a file). - $tmpSvgFilename = $this->cache->getTempSvgFile(); - $file->saveToPath($tmpSvgFilename); + $translations = $request->request->all(); + $file->setTranslations($lang, $translations); + + // Write the modified SVG out to the filesystem, named with a unique key. This is necessary + // both because multiple people could be translating the same file at the same time, and + // also means we can use the same key for the rendered PNG file. The key is generated from + // the translation set so that the + $fileKey = md5(serialize($translations)); + $tempPngFilename = $this->getTempPngFilename($filename, $fileKey); + $file->saveToPath($tempPngFilename); + + // Render the modified SVG to PNG, and return it's URL. + $renderedPngContents = $this->svgRenderer->render($tempPngFilename, $lang); + file_put_contents($tempPngFilename, $renderedPngContents); + $relativeUrl = $this->generateUrl('api_file_translated', [ + 'filename' => $filename, + 'key' => $fileKey, + 'lang' => $lang, + ]); + return new JsonResponse(['imageSrc' => $relativeUrl]); + } - return $this->serveContent($tmpSvgFilename, $lang); + /** + * Get a request for a already-rendered, custom-translated PNG (identified by a key), and + * return that file. + * + * @Route("/api/file/{filename}/{lang}/{key}.png", name="api_file_translated", methods="GET") + * + * @param string $filename + * @param Request $request + * @return Response + */ + public function getFileWithTranslations(string $filename, string $lang, string $key, Request $request): Response + { + $tempPngFilename = $this->getTempPngFilename($filename, $key); + if (file_exists($tempPngFilename)) { + return new BinaryFileResponse($tempPngFilename); + } + throw new NotFoundHttpException(); } /** @@ -103,20 +148,4 @@ public function getLanguages(string $fileName): Response return $this->json($langs); } - - /** - * Serves an SVG as a PNG. - * - * @param string $svgFilename Full path to the SVG file to convert and serve as a PNG. - * @param string $lang The language to use for the SVG's text. - * @return Response - */ - private function serveContent(string $svgFilename, string $lang): Response - { - $content = $this->svgRenderer->render($svgFilename, $lang); - return new Response($content, 200, [ - 'Content-Type' => 'image/png', - 'X-File-Hash' => sha1($content), - ]); - } } diff --git a/src/Controller/TranslateController.php b/src/Controller/TranslateController.php index d865b709..6d99c349 100644 --- a/src/Controller/TranslateController.php +++ b/src/Controller/TranslateController.php @@ -122,16 +122,19 @@ public function translate( // Messages. $translations = $svgFile->getInFileTranslations(); $formFields = []; - foreach ($translations as $nodeId => $langs) { + foreach ($translations as $tspanId => $translation) { + $fieldValue = isset($translation[$targetLang->getValue()]) + ? $translation[$targetLang->getValue()]['text'] + : ''; $inputWidget = new TextInputWidget([ - 'name' => 'translation-field-'.$nodeId, - 'value' => isset($langs[$targetLang->getValue()]) ? $langs[$targetLang->getValue()]['text'] : '', - 'data' => ['nodeId' => $nodeId], + 'name' => 'translation-field-'.$tspanId, + 'value' => $fieldValue, + 'data' => ['tspan-id' => $tspanId], ]); $field = new FieldLayout( $inputWidget, [ - 'label' => $langs[$sourceLang->getValue()]['text'], + 'label' => $translation[$sourceLang->getValue()]['text'], 'infusable' => true, ] ); diff --git a/src/Model/Svg/SvgFile.php b/src/Model/Svg/SvgFile.php index ddb81f6f..e9ab8fb8 100644 --- a/src/Model/Svg/SvgFile.php +++ b/src/Model/Svg/SvgFile.php @@ -430,6 +430,38 @@ public function getInFileTranslations(): array return $this->inFileTranslations; } + /** + * Set translations for a single language. + * @param string $lang Language code of the translations being provided. + * @param string[] $translations Array of tspan-IDs to message texts. + * @return string[][] + */ + public function setTranslations(string $lang, array $translations): array + { + // Load the existing translation structure, and go through it swapping the messages. + $inFileTranslations = $this->getInFileTranslations(); + $filteredTextNodes = $this->getFilteredTextNodes(); + foreach ($translations as $tspanId => $msg) { + // Set up the tspan node (including adding in the new message). + if (!isset($inFileTranslations[$tspanId][$lang])) { + $inFileTranslations[$tspanId][$lang] = $inFileTranslations[$tspanId]['fallback']; + $inFileTranslations[$tspanId][$lang]['id'] .= "-$lang"; + } + if (!empty($msg)) { + $inFileTranslations[$tspanId][$lang]['text'] = $msg; + } + // Set up the text node (if this is a new language). + $textId = $inFileTranslations[$tspanId][$lang]['data-parent']; + if (!isset($filteredTextNodes[$textId][$lang])) { + $filteredTextNodes[$textId][$lang] = $filteredTextNodes[$textId]['fallback']; + $filteredTextNodes[$textId][$lang]['id'] .= "-$lang"; + } + } + $allTranslations = array_merge($inFileTranslations, $filteredTextNodes); + // Add the updated translations back into the file. + return $this->switchToTranslationSet($allTranslations); + } + /** * Try to return $this->savedLanguages (a list of languages which have one or more * translations in-file). If it is not cached, analyse the SVG and hence generate it. diff --git a/src/Service/FileCache.php b/src/Service/FileCache.php index cfd91b49..9f33cc21 100644 --- a/src/Service/FileCache.php +++ b/src/Service/FileCache.php @@ -71,7 +71,7 @@ protected function tick(): void return; } - foreach (glob($this->fullPath('*.svg')) as $fileName) { + foreach (glob($this->fullPath('*.*')) as $fileName) { $this->statFile($fileName); } } @@ -103,18 +103,8 @@ protected function statFile(string $fileName): bool * @param string $fileName * @return string */ - protected function fullPath(string $fileName): string + public function fullPath(string $fileName): string { return $this->directory.DIRECTORY_SEPARATOR.$fileName; } - - /** - * Create a file with a unique .svg filename, with access permission set to 0600, - * and return its name. - * @return string - */ - public function getTempSvgFile(): string - { - return tempnam($this->directory, 'temp_').'.svg'; - } } diff --git a/templates/base.html.twig b/templates/base.html.twig index a6b3289f..04bd3983 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -75,6 +75,7 @@