4fc3650b2d
## Problem The automated `i18n - translations` PR (branch `i18n`) conflicts on `twenty-emails` `.po` files on **every** cycle. Each time, the msgid *set* is identical to main — only the entry **order** differs. ## Root cause `twenty-emails` uses explicit message ids (`js-lingui-explicit-id`). With lingui's default ordering, **`lingui extract` is non-idempotent for this catalog** — two consecutive runs on identical source produce different `.po` orderings: ``` # no source change between runs lingui extract # run 1 lingui extract # run 2 -> ~170 lines reordered vs run 1 ``` So the order produced by the `i18n-push` extract on main, the order stored in Crowdin, and the order the `i18n-pull` bot downloads never agree, and the translation PR re-conflicts perpetually. `twenty-front`/`twenty-server` use hashed ids and are already idempotent — this is isolated to emails. ## Fix Set `orderBy: 'messageId'` in `twenty-emails/lingui.config.ts`. Verified this makes extraction idempotent — two consecutive extracts now produce byte-identical output. This commit includes the one-time reorder of the existing catalogs into the stable order. Generated `.ts` output is unchanged (already order-independent). After merge, one push cycle syncs Crowdin to the stable order, after which the recurring conflicts stop. ## Test plan - `nx run twenty-emails:lingui:extract` twice → no diff on the second run. - `nx run twenty-emails:lingui:compile` → succeeds, generated `.ts` unchanged. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22803?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
31 lines
1.1 KiB
TypeScript
31 lines
1.1 KiB
TypeScript
import { defineConfig } from '@lingui/conf';
|
|
import { formatter } from '@lingui/format-po';
|
|
import { APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations';
|
|
|
|
export default defineConfig({
|
|
sourceLocale: 'en',
|
|
locales: Object.values(APP_LOCALES),
|
|
pseudoLocale: 'pseudo-en',
|
|
fallbackLocales: {
|
|
default: SOURCE_LOCALE,
|
|
},
|
|
extractorParserOptions: {
|
|
tsExperimentalDecorators: true,
|
|
},
|
|
catalogs: [
|
|
{
|
|
path: '<rootDir>/src/locales/{locale}',
|
|
include: ['src'],
|
|
},
|
|
],
|
|
catalogsMergePath: '<rootDir>/src/locales/generated/{locale}',
|
|
// Sort catalog entries by message id. These emails use explicit ids
|
|
// (js-lingui-explicit-id), for which the default order is non-deterministic:
|
|
// `lingui extract` reorders the .po on every run even with no source change,
|
|
// so main and the Crowdin sync never agree and every i18n pull re-conflicts.
|
|
// Sorting by messageId makes extraction idempotent and the order stable.
|
|
orderBy: 'messageId',
|
|
compileNamespace: 'ts',
|
|
format: formatter({ lineNumbers: false, printLinguiId: true }),
|
|
});
|