mirror of
https://github.com/FreshRSS/FreshRSS.git
synced 2026-07-16 10:02:59 -04:00
## Problem The feed **tree** (left sidebar) and the **feed-title view** (main body) order feeds differently for names with accents or symbols. As reported in #8300, a Spanish feed starting with `Ú` appears **last** in the tree, after every ASCII-named feed. The tree is sorted in PHP by `FreshRSS_Category::sortFeeds()` with `strnatcasecmp()`, which compares raw UTF-8 **bytes** — so any name starting with a non-ASCII character (`0xC3…` for `Á`, `Ñ`, `Ú`, …) sorts after `A–Z`. The main view is sorted by the database according to its collation, which orders accented letters near their base letter — hence the mismatch (as @Alkarex noted in the issue). Closes #8300. ## Change `sortFeeds()` now compares with a `Collator` (`ext-intl`, already a hard requirement) for the user's language, falling back to the previous `strnatcasecmp()` if a collator cannot be created: ```php $collator = \Collator::create(FreshRSS_Context::hasUserConf() ? FreshRSS_Context::userConf()->language : ''); ``` Sorting a Spanish set, before / after: ``` old: banana, Manzana, nube, Zorro, Ábaco, Ñandú, Úlcera, árbol new: Ábaco, árbol, banana, Manzana, nube, Ñandú, Úlcera, Zorro ``` This makes the tree order locale-aware and much closer to the main view. Exact parity with the main view still depends on the database collation (which is admin/DB-specific and cannot be reproduced generically in PHP), but the "accented names sort last" problem is gone. * Feeds tree: sort feed names with locale-aware collation The feed tree sorted names byte-wise with strnatcasecmp(), which places names starting with a non-ASCII character (e.g. an accented capital such as "U-acute") after every ASCII name. Use a Collator for the user's language so accented and non-ASCII names sort near their base letter, closer to the database collation used on the main feed-title view. For https://github.com/FreshRSS/FreshRSS/issues/8300 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Guard Collator with class_exists() so intl stays optional The intl extension is only a recommended (not required) dependency, but sortFeeds() called \Collator::create() unconditionally when a user language was set. On installs without intl the \Collator class does not exist, so the call raised a fatal "Class \"Collator\" not found" — effectively promoting intl from recommended to required. Guard the call with class_exists('Collator'): when intl is absent, fall back to the previous byte-wise strnatcasecmp() sort. Locale-aware ordering stays a progressive enhancement and the listed requirements are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Shorten the sortFeeds() collation comment per review Trim the rationale comment to a concise four lines as suggested in review, keeping the locale-aware/fallback and class_exists() reasoning. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Stylistic preference * Factorise localeCompare * Minor code preference * Preserve natural locale sort behaviour * Avoid repeated locale lookup in comparator --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>