test(vue): add Vite integration example - #2014
Open
eoinest wants to merge 7 commits into
Open
Conversation
Contributor
size-limit report 📦
|
Contributor
Author
4 similar comments
Contributor
Author
Contributor
Author
Contributor
Author
Contributor
Author
eoinest
force-pushed
the
e/vue/add-vue-vite-example
branch
from
August 1, 2026 02:33
5b10c7d to
06e8490
Compare
This was referenced Aug 1, 2026
Contributor
Author
eoinest
force-pushed
the
e/vue/add-vue-vite-example
branch
from
August 1, 2026 02:50
06e8490 to
bd5ef4d
Compare
Contributor
Author
eoinest
force-pushed
the
e/vue/add-vue-vite-example
branch
from
August 1, 2026 03:09
bd5ef4d to
6714637
Compare
Contributor
Author
eoinest
force-pushed
the
e/vue/add-vue-vite-example
branch
from
August 5, 2026 20:15
6714637 to
b983e51
Compare
Contributor
Author
This was referenced Aug 5, 2026
Contributor
Author
1 similar comment
Contributor
Author
archie-mckenzie
previously approved these changes
Aug 6, 2026
Contributor
Author
1 similar comment
Contributor
Author
eoinest
changed the base branch from
e/cli/add-vue-extraction
to
e/release/enter-iris-prerelease
August 6, 2026 19:05
eoinest
changed the base branch from
e/release/enter-iris-prerelease
to
e/cli/add-vue-extraction
August 6, 2026 19:17
Contributor
Author
eoinest
dismissed
archie-mckenzie’s stale review
August 6, 2026 20:16
The merge-base changed after approval.
eoinest
force-pushed
the
e/vue/add-vue-vite-example
branch
from
August 6, 2026 22:29
bf57f83 to
6f54b09
Compare
Contributor
Author
eoinest
force-pushed
the
e/vue/add-vue-vite-example
branch
from
August 7, 2026 00:43
6f54b09 to
9137192
Compare
Contributor
Author
eoinest
added a commit
that referenced
this pull request
Aug 7, 2026
## Summary - Add an unstable, lightweight `gt-vue` runtime with `T`, child-only `Var`, typed-value `Num` / `DateTime` / `Currency`, `Plural`, `Branch`, `useGT`, `useMessages`, and `msg`. - Keep string translation deliberately narrow: `$context` is the only public metadata option; all content is literal STRING data with no ICU interpolation, formatting fields, or development hot reload. - Provide isolated `createGT()` instances, async per-locale catalog caching, reactive locale changes, latest-wins concurrency, retryable loader diagnostics, and source-locale fast paths for client and SSR use. - Preserve Vue component props/listeners and scoped slots, keep rich-content IDs and plural selection compatible with react-core, exclude presentation/runtime attributes from persisted Branch hashes, and suppress unsupported fallthrough attrs on wrapperless value components. - Share the literal STRING hash/registration contract through `gt-i18n/internal/string`; `gt-i18n` is a real external runtime dependency in both ESM and CJS. ## Testing - `gt-vue`: full runtime suite passed, including SSR/hydration, keyed VNode reconciliation, opaque slots, Suspense, and concurrency - `gt-i18n`: 33 files / 314 tests - `@generaltranslation/react-core`: 12 files / 50 tests, including shared hand-pinned wire-format fixtures - Forced Turbo build/typecheck for the runtime dependency graph — passed - Root library-default, lint, and format gates — passed - Size limits — passed (`gt-vue` 7.56 kB Brotli; `gt-i18n/internal/string` 2.97 kB) - Packed consumers on Vue 3.3.13 and 3.5.40 — passed ESM, CJS, SSR, `vue-tsc`, Vite production builds, and real Chromium locale/formatting loops with zero console warnings/errors - Changesets simulation — `gt-vue@0.1.0` correctly depends on `gt-i18n@1.1.0` ## Notes - `gt-vue` is explicitly documented as unstable and independently versioned during 0.x. - Changesets: minor for both the first `gt-vue` release and the literal STRING contract update in `gt-i18n`. - Stack 1/4. Base: `main`. Next: #2013, #2014, then #2033. - This PR is not being merged or published yet. <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR introduces `gt-vue`, a new lightweight Vue 3 i18n runtime package, plus a shared `gt-i18n/internal/string` contract for STRING-format translation hashing and cookie utilities consumed by both Vue and React runtimes. It also refactors `gt-i18n`'s `msg` to delegate to a new `msgString` path when `$format: 'STRING'` is requested, and consolidates cookie-name constants from `react-core` into `gt-i18n`. - **`gt-vue` runtime**: adds `T`, `Var`, `Num`, `DateTime`, `Currency`, `Plural`, `Branch`, `createGT`, `useGT`, `useMessages`, `useLocale`, `useSetLocale`, and `msg` — with reactive locale state, per-locale catalog caching, latest-wins concurrency, SSR/hydration support, and source-locale fast paths. - **`gt-i18n` additions**: `msgString`, `encodeMsg`, `hashStringMessage`, browser cookie utilities, and new internal entry points (`internal-string`, `internal-cookies`) shared across frameworks. - **`react-core` cleanup**: `cookieNames.ts` now re-exports from `gt-i18n/internal/cookies` rather than duplicating constants. <details open><summary><h3>Confidence Score: 5/5</h3></summary> - This PR is safe to review and merge — no functional regressions or data-loss paths were found across the new Vue runtime, the shared gt-i18n STRING contract, or the react-core consolidation. - The new gt-vue package adds a large surface area (rich-content rendering, locale concurrency, SSR/hydration, cookie management) but each subsystem is self-contained and backed by targeted tests. The latest-wins concurrency logic in setLocale, the revision-counter reactivity contract, the source-locale fast-path that deliberately skips catalog reads, the VNode identity cache rollback on render errors, and the `isEncodedTranslationOptions` type guard before msg decode are all implemented correctly. The react-core cookie constant consolidation is a straight re-export with no behavioral change. No blocking issues were found. - No files require special attention. </details> <details><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | packages/vue/src/runtime/state.ts | Core plugin factory. Locale concurrency (latest-wins), per-locale catalog caching, cookie-backed locale persistence, and reactive revision counter are all implemented correctly. `console.error` on load failure is intentional diagnostic output, not debug logging. | | packages/vue/src/rendering/translateVueChildren.ts | Rich-content translation engine. Source serialization, hash-based catalog lookup, variable/branch/plural rendering, VNode identity caching with rollback, and metadata copying all look correct. `copyRenderMetadata` relies on undocumented `ctx` / `slotScopeIds` fields (flagged in a previous review thread). `cloneWithProps` for components intentionally passes a VNode to `h()` to take the clone-and-renormalize path. | | packages/vue/src/runtime/localeCookie.ts | Cookie-backed locale accessor. SSR/hydration contract is correct: explicit locale overrides a stale browser cookie on first mount, `getLocale` reads live cookie on browser, `serverLocale` closure isolates per-request SSR state. | | packages/vue/src/composables/strings.ts | useGT and useMessages composables. Encoded msg metadata is decoded and short-circuited through the precomputed hash path; raw strings fall through to the regular STRING hash lookup. Nullish passthrough is correct. | | packages/vue/src/components/variables.ts | Num, DateTime, Currency, and Var components. Null/empty-string guards, NaN fallback to String(value), and _locale override for the rich-translation pipeline are all correctly implemented. | | packages/vue/src/components/branches.ts | Plural and Branch components. getBranchNames deduplicates attr/slot names via Set (regression test included). getBranchContent slot-wins logic and getFormatLocales fallback are correct. | | packages/i18n/src/translation-functions/msg/msgString.ts | New STRING-format msg registration path. Array recursion with $id indexing, STRING format tagging, and encodeMsg delegation are all correct. The early return when options is absent preserves the original input's type. | | packages/i18n/src/utils/hashStringMessage.ts | Canonical STRING catalog key computation. Precomputed $_hash short-circuit is used correctly by both msgString and translateString to avoid re-hashing. | | packages/react-core/src/setup/cookieNames.ts | Replaced duplicated cookie constants with re-exports from gt-i18n/internal/cookies. Single source of truth for cookie names across runtimes. | | packages/vue/src/components/utils.ts | Shared component utilities. isBranchAttribute correctly excludes event handlers, ARIA/data attributes, and the NON_BRANCH_ATTRIBUTE_NAMES set. getBranchNames deduplication and getBranchContent slot-priority logic look correct. | </details> <details><summary><h3>Sequence Diagram</h3></summary> ```mermaid sequenceDiagram participant App as Vue App participant Plugin as GTPlugin (createGT) participant State as GTState participant Cookie as CookieBackedLocale participant Loader as loadTranslations participant Catalog as catalogs Map participant T as T Component participant Renderer as translateVueChildren App->>Plugin: app.use(plugin) Plugin->>State: provide(gtContextKey, state) Plugin->>Loader: load(getLocale()) [async, fire-and-forget] Loader-->>Catalog: catalogs.set(locale, catalog) Loader-->>State: "revision.value += 1" App->>Plugin: setLocale('fr') Plugin->>Loader: load('fr') note over Plugin,Loader: concurrent requests share one Promise<br/>latest-wins: older requests return early Loader-->>Catalog: catalogs.set('fr', catalog) Plugin->>Cookie: setLocale('fr') → writes cookie Plugin-->>State: "revision.value += 1" T->>State: getLocale() → reads revision (reactive) T->>State: getCatalog() → reads revision (reactive) T->>Renderer: translateVueChildren(vnodes, state, options) Renderer->>Renderer: createSourceNodes → serializeNodes → hashSource Renderer->>Catalog: getCatalog()[hash] Renderer-->>T: translated VNodeChild ``` </details> <sub>Reviews (13): Last reviewed commit: ["fix(vue): persist locale in browser cook..."](163973a) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=48899958)</sub> <!-- /greptile_comment -->
eoinest
force-pushed
the
e/vue/add-vue-vite-example
branch
from
August 7, 2026 00:53
9137192 to
c03f9c6
Compare
eoinest
force-pushed
the
e/vue/add-vue-vite-example
branch
from
August 7, 2026 02:19
c03f9c6 to
9ef233a
Compare
eoinest
force-pushed
the
e/vue/add-vue-vite-example
branch
from
August 7, 2026 02:44
9ef233a to
d984cbd
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
gt-vuesurface, including child-onlyVar, typedvaluebindings, and Vue TSX through local re-exports, namespace components, and forwarded translators.Testing
gt generateandgt validate— passed with exactly 21 entries; regenerated English/French catalogs remained byte-for-byte unchangedvue-tsc -band Vite 7.3.1 production build — passedworkspace:references; packed CLI generate/validate, typecheck, build, and browser loops passedNotes
examples/vite-vuepluspnpm-lock.yaml.Greptile Summary
This PR adds a new
examples/vite-vueworkspace that demonstrates the full lightweightgt-vueAPI on top of Vite 7 and Vue 3, using only the standard@vitejs/plugin-vueand@vitejs/plugin-vue-jsxplugins — no GT compiler, server, or hot-reload integration. The PR description documents comprehensive manual testing (EN ↔ FR loops, lazy loading, typecheck, production build) and confirmsgt generate/gt validatepassed with exactly 21 entries.App.vueexercises<T>, child-only<Var>,<Plural>,<Branch>,<Num>,<Currency>,<DateTime>,useGT(),msg()/useMessages(), and reactiveuseLocale()/useSetLocale()with correct ARIA state management anddocument.langsynchronisation via a watcher.TsxCompatibilityCard.tsxdemonstrates three TSX patterns against the same catalog: a locally re-exported<T>with<Vue.Fragment>, a namespace<GT.T>, and a forwardedGTFunctionhelper.translations.tsusesimport.meta.globfor per-locale lazy-loading;vite.config.tsaddsresolve.dedupe: ['vue']to prevent duplicate Vue instances from linked workspace packages.Confidence Score: 5/5
examples/vite-vuedirectory and a singlepnpm-lock.yamlupdate. No library code, shared utilities, or CI pipelines are modified. The example is correctly structured, TypeScript-strict, and the PR author reports full test coverage including typecheck, production build, and browser verification loops.Important Files Changed
Sequence Diagram
sequenceDiagram participant User participant App.vue participant gt-vue participant translations.ts participant ViteChunk as Vite JSON chunk User->>App.vue: Click language button App.vue->>App.vue: selectLocale(nextLocale) Note over App.vue: changingLocale = true App.vue->>gt-vue: setLocale(nextLocale) gt-vue->>translations.ts: loadTranslations(locale) translations.ts->>ViteChunk: dynamic import('./_gt/fr.json') ViteChunk-->>translations.ts: TranslationCatalog translations.ts-->>gt-vue: "TranslationCatalog (or {} if not found)" gt-vue-->>App.vue: locale Ref updated Note over App.vue: changingLocale = false (finally) App.vue->>App.vue: watch(locale) fires App.vue->>App.vue: "document.documentElement.lang = locale" App.vue-->>User: UI re-renders with new localeReviews (17): Last reviewed commit: "test(vue): exercise TSX extraction in Vi..." | Re-trigger Greptile