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
40 lines
1.3 KiB
TypeScript
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",
|
|
});
|