evOo-local/apps/web/lingui.config.ts
Claude dc259f0491
feat(web): keep Lingui catalogs complete and in sync
The committed catalogs were last extracted weeks ago: about 330 source
messages were missing from every locale, and production builds keep only
message ids, so those strings rendered as hash ids (sidebar sections,
privacy settings, profile, timeline, ...). German also had 226 empty
entries, and every extraction rewrote the files because references carried
line numbers.

- lingui.config.ts: po references without line numbers, and a stable sort
  that breaks Lingui's ordering ties (explicit ids, equal text) by id, so
  the output no longer depends on file-system order.
- Re-extract all catalogs with --clean (drops 25-44 obsolete entries per
  locale; no existing translation changed).
- Translate every German entry (du form, consistent with the existing
  catalog). Other locales keep empty entries and fall back to English.
- i18n-catalog-sync.test.ts extracts into a copy of the catalogs and fails
  when the committed files differ or a German entry is empty, so stale
  catalogs fail the unit test job (offline, about 5 s).

Adds @lingui/format-po (already installed through @lingui/cli) as a direct
dev dependency to configure the formatter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u
2026-10-03 13:24:43 +00:00

40 lines
1.3 KiB
TypeScript

import type { CatalogFormatter, CatalogType } from "@lingui/conf";
import { defineConfig } from "@lingui/conf";
import { formatter } from "@lingui/format-po";
// File references without line numbers, so catalogs change only when messages change.
const po = formatter({ lineNumbers: false });
const collator = new Intl.Collator("en-US");
// Lingui orders entries by source text but leaves ties (explicit ids, equal text) in the order the
// files were found, which differs between file systems. Break ties by id so output is stable.
function sortCatalog(catalog: CatalogType): CatalogType {
return Object.fromEntries(
Object.entries(catalog).sort(
([aId, a], [bId, b]) =>
collator.compare(a.message ?? aId, b.message ?? bId) ||
collator.compare(a.context ?? "", b.context ?? "") ||
(aId < bId ? -1 : aId > bId ? 1 : 0),
),
);
}
const stablePo: CatalogFormatter = {
...po,
serialize: (catalog, ctx) => po.serialize(sortCatalog(catalog), ctx),
};
export default defineConfig({
sourceLocale: "en",
locales: ["en", "de", "ko", "tr", "hi", "pt-BR", "zh-CN", "es", "ru"],
catalogs: [
{
path: "<rootDir>/src/locales/{locale}/messages",
include: ["src"],
exclude: ["**/locales/**", "**/*.test.*"],
},
],
format: stablePo,
compileNamespace: "es",
});