Blogs Engineering

Shrinking Kimai's Translation Cache: Warm Only the Locales That Ship Translations

Kimai warmed translation caches for about 300 locales. The merged change limits it to translated ones; the maintainer reported a file-cache reduction from ~53 MB to 20 MB.

PHPkimai/kimaiSymfonyperformancei18n

A configuration change that a maintainer took further, fixing an older URL bug along the way.

Short answer

Kimai's framework.enabled_locales listed roughly 300 locales, including every subregion used only for date and number formatting. Symfony's translator warmed a cache for each one. The change introduces a kimai_translated_locales parameter for the locales that actually ship translation files and uses it for cache warming and URL route requirements. The maintainer adapted it so untranslated locales such as /en_CY/ can no longer appear in URLs, and reported that the file cache in var/cache/ dropped "from ~53 MB to 20 MB". It was merged as PR #6148.

The problem

Kimai is an open-source time-tracking application built on Symfony. It separates two things: the language the UI is translated into, and the locale used for formatting dates, times and money. The formatting list is long; the translation list is much shorter. But both fed the same enabled_locales setting, so cache warmup processed every formatting locale.

Root cause

The PR description explains it: "Symfony's Translator::warmUp() keeps every warmed catalogue (including a full copy of each fallback catalogue) in memory", so hundreds of locales multiplied memory use during warmup.

The fix

# config/packages/translation.yaml
-    enabled_locales: '%kimai_locales%'
+    enabled_locales: '%kimai_translated_locales%'

Route requirements were also narrowed to translated locales:

// @deprecated since 2.21.0 - only kept for (plugin) route requirements
$container->setParameter('app_locales', implode('|', $container->getParameter('kimai_translated_locales')));

The maintainer's commits made the homepage and locale redirect map a user's stored language to the nearest translated locale, so users whose profile holds an untranslated language don't hit a 404. A new test checks that kimai_translated_locales matches exactly the locales marked translation: true in config/locales.php, and the kimai:regenerate-locales command now keeps the list in sync.

By the numbers

  • Repository: kimai/kimai, 5,135 stars (Nov 3, 2026), PHP, AGPL-3.0
  • Files changed: 9
  • Lines: +56 / -10
  • Commits: 5 (1 from the PR author, 4 from the maintainer)
  • Opened: Aug 21, 2026. Merged: Sep 10, 2026. Time to merge: 19 days, 22 hours
  • Review: approved and merged by the maintainer; CLA signed

How the review went

The maintainer first asked for evidence: "Thanks for the idea. Some profiling infos would be good, before and after." The PR author reported the following profiling results: "warming 303 locales peaked at 58 MiB and failed under a 48 MiB limit, while warming the 42 translated locales peaked at 42 MiB and completed under the same limit."

The maintainer then took the change further: "I took your PR and adapted it slightly to fix a bug that was apparently existing for a longer time: you could use untranslated locales in the url, so /en_CY/ was possible without having translations." Their verdict: "The PR speeds up cache warmup and reduces memory usage, awesome 🎉 And it reduces the file cache size in var/cache/ from ~53 MB to 20 MB 😮"

Takeaways

  • Separate the lists that mean different things. Formatting locales and translation locales grew apart, and only one of them needs a translation cache.
  • Make measurements reproducible. The author reported before-and-after profiling figures, but the discussion provides no raw output to independently validate them. The maintainer separately reported the file-cache reduction.

FAQ

Can users still format dates in a subregion locale?

Yes. Formatting locales are still configured in the user profile; only the URL and translation cache are limited to translated locales.

Could this break bookmarks?

The maintainer noted it "could be a BC for bookmarks with such invalid locales, but its unlikely, as you could not geenrate themn with Kimai directly."

Where can I read more?

See the pull request.

The goal

Cache warmup is invisible until it fails. Warming only what the app can actually display makes deploys faster and lighter.

Run the loop

Turn production signals into reviewed fixes.

Start a free trial and see how Prilog maps real incidents to code-level pull requests.