Run i18n:export to refresh the locale JSON exports and locales.json
manifest (picks up all current lang/ folders, sorted by display name),
then rebuild frontend assets via Laravel Mix.
Empty lang/x/web.php values (untranslated Crowdin placeholders) were
being exported as empty strings, overriding the English UI fallback and
breaking non-English languages. Recursively strip empty strings before
writing the JSON build files, then regenerate all language files.
- terms/privacy/community-guidelines views accessed the cached page as an
object ($page->title), but cachedPage() returns an array, causing a 500
whenever a custom Page row existed. Switch to array access.
- PublicRouteSmokeTest: enable open_registration before hitting /register,
which 404s by default when registration is disabled.
- Api/AccountTest: derive sanctum.stateful domain from app.url instead of
hardcoding pixelfed.test, so the first-party auth test is environment
independent.
locale_get_display_language reads only the language subtag and ignores
the region, so zh-cn and zh-tw both rendered as 'Chinese - 中文'.
Switching to locale_get_display_name disambiguates region variants
(Chinese (China) / Chinese (Taiwan)) while leaving all region-less
locales unchanged.
Updated the settings language dropdown and the /i/lang picker.
Swap the custom 'rt' register token anti-spam mechanism for
spatie/laravel-honeypot on the registration and parental-controls
invite flows.
- Add spatie/laravel-honeypot and publish config/honeypot.php
- Remove getRegisterToken() and the rt validation rule from RegisterController
- Replace the rt hidden field with the @honeypot directive in both forms
- Attach ProtectAgainstSpam middleware to POST /register and the
parental-controls invite register route
- Update RegisterTest to disable honeypot for the valid registration case
- Relocate translation files from resources/lang to lang/ via git mv
- Update PHP references to use the lang_path() helper
- Update crowdin.yml source/translation paths
- Update phpstan.neon translationDirectories
Back out all emoji cloud-storage work from staging so it can be reworked and
re-landed separately (the URL resolution flips to cloud on a global config
flag, which created a broken-URL window, and the migration approach needs
revisiting).
Reverts to pre-emoji state:
- CustomEmoji model URL/storage helpers (urlForPath, storageTarget, storeMedia,
storeMediaFromFile, deleteMedia, url) and callers in ImportEmojis,
CustomEmojiService, AdminController
- admin custom-emoji blade views back to local /storage URLs
- Remove admin:EmojiMoveStorageLocalToCloud command
- Remove the deploy migration and its scheduler entry
Media (and the already-reverted story) scheduler entries are untouched.
Two issues prevented emoji from serving/migrating correctly on cloud:
- Admin custom-emoji views hardcoded url('storage/'.media_path), so they
always showed local URLs and bypassed cloud resolution. Use $emoji->url().
- The migration/command guard relied solely on config_cache('pixelfed.cloud_storage'),
which is DB/12h-cached and can read stale-false right after cloud is
enabled, causing the migration to silently no-op. Treat cloud as enabled
when either live config() or config_cache() is true.