Closed fontanil closed 2 years ago
Sorry, I missed the error log.
The thing is that for some reason you apparently pass an XML object into Text::_()
instead of the language KEY. Also, it contains already the translated value, which at this point shouldn't be there.
So the question is how that Text::_()
is called. Instead of passing just a single LANGUAGE_KEY (eg COM_LOCALISE_NOTICE_GITHUB_FILE_ADDED
), it gets passed a lot more.
Btw, simple_xml does behave a bit different in PHP 8 as well. So it may be that you need to better pass a simpleXML string.
@Bakual
Previously from the other coment you say "The comma is only used as a separator from the KEY to the values."
I does not understand why is used a comma as separator, but this one now have sense with the code line:
$first_part = array_shift($string_parts);
Than "eat" the first element from the array, and leave only "string parts".
If it is used to separate the key from the string (no idea due i have not a general knowledge of the whole cycle, only the part that I see fail), note than that "comma" is not present at "var_dump".
Second stuff to take in mind is than comlocalise code is not trying to "prerender" or "preprocess" the Text::() or Text::sprintf() outputs in any way. As all others extensions we simply call:
use Joomla\CMS\Language\Text;
And is the "Text" function who is calling the:
if (self::passSprintf($string, $jsSafe, $interpretBackSlashes, $script))
{
return $string;
}
and then frompassSprintf
is loading a language
$lang = Factory::getLanguage();
$string_parts = explode(',', $string);
And trying to precheck each string as valid or not vallidText::sprintf()
Finallly note than the code for the key COM_LOCALISE_NOTICE_GITHUB_FILE_ADDED
is at /administrator/components/com_localise/Helper/LocaliseHelper.php
path, and is not showed the time the warning log is tiggered, the syntax is right and the amount of placeholders and placeholdrs format is exactly the required by code and by language string.
So the question is how that Text::_() is called. Instead of passing just a single LANGUAGE_KEY (eg COM_LOCALISE_NOTICE_GITHUB_FILE_ADDED), it gets passed a lot more.
Text::_() i think is calling it, loading the language file and then evaulating key by key the strings, without success sometimes due is bugged.
For the other error (Warning: Trying to access array offset on value of type bool in /home/www/sitestests/admtools/administrator/components/com_localise/Model/TranslationModel.php on line 317) PHP 8 doesn't allow empty line[0] so we need to use `if(empty($line[0])) {
} elseif ($line[0] == '#') { $this->item->error[] = $lineNumber; } elseif ($line[0] == ';') `
@fontanil Have you installed the beta6 pack I provided above? https://github.com/infograf768/j4localise/issues/42#issuecomment-950283532 I do not get that error here with php8.
For the other error (Warning: Trying to access array offset on value of type bool in /home/www/sitestests/admtools/administrator/components/com_localise/Model/TranslationModel.php on line 317) PHP 8 doesn't allow empty line[0] so we need to use `if(empty($line[0])) {
} elseif ($line[0] == '#') { $this->item->error[] = $lineNumber; } elseif ($line[0] == ';') `
I can not test at PHP 8.0, maybe JM can. We need simply be sure than your suggestion also is working on PHP 7
@fontanil Have you installed the beta6 pack I provided above? #42 (comment) I do not get that error here with php8.
Yes, JM
@fontanil In the end we are going to get your part of a born coder!! :D
I don't understand why the strings in Text.php are in English, as I am trying to translate into French. I deleted all commas from the French string and get the error (for com_ats.ini) @Valc No, I'm just tenacious. ;)
No, I'm just tenacious. ;)
I don't understand why the strings in Text.php are in English, as I am trying to translate into French. I deleted all commas from the French string and get the error (for com_ats.ini)
That is not the problem, is "API maters", so, no worry.
Bakual sure bring light due he have the knowknowledge of the whole cycle, or very close to the whole cycle.
I tried with PHP 7.4, no error for the "line[0]" correction
Why is it the reference value, in English, that causes an error when recording this translated value?
Why is it the reference value, in English, that causes an error when recording this translated value?
Due the language loaded by "use Text", at the moment, is in English. So, the parse is on en-GB strings.
The error message that was posted was
Warning: vsprintf(): Too few arguments in /var/www/html/ft/libraries/src/Language/Text.php on line 123
object(SimpleXMLElement)#8090 (1) { [0]=> string(193) "COM_LOCALISE_NOTICE_GITHUB_FILE_ADDED
A new file <strong>%1$s</strong> present in the Github %2$s branch, has been added to the local %3$s/language/en-GB folder." }
As you see, there was a SimpleXMLElement object here, containing a string COM_LOCALISE_NOTICE_GITHUB_FILE_ADDED A new file <strong>%1$s</strong> present in the Github %2$s branch, has been added to the local %3$s/language/en-GB folder.
But Text::_()
never expects such a string or object. It only expects COM_LOCALISE_NOTICE_GITHUB_FILE_ADDED
as string.
So for something in comlocalise does call `Text::()` with a SimpleXMLElement instead of the language key. That is your issue.
The error you then see is just a symptom of it. Text::_()
can handle a special case where you would call it like Text::_('SOME_KEY, value1, value2')
and it would then run a sprintf with those values. This is no issue if you only pass the language key, as that one never has a comma in it. But if you as well pass the language source string, then it of course may contain a comma and it tries to run it through sprintf which then fails.
As I don't know how com_localise works in detail, I can't say where that happens. I did some searching through the code but couldn't find an obvious place. So you need so look at the stacktrace where your error happens. That will give you a clue.
Ok, Thank you @Bakual :)
i have changed a bit more the passSprintf code to help to understand what is happening:
/**
* Checks the string if it should be interpreted as sprintf and runs sprintf over it.
*
* @param string &$string The string to translate.
* @param mixed $jsSafe Boolean: Make the result javascript safe.
* @param boolean $interpretBackSlashes To interpret backslashes (\\=\, \n=carriage return, \t=tabulation)
* @param boolean $script To indicate that the string will be push in the javascript language store
*
* @return boolean Whether the string be interpreted as sprintf
*
* @since 3.4.4
*/
private static function passSprintf(&$string, $jsSafe = false, $interpretBackSlashes = true, $script = false)
{
// Check if $string is comming as html output
if (preg_match("'<strong>(.*?)</strong><br>'", $string, $matches))
{
// Uncomment to test the case tiggering system messages without call Text::_()
$message = 'passSprintf as HTML output catched<br>' . htmlspecialchars($string);
Factory::getApplication()->enqueueMessage($message, 'warning');
$string = str_replace($matches[0], '', $string);
$issued_input = true;
}
else
{
$issued_input = false;
}
// Check if string contains a comma
if (strpos($string, ',') === false)
{
return false;
}
$lang = Factory::getLanguage();
$string_parts = explode(',', $string);
// Pass all parts through the Text translator
foreach ($string_parts as $i => $str)
{
$string_parts[$i] = $lang->_($str, $jsSafe, $interpretBackSlashes);
}
if ($issued_input)
{
// Trying to emulate than we take off "the key" when realy we now here there was not a key before the first comma.
$first_part = $string_parts[0];
array_shift($string_parts);
}
else
{
$first_part = array_shift($string_parts);
}
// Replace custom named placeholders with sprintf style placeholders
$first_part = preg_replace('/\[\[%([0-9]+):[^\]]*\]\]/', '%\1$s', $first_part);
// Check if string contains sprintf placeholders
if (!preg_match('/%([0-9]+\$)?s/', $first_part))
{
return false;
}
$final_string = vsprintf($first_part, $string_parts);
if (!$final_string && $issued_input)
{
$message = 'passSprintf returning false <b>with</b> the issued HTML input<br>'
. $string
. '<br>String parts= '
. count($string_parts)
. '<br>First part= '
. $first_part;
Factory::getApplication()->enqueueMessage($message, 'error');
}
else if (!$final_string && !$issued_input)
{
$message = 'passSprintf returning false <b>without</b> the issued HTML input<br>' . $string;
Factory::getApplication()->enqueueMessage($message, 'error');
}
// Return false if string hasn't changed
if ($first_part === $final_string)
{
return false;
}
$string = $final_string;
if ($script)
{
foreach ($string_parts as $i => $str)
{
static::$strings[$str] = $string_parts[$i];
}
}
return true;
}
Now can display this output when "save"
In our case is passing a full HTML output for all keys within the language file to save.
I has been also searching through the code but couldn't find an obvious place to allow this one. I will continue searching a bit more tomorrow. If you think is at com_localise code, i belive you XD
The "preprocessForm" at our TranslationModel.php file is adding the "strong" HTML tags to the keys and the "br" and handling a simple XML object there..
but how is posible than doing that to show the view with the required style can to end mixing calls to language files to load by the system with forms to display within a view??, in our case, of course, a form with language keys and strings to handle.
Found when this code was implemented for 3.4.4 (September 2015). The reason was totally different than what I thought.
https://github.com/joomla/joomla-cms/pull/6581
It looks legit to me, at least for php <=7.x
@regularlabs Could it be that this code has to be modified for php 8 as it is more strict?
Again: This code is not the reason for the error. You're chasing a ghost 😄
You need to find out why on eart the english sourcestring appears at that point. It should only be the language key, no real text.
The language strings are loaded after that part, so translations and english fallback are not yet available at this point. Which means they are passed into Text::_()
which is completely wrong and the reason for your issue.
A Stacktrace would help here.
Ok, I found the issue. The source is the "Strings" tab in the edit view Note that the english sourcetext is part of the label (and may contain commas).
Now when you save the form, Joomla will try to translate the field label within Form::validate() and there this breaks as that label contains a comma.
Note that the english sourcetext is part of the label (and may contain commas).
Hi, @Bakual:
That one is our label, and the "field" is at the right side. Our label html output is "<strong>key</strong><br>string
"
We are not calling from our code "Text::_($label)
" or similar cases in any way.
If we separare the "string" from the key, then our label will be: "<strong>A_KEY_TO_SHOW_AS_REFERENCE</strong><br>
"
And in this way, if is as you say, Form::validate() will try to validate the label again, of course, this time without error due no "commas"...
.. but HTML? Is required attempt to "Text::(<strong>A_KEY_TO_SHOW_AS_REFERENCE</strong><br>)"
and then passSprintf under "fake keys" or "key to no call" or "keys than need to be displayed without apply JText there"?
Did you mean than if we use as label only "A_KEY_TO_SHOW_AS_REFERENCE", without string, without html, etc.. it will be translated at our translation view? due this one is not the expected result we have programed.
So, again and thank you for your patience :) :
If you don't want to call it a failure in the current code to try to translate things that should not be translated, could we agree that "returning false" for things that obviously are not a key to translate could be improved from that code?
For example, from passSprintf:
$the_case = "THIS_ONE_IS_A_VALID_KEY_THAN_WE_CALL_BY_VAR_NAME_STRING";
if (htmlspecialchars($the_case) !== $the_case)
{
return false;
}
else if (!is_string($the_case))
{
return false;
}
elseif (preg_match('/^*=(\s*(("[^"]*")|(_QQ_)))+))\s*(;.*)?$/', $the_case))
{
return false;
}
else if (strpos($string, ',') === false)
{
return false;
}
Also, some fields can have the param "transladable" or not, and no idea if is posible add there something by xml declaration similar to transladable="false";
to help avoiding this cases.
Or maybe already exists a label or description class type "ignore-me-please" to use.
@infograf768 @Bakual
Now with a bit more modified Text file i have moved the body by:
/administrator/index.php?option=com_installer&view=updatesites
And those also does not seems single keys 8) ( i think there was an issue opened about it, not remember were, so, maybe can help there) It is our<description><![CDATA[text here as detail]]></description>
Used code
private static function passSprintf(&$string, $jsSafe = false, $interpretBackSlashes = true, $script = false)
{
if (htmlspecialchars($string) !== $string)
{
$message = 'passSprintf as HTML output catched and returning false<br>' . htmlspecialchars($string);
Factory::getApplication()->enqueueMessage($message, 'notice');
return false;
}
// Check if $string is comming as html output
if (preg_match("'<strong>(.*?)</strong><br>'", $string, $matches))
{
// Uncomment to test the case tiggering system messages without call Text::_()
$message = 'passSprintf as HTML output catched<br>' . htmlspecialchars($string);
Factory::getApplication()->enqueueMessage($message, 'warning');
$string = str_replace($matches[0], '', $string);
$issued_input = true;
}
else
{
$issued_input = false;
}
// Check if string contains a comma
if (strpos($string, ',') === false)
{
return false;
}
$lang = Factory::getLanguage();
if ($issued_input)
{
//die(var_dump($lang));
}
$string_parts = explode(',', $string);
// Pass all parts through the Text translator
foreach ($string_parts as $i => $str)
{
$string_parts[$i] = $lang->_($str, $jsSafe, $interpretBackSlashes);
}
if ($issued_input)
{
// Trying to emulate than we take off "the key" when realy we now here there was not a key before the first comma.
$first_part = $string_parts[0];
array_shift($string_parts);
}
else
{
$first_part = array_shift($string_parts);
}
// Replace custom named placeholders with sprintf style placeholders
$first_part = preg_replace('/\[\[%([0-9]+):[^\]]*\]\]/', '%\1$s', $first_part);
// Check if string contains sprintf placeholders
if (!preg_match('/%([0-9]+\$)?s/', $first_part))
{
return false;
}
$final_string = vsprintf($first_part, $string_parts);
if (!$final_string && $issued_input)
{
$message = 'passSprintf returning false <b>with</b> the issued HTML input<br>'
. $string
. '<br>String parts= '
. count($string_parts)
. '<br>First part= '
. $first_part;
Factory::getApplication()->enqueueMessage($message, 'error');
}
else if (!$final_string && !$issued_input)
{
$message = 'passSprintf returning false <b>without</b> the issued HTML input<br>' . $string;
Factory::getApplication()->enqueueMessage($message, 'error');
}
// Return false if string hasn't changed
if ($first_part === $final_string)
{
return false;
}
$string = $final_string;
if ($script)
{
foreach ($string_parts as $i => $str)
{
static::$strings[$str] = $string_parts[$i];
}
}
return true;
}
I've created a PR for core which allows to disable the translating of the field label. Same as we already can when displaying the field label.
If that PR is accepted, you can add the line $field->addAttribute('translateLabel', 'false');
after https://github.com/infograf768/j4localise/blob/68201ae84d8005c1b43e2abc9acfd9004acd6efd/administrator/components/com_localise/Model/TranslationModel.php#L985
That should do the trick as the form no longer uselessly tries to translate each field label.
I've created a PR for core which allows to disable the translating of the field label. Same as we already can when displaying the field label.
If that PR is accepted, you can add the line
$field->addAttribute('translateLabel', 'false');
afterThat should do the trick as the form no longer uselessly tries to translate each field label.
You rocks! :P
Another approach would be to add the english sourcetext only during display (eg by using a custom formfield or layout override) instead of polluting the whole formfield label with it. If the text is not part of the field label, it would fix things as well.
The core PR by @Bakual is here: https://github.com/joomla/joomla-cms/pull/35900
@Bakual PR (which is anyway a nice improvement to core), combined with using translateLabel in com_localise works great.
@Valc If you see a way to implement https://github.com/infograf768/j4localise/issues/42#issuecomment-951206525 then we would be even more independent.
@Bakual PR (which is anyway a nice improvement to core), combined with using translateLabel in com_localise works great.
@Valc If you see a way to implement #42 (comment) then we would be even more independent.
@Bakual Thank you!
@infograf768
Note than that #42 (comment) i think is a workarround that surely no log errors but that does not skip "check unrequired fake html encoded keys to display".
The Bakuals' PR is a direct core solution to the issue that does not lost time processing that ones (all our "labels" when we edit: imagine the joomla.ini file).
As Thomas patch is likely not to be added in next J4 release. I guess we would have until then to limit com_localise use to php < 8 .
BTW, we have evidently the same problem with php8 and the com_localise 4.0.38-dev version. (Forget the 4.10 version which is a fake...)
@infograf768 also, about the @fontanil issue with PHP 8, maybe we need to open a new PR based on the code he suggest as first comment, due i am a bit lost with this large issue XD
https://github.com/infograf768/j4localise/issues/42#issuecomment-950346165
As Thomas patch is likely not to be added in next J4 release. I guess we would have until then to limit com_localise use to php < 8 .
It seems the right option at the moment.
Job time now :)
I can't reproduce @fontanil issue at all in php 7.4 or php 8. In any browser.
Also our code does take into account any other value than #
and ;
and absence of value for $line[0]
line 484 by
}
else
{
break;
}
I'm lost about that.
I can't reproduce @fontanil issue at all in php 7.4 or php 8. In any browser. Also our code does take into account any other value than
#
and;
and absence of value for$line[0]
line 484 by} else { break; }
I'm lost about that.
I think that part of the code is only focused to get the header data about "Author", "Copyright", etc than later is used to create or display that info when we load a language file "Details" tab:
If present there, is used and if not we get the configured by "Options".
The code is expecting found a ";" as char 0 of the $line
So $line[0] is catching the firts char from the actual line and if the line start by ";" then search "Details", and if not, "break" to continue to the next line.
Seems than "#" is not an invalid char to use to comment lines, and simply seems is not suggested use it as a right formated "commented" ini files. So, If catched, is handled as "error".
About the @fontanil issue if is just at PHP 8 i think the Joomla Project will apply some changes when required to adjust the stuff to the "news", due maybe now is due the core is still not ready to PHP 8.
I can not reproduce the issue and i can not understand why is required call to the "char 0" by "var name", before, from PHP, was allowed do $line{0} and today is depeciated.. so, no idea. If not now sure we catch later :)
Note:
for #
, it is a legacy thing. it just deals with 1.5 language files which were starting with #
and with a different format;)
Example:
# $Id: fr-FR.com_banners.ini 1.5.10 2009-03-14 12:55:10 humvee ~3 $
# author French translation team : Joomla!fr
# copyright (C) 2005 - 2010 Joomla.fr & Open Source Matters. All rights reserved.
# license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
# Note : All ini files need to be saved as UTF-8
BANNER=Bannière
BANNER CLIENT=Client de la bannière
Note: for
#
, it is a legacy thing. it just deals with 1.5 language files which were starting with#
and with a different format;) Example:# $Id: fr-FR.com_banners.ini 1.5.10 2009-03-14 12:55:10 humvee ~3 $ # author French translation team : Joomla!fr # copyright (C) 2005 - 2010 Joomla.fr & Open Source Matters. All rights reserved. # license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL # Note : All ini files need to be saved as UTF-8 BANNER=Bannière BANNER CLIENT=Client de la bannière
So, seems than actualy the code if catch the symbol "#" as first char will be triggered as "error". Maybe we can test what happens adding some of them at the header lines as first char.
If not mandatory trigger it as errors, so, can to be removed try to catch it as wrong from the code.
As I said previously, PHP 8 returns an error with line[0] when the line is empty, and the error displays the first text I reported. I don't think there is any link to the other problem with commas.
Empty lines i think are handled from other code lines block below, so, i think we can not skip them.
But you can try the next one than i think can not crash next code matching with empty lines if present:
while (!$stream->eof())
{
$line = $stream->gets();
$lineNumber++;
if (!empty($line) && $line[0] == '#')
{
$this->item->error[] = $lineNumber;
}
elseif (!empty($line) && $line[0] == ';')
{
I'm speaking about this error message in the listing page of translation files administrator/components/com_localise/Model/TranslationModel.php on line 317 (and line 321)
I'm speaking about this error message in the listing page of translation files administrator/components/com_localise/Model/TranslationModel.php on line 317 (and line 321)
Yes. What code lines have you there?
if ($line[0] == '#')
{
$this->item->error[] = $lineNumber;
}
elseif ($line[0] == ';')
I proposed to check if line[0] is empty and you added it in the code you quoted there__ Sorry, I wasn't very well awake earlier
As @Bakual PR has been merged I will now directly add the $field->addAttribute('translateLabel', 'false');
line in com_localise. It will not break php7 and will solve php8 for J4 next version.
@fontanil
line[0]
is never empty. If there are no comments starting with ;
then there are 2 possibilities (let's forget '#'), both are not boolean.
line[0]
is equal to a space, i.e. " "2 . The first line is a string
line[0]
= the first letter of the line constant i.e. "A" for example.
It is possible though that there is a problem with the end of file (eof) of one of your inis. In this case we could get a NULL because $stream
would be wrong.
The only way to test is to edit one ini at a time after adding a var_dump line 316:
while (!$stream->eof())
{
$line = $stream->gets();
$lineNumber++;
var_dump($line[0]); //add this line
if ($line[0] == '#')
{
$this->item->error[] = $lineNumber;
}
elseif ($line[0] == ';')
{
Commit is here: https://github.com/infograf768/j4localise/commit/d88c552009f258a80efa253e20c7140ba74d663c
Thanks @Bakual
Sorry JM, but line[0] is empty on some lines and then an error occurs with PHP 8
@infograf768
https://downloads.joomla.org/technical-requirements
Seem Joomla 4 is PHP 8 Recommended
I will take a look to mount at my descktop PC a test server this weekend if i have time.
Also a link about PHP 8 issues comming from previous versions.
@infograf768 @fontanil
Now i am testing on PHP 8.0.12 with debug and error reporting to maximum using the beta 6 package than JM have here:
https://github.com/infograf768/j4localise/issues/42#issuecomment-950283532
With the last one added to our pack:
https://github.com/infograf768/j4localise/issues/42#issuecomment-955159282
Also with the Bakuals' PR added to Joomla core files:
https://github.com/joomla/joomla-cms/pull/35900.
Due if not, the same issue that at PHP 7 was simply triggering a log warning, at PHP 8 make a crash than is not possible continue working with com_localise files edition in normal mode.
But, one time the previous issue due "blindly try to translate the formfield label" is solved, i can not reproduce the issue related with $line[0]
: no warnings, no log messages, nothing.
I think we need more testers due surely the issue is there, but if it is invisible for us seems there is no way to continue.
Please try this code ` while (!$stream->eof()) { $line = $stream->gets(); $lineNumber++; if(empty($line[0])) {
} else
if ($line[0] == '#')
{
$this->item->error[] = $lineNumber;
}
elseif ($line[0] == ';')`
On my test site, PHP 8.0.8, no more error for line[0]
@fontanil I think we can solve adding that patch, but also is possible than this one is a PHP 8 bug than they have solved at the PHP released version i have installed. Note than they also have bugs to fix:
https://www.php.net/ChangeLog-8.php
It is possible you test under the last PHP 8 version?
Share the block of code, please. Due does not have to many sense try an "if (empty($line[0]))" to do nothing.
With PHP 8.0.12 on Wampserver 64, without my changes: "Warning: Trying to access array offset on value of type bool in D:\wamp64\www\admtools\administrator\components\com_localise\Model\TranslationModel.php on line 319" No more error with the code I quoted.
And with the next code lines you have the warning??
while (!$stream->eof())
{
$line = $stream->gets();
$lineNumber++;
if (!empty($line) && $line[0] == '#')
{
$this->item->error[] = $lineNumber;
}
elseif (!empty($line) && $line[0] == ';')
{
No error with this code, as it is quite the same of mine. ;) As I said some comments higher: "I proposed to check if line[0] is empty and you added it in the code you quoted there__"
Please, also test the next code than have an "if empty" doing something :D
while (!$stream->eof())
{
$line = $stream->gets();
$lineNumber++;
if (empty($line))
{
die("The line number $lineNumber is empty and the line[0] have the $line[0] value");
}
elseif ($line[0] == '#')
{
$this->item->error[] = $lineNumber;
}
elseif ($line[0] == ';')
{
Warning: Trying to access array offset on value of type bool in D:\wamp64\www\admtools\administrator\components\com_localise\Model\TranslationModel.php on line 319
"The line number 1 is empty and the line[0] have the value
line[0] is empty so you can't display "the $line[0] value"
Hi I'm trying to translate Akeeba Tickets System (com_ats.ini admin side) and I can't save the file, I get this message:
0 The arguments array must contain 2 items, 1 given
Debug and error reporting to maximum, there is one error when I open the list of filesadministrator/components/com_localise/Model/TranslationModel.php on line 317 (and line 321)
I had no error with com_ats.sys.ini file. Regards, fontanilLocalise 5.0.0 beta 5 PHP 8.0.10