feat(twenty-sdk): extract & compile app translations into the manifest (#22236)

## Summary

**PR 2/4** of the app-metadata-translations stack. Gives app developers
the authoring side, as part of the normal manifest build — and it stays
out of the way of developers who don't translate.

- `twenty-sdk` CLI i18n pipeline: collect translatable strings from the
manifest, generate value-as-key message ids (`sha256(value)` truncated,
byte-identical to the server's `generateMessageId`), a `dev
i18n-extract` command to scaffold per-locale catalog files, and a
compile step folded into `build` that emits `manifest.translations`.
- Opt-in: no `locales/` dir → `compileApplicationTranslations` returns
`undefined` → manifest is unchanged.
- Adds an optional `locale` to the front-component execution context so
components can translate against the host locale.

## Stack
Stacks on #22235 (PR 1/4). Base branch:
`claude/app-translation-1-runtime-resolution`.

## Tests
Unit (vitest): extract/compile round-trip + message-id determinism.

## Verification note
`yarn install` could not complete in the remote dev environment, so
typecheck/lint/tests were not run locally — **CI is the source of
truth**.

https://claude.ai/code/session_01NiE7o3cd3zCLZarVkJa6UA

---
_Generated by [Claude
Code](https://claude.ai/code/session_01NiE7o3cd3zCLZarVkJa6UA)_

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22236?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. -->
This commit is contained in:
Félix Malfait
2026-06-28 07:36:48 +02:00
committed by GitHub
parent 41c10b9ee7
commit d81b3c3fa3
13 changed files with 407 additions and 2 deletions
@@ -7,6 +7,7 @@ import { runTypecheck } from '@/cli/utilities/build/common/typecheck-plugin';
import { buildAndValidateManifest } from '@/cli/utilities/build/manifest/build-and-validate-manifest';
import { manifestUpdateChecksums } from '@/cli/utilities/build/manifest/manifest-update-checksums';
import { writeManifestToOutput } from '@/cli/utilities/build/manifest/manifest-writer';
import { compileApplicationTranslations } from '@/cli/utilities/i18n/compile-application-translations';
import { runSafe } from '@/cli/utilities/run-safe';
import { APP_ERROR_CODES, type CommandResult } from '@/cli/types';
@@ -62,6 +63,8 @@ const innerAppBuild = async (
onProgress?.('Generated cover image from logo');
}
const translations = await compileApplicationTranslations(appPath);
onProgress?.('Building application files...');
const buildResult = await buildApplication({
@@ -95,7 +98,10 @@ const innerAppBuild = async (
builtFileInfos: buildResult.builtFileInfos,
});
await writeManifestToOutput(appPath, updatedManifest);
await writeManifestToOutput(
appPath,
translations ? { ...updatedManifest, translations } : updatedManifest,
);
const outputDir = path.join(appPath, '.twenty', 'output');