product icon

Paraglide JS

App

Benchmark

This benchmark compares the transfer size of different i18n libraries and their implementations.

The goal is to understand how the size of the library changes with different configurations, such as the number of locales, messages per page, and namespace size.

If you are looking for a feature comparison, check out the comparison table.

💡 Tip: Paraglide JS has not reached its final optimizations yet. Tickets like #88 per locale builds or #354 pruning server side rendered messages are yet to be implemented. Pull requests are welcome!

What is Being Tested

The benchmark creates a static website for each configuration (library variant, number of locales, messages per page, and namespace size). Each website is loaded in a headless browser, and the total transfer size is measured.

  • Number of Locales: How does an i18n library scale with the number of locales?
  • Number of used Messages: How does an i18n library scale with the number of messages that are used on a given page?
  • Library Implementation Variants: Testing different implementation approaches:
    • Paraglide:
      • default: Standard implementation
      • experimental-: Experimental implementation with per-locale splitting
    • i18next:
      • http-backend: Using HTTP backend for loading translations
  • Namespace Size: Testing how the total available messages in a namespace affects bundle size

Library modes

Each library is tested in different modes:

  • Paraglide:
    • default: Out of the box Paraglide JS with no additional compiler options.
    • : Mode with a compiler option that is being tested.
  • i18next:
    • default: The default i18next implementation source.
    • http-backend: i18next implementation using HTTP backend for loading translations on dmeand source.

Limitations

Choosing the number of messages and namespace varies between projects

Some teams use per component namespacing while other teams have one namespace for their entire project. In cal.com's case, every component that uses i18n loads at least 3000 messages per locale.

To the point of the problem: Avoiding manual chunking of messages into namespaces is the benefit of Paraglide JS. The bundler tree-shakes all unused messages, making namespaces redundant.

Contributing

Contributions to improve the benchmark are welcome.

  1. adjust the build matrix in build.config.ts
  2. run pnpm run bench to build the benchmark
  3. run pnpm run preview to preview the results