FAQ: Why do I get ArgumentCountError
/ ValueError
when upgrading PHP?
Incorrectly formatted strings can cause fatal errors under PHP 8.
This is likely to be a mistake in the translation, rather than in anyone's code.
If you get fatal errors after upgrading from PHP 7 to PHP 8, check your error logs for messages like these:
Fatal error: Uncaught ArgumentCountError: 2 arguments are required, 1 given
Fatal error: Uncaught ValueError: Unknown format specifier ...
These errors are likely to be caused by incorrectly formatted translations that have been passed to PHP's printf function (or similar). That means you could experience this issue even if your theme and plugins are 100% compatible with PHP 8.
We won't repeat the WordPress documentation on formatting translations but we'll explain the two most common mistakes that can crash your website and leave you thinking there's a bug in the code, when in fact it's a bug in the translations.
ArgumentCountError
: Too few arguments
Suppose a source string looks like this inside the Loco Translate editor:
<span class="%1$s">Published</span> %2$s
This string has two placeholders (%s
). We say that the string accepts two arguments. In this example the first argument is a CSS class; the second is a formatted date.
They're numbered 1 and 2 here, so the intended order is clear and may be swapped if needed in another language.
If your translation doesn't also have two placeholders then it's incorrectly formatted. PHP will forgive you for using fewer placeholders, but if you add too many then the code that renders the string will throw an error for supplying too few arguments.
Here's an example of a translation that will break your website under PHP 8 if it receives two arguments:
<span class="%1$s">Veröffentlicht</span> <time datetime="%2$s">%3$s</time>
Our imaginary translator has decided to use the date argument twice, but they've done it wrongly. Instead of repeating the second placeholder, they've created a string that now accepts a minimum of three arguments. Under PHP 8 this will cause a fatal error when it's printed on screen.
ValueError
: Unknown format specifier
A fatal error will also be raised by PHP 8 if an otherwise valid formatting pattern contains an unknown type specifier.
The type in our example above is "s"
(string) which is the simplest type possible and the most commonly used in translations.
The following accidental use of a capital "S"
would result in a fatal error when it's printed on screen:
<span class="%1$s">Veröffentlicht</span> %$2$S
A simple mistake with a serious consequence, and one which may lie silently in wait for a long time before you notice.
ValueError
: Missing format specifier
This is similar to the unknown specifier error, except it's triggered when no type specifier follows the "%"
symbol. As such it can only happen at the end of a string.
This is common when a translator ignores the "s"
when copying the source text, assuming that only the "%"
is operative. For example: "Template for %s"
→ "Template für %"
.
Why was everything fine before I upgraded PHP?
Because PHP 8 is stricter about this kind of mistake than PHP 7. The mistake may have always been there, but you didn't notice because it didn't break your website.
For example, under PHP 7.4 you will get just a warning in log files, such as "sprintf(): Too few arguments"
, or possibly no message at all.
Unknown format specifiers were simply ignored before PHP 8.
I didn't enter any bad formatting! How do I fix it?
If a wrongly formatted translation wasn't your doing, then it was either shipped by the author, installed from GlotPress or possibly produced by a machine translation service. Loco Translate doesn't automatically fix broken formatting, but it will warn you.
To fix formatting errors you'll have to establish which file is storing the offending string:
- If it's from an installed file, then you should copy the file to override the translations and correct any bad strings that you find.
- If the bad formatting is coming from an auto-translation service, then you should correct the formatting before saving the translations in the editor.
How can I find which string is causing fatal errors?
Your first line of enquiry should always be your error logs. Look for fatal errors that are thrown from the printf
or sprintf
functions.
If you can't find any then this may not be the cause of your error, or your error logging may not be set up properly.
Ensure that fatal errors are logging full stack traces and that the traces show the arguments being passed to each function call. This should reveal any wrongly formatted strings being passed to the PHP functions.
Tip:
zend.exception_ignore_args
should be off in order to see translation text in stack traces.
If the text is cut short, try increasing the value ofzend.exception_string_param_max_len
.
Ask your hosting provider if you need help configuring verbose logging.
But my translation looks exactly like the source string, and it still crashes
It's possible that the source string is wrong.
If the theme/plugin author has only tested their code under PHP 7.4 or below then they may not know about the error. Look at their code to see if the correct number of arguments is being used to format the translated string. Contact them if you don't know how to do this.
You can still correct the translation when the source is wrong, but if you're not familiar with printf
then ask on a general WordPress or PHP forum for help.
It's a bug in Loco Translate. There's a problem with PHP compatibility
Formatting errors like these are not bugs or "conflicts" in Loco Translate. The latest version of the plugin supports the same versions of PHP as the latest version of WordPress. We will always endeavour to achieve this level of forward and backward compatibility.
If you can find a genuine PHP compatibility problem, please report it along with a full stack trace showing errors originating from our plugin code.
RTL languages
It's worth mentioning that editing right-to-left languages (such as Arabic and Hebrew) makes copying code elements from English source strings somewhat complicated.
Text direction during editing and rendering is handled by your browser's bidirectional text capability. This means that translated text can be mixed in with latin characters and code elements (such as HTML and printf
formatting) and may visually change direction multiple times. The code elements in the final translation may look very different to the source version, but actually be correct. You may see "s%"
in the editor, but the bytes in the string may actually be %, s.
It's important to understand that PHP functions like printf
don't know about text direction. They simply take a sequence of bytes in a fixed order.
If this isn't the order they appear in your translation editor, that's probably fine. Don't try to visually emulate the source text, because you may end up reversing the bytes.
If you need examples of this done properly, examine the WordPress community translations. e.g. Arabic / Hebrew.
Warnings in the editor
Loco Translate validates string formatting from within the editor. Any translations with validation errors will show a warning icon in the list pane and a brief description of the error in the translation pane.
Note that invalid formatting can be ignored if the string is not intended to be formatted. i.e. if the code author is not using printf (or similar) when displaying the translation.
Loco Translate doesn't know whether a string should be formatted unless the code author has flagged it. In the absence of this flag, Loco Translate automatically detects string formatting in the source string. If the source string looks valid, then the translation will be validated too. This carries a risk of false positives. For example the string "20% off"
is actually valid printf
syntax, even though it probably isn't intended to be. The code author should annotate this string with /* xgettext:no-php-format */
to disable syntax validation.
Watch out for automatic translation services producing invalid string formatting. We've found that printf
syntax tends to be treated as general punctuation and left intact by most providers, but we've also seen reformatting occur. For example "%s"
may become "% s"
(which is fortunately valid) but "% S"
or "% Σ"
would not be. Loco Translate will warn you, but it won't fix the string for you.