assetLocaleGetString rewinds and linearly scans/re-decompresses the
whole locale file from byte 0 on every single call, with no caching -
a text-heavy screen can easily make 10+ of these in a row (e.g. opening
the game menu), and on PSP the containing archive is already fully
resident in RAM, so the repeated cost is pure CPU (decompression +
scanning), not I/O.
Adds a fixed 128-entry move-to-front LRU cache keyed by
(messageId, pluralCount), capped at 64/256 bytes per key/value (~40KB
total) so the cost stays bounded no matter how large the game's script
ends up being, rather than caching the whole locale file's text.
The cache is a lazily-allocated pointer on assetlocalefile_t, not
embedded inline - that struct lives inside the assetloaderoutput_t
union shared by every asset type, and all ASSET_ENTRY_COUNT_MAX asset
slots carry that union directly, so embedding it would have sized every
slot up by ~40KB regardless of what asset type occupies it.
Also fixes a bug this surfaced in test_assetlocale.c's own fixture:
locale_teardown zeroed the locale struct directly instead of going
through assetLocaleDispose, which would have leaked the new cache
allocation across tests.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>