Defects in English language files

未关闭
#5,366 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
3/5
预计耗时
1-2 天
新手友好度
55/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
冷清
技术栈
php

调研方向

Start with system/ee/language/english/expressionengine_info_lang.php line 27 and its call site in system/ee/ExpressionEngine/Controller/Settings/General.php line 336, where %i makes sprintf throw on PHP 8. Then check the channel_form_lang.php validation strings against Form_validation.php, and the sig_too_big string in member_lang.php. Done means each listed sprintf call runs without a ValueError and renders the expected text. Coordinate with maintainers on which of the many listed items to take first.

由索引模型根据 Issue 内容生成。

描述

ExpressionEngine 7.5.26 - Defects in English language files

Reported by: Slovak translation maintainer
Version audited: ExpressionEngine 7.5.26 (unmodified) + Forum 5.1.3, IP to Nation 3.0.0, Simple Commerce 2.2.1
Verified on: PHP 8.1.6
Scope: 74 English *_lang.php files (9,831 keys) cross-referenced against 2,708 PHP/HTML source files.


How this was found

While maintaining the Slovak translation I compared every English language string against its actual consumption in the codebase. Each key containing a placeholder was traced to its lang() / ee()->lang->line() call sites and classified by the substitution mechanism used there.

This surfaced a class of defects that a translator hits immediately but that is invisible when reading the language files alone: ExpressionEngine uses two unrelated placeholder conventions, and a handful of strings use the wrong one for their call site.

Convention Mechanism Example call site
%s, %d sprintf() sprintf(lang('key'), $val)
%x, %y, %n, %time%, %max%, %overflow_names% str_replace() str_replace('%x', $val, lang('key'))

For the record: %x is legitimate in EE and must not be "corrected" to %s. Of 34 %x occurrences, 26 are correctly consumed by str_replace, 7 are in dead keys, and exactly 1 is a genuine bug (§2.1).

All findings below were reproduced by executing the relevant sprintf calls with representative arguments.


1. Critical - fatal errors on PHP 8

1.1 version_update_inst - ValueError, breaks Settings › General

String: system/ee/language/english/expressionengine_info_lang.php:27

'version_update_inst' => '<a class="update" href="%d" title="Download Here" rel="external">Download the latest version</a> and follow the <a class="update" href="%i" title="Update Instructions" rel="external">Update Instructions</a>.',

Call site: system/ee/ExpressionEngine/Controller/Settings/General.php:336

$banner->addToBody(sprintf(lang('version_update_inst'), $upgrade_url, $instruct_url));

Two defects:

  1. %i is not a valid PHP format specifier. On PHP 8 sprintf() throws:
    ValueError: Unknown format specifier "i"
    
  2. %d casts its argument to integer. A URL string becomes 0, producing href="0".

Reproduction:

sprintf(
    '<a href="%d">Download</a> and <a href="%i">Instructions</a>',
    'https://expressionengine.com/download',
    'https://docs.expressionengine.com/update'
);
// PHP 8.1.6 → ValueError: Unknown format specifier "i"

Impact: Any user visiting Settings › General while an update is available gets a fatal error instead of the update banner. On PHP 7 the page rendered but with a broken download link (href="0").

Suggested fix: use %s for both placeholders.


1.2 channel_form_lang.php - four validation strings expect 2 arguments, receive 1

Strings: system/ee/language/english/channel_form_lang.php

Line Key Value
24 exact_length The %s field must be exactly %s characters in length.
38 matches The %s field does not match the %s field.
40 max_length The %s field cannot exceed %s characters in length.
42 min_length The %s field must be at least %s characters in length.

Call sites: system/ee/legacy/libraries/Form_validation.php

// line 815 - one argument (field label)
$message = sprintf($line, $this->_translate_fieldname($row['label']));

// line 951 - one argument (rule parameter)
$message = sprintf($line, $param);

Form_validation never passes more than one argument. On PHP 8:

ValueError: The arguments array must contain 2 items, 1 given

Compounding issue - key collision. The same four keys also exist in system/ee/language/english/form_validation_lang.php (lines 19, 47, 49, 51) with the correct single-placeholder form:

'max_length' => 'This field cannot exceed %s characters in length.',

Whichever file is loaded last wins, so the failure is load-order dependent and therefore intermittent across contexts. Form_validation.php:1146 explicitly loads form_validation, which usually masks the problem - but any code path that loads channel_form afterwards will crash.

Suggested fix: drop the leading The %s field from the channel_form_lang.php variants, or remove the duplicated keys entirely and rely on form_validation_lang.php.


2. Incorrect output

2.1 sig_too_big - number rendered as hexadecimal

String: system/ee/language/english/member_lang.php:545

'sig_too_big' => 'Signatures can only contain %x characters',

Call site: system/ee/ExpressionEngine/Addons/member/mod.member_images.php:107

sprintf(lang('sig_too_big'), $maxlength)

This is the one place where %x reaches sprintf instead of str_replace. %x is lowercase hexadecimal, so:

sprintf('Signatures can only contain %x characters', 10000);
// → "Signatures can only contain 2710 characters"

Impact: users are told a wrong, much smaller-looking limit. With the default sig_maxlength of 10000 the message reads "2710 characters".

Suggested fix: change %x to %s in the string (the call site already uses sprintf consistently with the rest of the file).


2.2 less_than - key collision corrupts relative dates

Defined twice with unrelated meanings:

File Line Value
system/ee/language/english/core_lang.php 237 less than
system/ee/language/english/form_validation_lang.php 41 This field must be less than: %s

Consumer: system/ee/legacy/libraries/Relative_date.php:43

$this->less_than = lang('less_than');

Relative_date wants the core_lang value to build strings like "less than a minute ago". If form_validation_lang.php has been loaded, the output becomes:

This field must be less than: %s a minute ago

Suggested fix: rename one of them (e.g. validation_less_than).


2.3 running_current - %v is never substituted

String: system/ee/language/english/expressionengine_info_lang.php:19

'running_current' => 'ExpressionEngine is up to date (%v)',

Call site: system/ee/ExpressionEngine/Controller/Settings/General.php:347

->withTitle(lang('running_current'))

No sprintf, no str_replace. The literal %v is shown to the user. The very next line handles the sibling string correctly:

->addToBody(sprintf(lang('running_current_desc'), APP_VER))

Suggested fix: either wrap the title in sprintf(..., APP_VER) and change %v to %s, or drop the placeholder from the string.


3. Missing language keys

Key Called from Notes
search_reindex_completed system/ee/ExpressionEngine/Service/Channel/Reindex.php:195 Typo in the code. search_reindexed_completed exists at utilities_lang.php:553 (Content reindexing complete. %s entries were reindexed.) and already carries the %s this call passes.
removed_role system/ee/ExpressionEngine/Controller/Members/Roles/Roles.php:2006 Not defined anywhere. sprintf(lang('removed_role'), '<b>'.$role_name.'</b>') writes the literal string removed_role into the CP action log.

4. Values passed by code but discarded by the string

The call site supplies data the English string has no placeholder for, so the information is silently dropped.

Key Language file Call site Discarded value
file_saved admin_lang.php:389 Controller/Utilities/Translate.php:479 destination path
rows_replaced admin_lang.php:753, tools_data_lang.php Controller/Utilities/Sandr.php:63 number of replacements
imglib_unsafe_config image_lib_lang.php:25 legacy/libraries/Image_lib.php:685 offending path
forum_board_removed_desc forum/…/forum_cp_lang.php:383 user/addons/forum/mcp.forum.php:1223 forum name
access_privilege_caution members_lang.php:482 Controller/Members/Profile/Roles.php:87 icon markup (already hardcoded in the string)
rel_ft_limit fieldtypes_lang.php:66 Addons/relationship/ft.relationship.php:709 second argument (string has one %s, two are passed)

Worth noting that utilities_lang.php already has the correct variants - file_saved at line 119 (The translation file has been saved to <b>%s</b>) and rows_replaced at line 205 (… occurred: %s). The duplicates in admin_lang.php and tools_data_lang.php are the stale ones.


5. Dead keys containing placeholders

Not referenced anywhere in the codebase. Listed because they mislead translators into preserving placeholders in strings that will never render.

Key File Placeholder
unreadable_language installer_lang.php:97 %x
click_to_recount admin_lang.php %x, %y
system_path admin_lang.php %x
auto_redirection core_lang.php %x
page_rendered cp_lang.php %x
queries_executed cp_lang.php %x
if_replacing_templates tools_data_lang.php %x
entry_title_with_title content_lang.php %title

6. Duplicate keys across files

431 keys are defined in more than one English language file with differing values. Resolution depends on load order, which makes the effective string context-dependent.

27 of these are risky - one variant carries a placeholder and another does not, so depending on load order either a value is dropped or sprintf raises ArgumentCountError / ValueError on PHP 8.

Highest-impact clusters:

  • channel_form_lang.php × form_validation_lang.php - 13 validation keys (required, numeric, integer, alpha, alpha_dash, alpha_numeric, is_natural, is_natural_no_zero, is_numeric, valid_email, exact_length, max_length, min_length, matches)
  • admin_lang.php × utilities_lang.php × tools_data_lang.php - file_saved, rows_replaced, total_results
  • addons_lang.php × rte_lang.php - settings_saved_desc

7. Spelling and markup errors in English strings

File Key Current Should be
installer_lang.php:100 unreadable_dbdriver sytem/ee/installer/schema/ system/…
installer_lang.php:103 update_step_error occured occurred
admin_lang.php:145 analize Analize Tables - the key itself is misspelled too analyze / Analyze Tables
admin_lang.php:551 not_writable_path writeable writable
cp_lang.php:432 not_writable_path writeable writable
members_lang.php:346 not_writable_path writeable writable
tools_lang.php:75 trans_file_not_writable writeable writable
utilities_lang.php:129 trans_file_not_writable writeable writable
members_lang.php:438 your_password_anonymize_members_desc anomymize anonymize
upload_lang.php:15 upload_invalid_dimensions exceedes exceeds
core_lang.php:166 php72_intl_error extentsion extension
cp_lang.php:895 text_icon Text file iconn icon
sites_lang.php:31 invalid_short_name underscroes underscores
cli_lang.php:257 command_make_fieldtype_building_fieldtype Building fieldype. fieldtype
cli_lang.php:493 command_sync_conditional_fields_summary connditional conditional
ip_to_nation_lang.php:35 ip_db_failed IP databse update failed database

Unbalanced HTML - a stray </em> with no opening tag, which leaks into the rendered page:

  • system/user/addons/forum/language/english/forum_cp_lang.php:247 - reply_notification_desc
    … when a <b>new</b> reply is made.</em><em>Separate multiple e-mails …
    
  • system/user/addons/ip_to_nation/language/english/ip_to_nation_lang.php:63 - update_info
    … rel="external">maxmind.com</a>.</em><em><i>The new data will …
    

Summary by severity

Severity Count Items
Critical (fatal on PHP 8) 2 §1.1 version_update_inst, §1.2 channel_form_lang.php ×4 keys
High (wrong output shown to users) 3 §2.1 sig_too_big, §2.2 less_than, §2.3 running_current
Medium (missing keys / lost data) 8 §3 ×2, §4 ×6
Low (dead keys, duplicates, spelling) 24+ §5 ×8, §6, §7 ×16

Notes for other translators

Three things that are easy to get wrong when translating EE and are worth documenting upstream:

  1. %x, %y, %n and %name% tokens are not sprintf placeholders. They must be preserved verbatim; substituting %s breaks them. Only %s and %d go through sprintf.
  2. Validation strings should carry exactly one %s. Form_validation always passes a single argument.
  3. Where the English string is missing a placeholder that the code supplies (§4), a translation may legitimately add %s - the Slovak files already do this for file_saved and rows_replaced, matching utilities_lang.php rather than the stale admin_lang.php copies.
主要语言
PHP
星标
505
派生
135
平均合并
3 天 7 小时
30 天内合并 PR
7

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

ExpressionEngine/ExpressionEngine 的其他 Issue

查看 ExpressionEngine/ExpressionEngine 的全部 Issue

相似的 Issue

更多 PHP Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。