-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Q1 2026 Roadmap — i18n package, test infrastructure, perf utilities, quick-start guide #400
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…ort, and formatting utilities Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…56 tests) Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…ndaries), quick start guide, and update ROADMAP Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…back Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
| @@ -0,0 +1,228 @@ | |||
| import { describe, it, expect, beforeEach } from 'vitest'; | |||
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 days ago
To fix an unused import, you remove just the unused identifier from the import statement, leaving the rest of the imports intact so existing functionality is unchanged. In this case, beforeEach is imported from vitest but never used in the test file, so we should remove beforeEach from the destructuring import.
Concretely, in packages/i18n/src/__tests__/i18n.test.ts, edit the first line so that beforeEach is no longer listed in the imported names. No other lines or imports need to be changed, and no additional methods or definitions are required for this fix.
-
Copy modified line R1
| @@ -1,4 +1,4 @@ | ||
| import { describe, it, expect, beforeEach } from 'vitest'; | ||
| import { describe, it, expect } from 'vitest'; | ||
| import { | ||
| createI18n, | ||
| getDirection, |
| import { | ||
| createI18n, | ||
| getDirection, | ||
| getAvailableLanguages, | ||
| builtInLocales, | ||
| isRTL, | ||
| RTL_LANGUAGES, | ||
| formatDate, | ||
| formatDateTime, | ||
| formatCurrency, | ||
| formatNumber, | ||
| } from '../index'; |
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 days ago
To fix an unused import, you simply remove it from the import list while keeping the rest of the imports intact. This eliminates dead code, keeps the test file clean, and avoids confusion about which APIs are actually being exercised.
In this file, the best minimal fix is to delete formatDateTime from the named imports from ../index on lines 2–13. No additional code changes or new functionality are required. Concretely, in packages/i18n/src/__tests__/i18n.test.ts, edit the import block so that formatDateTime is no longer present, leaving all the other imported symbols unchanged. No new methods, imports, or definitions are needed.
| @@ -7,7 +7,6 @@ | ||
| isRTL, | ||
| RTL_LANGUAGES, | ||
| formatDate, | ||
| formatDateTime, | ||
| formatCurrency, | ||
| formatNumber, | ||
| } from '../index'; |
|
|
||
| it('all locales have the same top-level keys', () => { | ||
| const enKeys = Object.keys(builtInLocales.en).sort(); | ||
| for (const [lang, locale] of Object.entries(builtInLocales)) { |
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 days ago
In general, the way to fix this is to either remove unused variables or replace them with a conventional placeholder (such as _) to indicate they are intentionally unused. For destructuring in for...of loops, you can destructure only the elements you need.
Here, on line 166 in packages/i18n/src/__tests__/i18n.test.ts, the loop:
for (const [lang, locale] of Object.entries(builtInLocales)) {should be updated to avoid binding lang. The best change without affecting behavior is:
for (const [, locale] of Object.entries(builtInLocales)) {This keeps the structure of iterating over entries but only binds locale, which is what the body uses. The same pattern appears again later at lines 174–175, so we should make the analogous change there as well to keep the tests consistent and remove both unused lang bindings. No new imports, functions, or other definitions are required.
-
Copy modified line R166 -
Copy modified line R174
| @@ -163,7 +163,7 @@ | ||
|
|
||
| it('all locales have the same top-level keys', () => { | ||
| const enKeys = Object.keys(builtInLocales.en).sort(); | ||
| for (const [lang, locale] of Object.entries(builtInLocales)) { | ||
| for (const [, locale] of Object.entries(builtInLocales)) { | ||
| const keys = Object.keys(locale).sort(); | ||
| expect(keys).toEqual(enKeys); | ||
| } | ||
| @@ -171,7 +171,7 @@ | ||
|
|
||
| it('all locales have common section keys matching English', () => { | ||
| const enCommonKeys = Object.keys(builtInLocales.en.common).sort(); | ||
| for (const [lang, locale] of Object.entries(builtInLocales)) { | ||
| for (const [, locale] of Object.entries(builtInLocales)) { | ||
| const keys = Object.keys(locale.common).sort(); | ||
| expect(keys).toEqual(enCommonKeys); | ||
| } |
|
|
||
| it('all locales have common section keys matching English', () => { | ||
| const enCommonKeys = Object.keys(builtInLocales.en.common).sort(); | ||
| for (const [lang, locale] of Object.entries(builtInLocales)) { |
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 days ago
In general, to fix an unused variable reported in a loop destructuring pattern, remove the unused binding while preserving the used one. For this case, the simplest change is to stop destructuring into [lang, locale] and instead iterate over the Object.values of builtInLocales, since only locale is needed.
Specifically, in packages/i18n/src/__tests__/i18n.test.ts around line 172–178, replace:
for (const [lang, locale] of Object.entries(builtInLocales)) {
const keys = Object.keys(locale.common).sort();
expect(keys).toEqual(enCommonKeys);
}with:
for (const locale of Object.values(builtInLocales)) {
const keys = Object.keys(locale.common).sort();
expect(keys).toEqual(enCommonKeys);
}This removes the unused lang variable without altering the logic of the test. No new imports or additional definitions are required.
-
Copy modified line R174
| @@ -171,7 +171,7 @@ | ||
|
|
||
| it('all locales have common section keys matching English', () => { | ||
| const enCommonKeys = Object.keys(builtInLocales.en.common).sort(); | ||
| for (const [lang, locale] of Object.entries(builtInLocales)) { | ||
| for (const locale of Object.values(builtInLocales)) { | ||
| const keys = Object.keys(locale.common).sort(); | ||
| expect(keys).toEqual(enCommonKeys); | ||
| } |
📦 Bundle Size Report
Size Limits
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements several Q1 2026 roadmap items across the monorepo: a new @object-ui/i18n package (locale packs + formatting + React provider), Playwright E2E infrastructure, additional unit tests for core modules, and improvements to lazy plugin loading utilities in @object-ui/react, plus associated documentation/config housekeeping.
Changes:
- Added
@object-ui/i18npackage with built-in locales, RTL helpers, React provider/hooks, and Intl-based formatting utilities. - Introduced Playwright E2E setup (
playwright.config.ts,e2e/smoke test) and updated test tooling config (vitest.config.mts,.gitignore, root scripts). - Enhanced
createLazyPlugin()with retry/error handling options and addedpreloadPlugin().
Reviewed changes
Copilot reviewed 30 out of 32 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| vitest.config.mts | Excludes e2e/ from Vitest and adds alias for @object-ui/i18n. |
| pnpm-lock.yaml | Locks new dependencies for Playwright + i18n stack. |
| playwright.config.ts | Adds Playwright E2E configuration and dev-server orchestration. |
| packages/react/src/LazyPluginLoader.tsx | Adds retry options, error boundary support, and preloadPlugin(). |
| packages/i18n/tsconfig.json | Adds TS build config for the new i18n package. |
| packages/i18n/src/utils/index.ts | Re-exports formatting utilities/types. |
| packages/i18n/src/utils/formatting.ts | Implements Intl-based date/number/currency/relative time formatting helpers. |
| packages/i18n/src/provider.tsx | Adds I18nProvider, useObjectTranslation, and context helpers (incl. document dir/lang updates). |
| packages/i18n/src/locales/zh.ts | Adds Chinese locale pack. |
| packages/i18n/src/locales/ru.ts | Adds Russian locale pack. |
| packages/i18n/src/locales/pt.ts | Adds Portuguese locale pack. |
| packages/i18n/src/locales/ko.ts | Adds Korean locale pack. |
| packages/i18n/src/locales/ja.ts | Adds Japanese locale pack. |
| packages/i18n/src/locales/index.ts | Exports locale packs, RTL language list, and isRTL(). |
| packages/i18n/src/locales/fr.ts | Adds French locale pack. |
| packages/i18n/src/locales/es.ts | Adds Spanish locale pack. |
| packages/i18n/src/locales/en.ts | Adds English default locale pack and TranslationKeys type. |
| packages/i18n/src/locales/de.ts | Adds German locale pack. |
| packages/i18n/src/locales/ar.ts | Adds Arabic locale pack. |
| packages/i18n/src/index.ts | Public entrypoint exports for provider, locales, RTL utils, and formatting helpers. |
| packages/i18n/src/i18n.ts | Implements createI18n, direction helpers, resource merging, and language detection. |
| packages/i18n/src/tests/i18n.test.ts | Adds unit tests for i18n initialization, translations, RTL utilities, and formatting. |
| packages/i18n/package.json | Declares new package metadata, scripts, deps/peers, and exports map. |
| packages/core/src/validation/tests/schema-validator.test.ts | Adds tests for schema validation helpers. |
| packages/core/src/evaluator/tests/ExpressionContext.test.ts | Adds tests for ExpressionContext behavior and scope handling. |
| packages/core/src/builder/tests/schema-builder.test.ts | Adds tests for schema builder factory functions and chaining. |
| package.json | Adds Playwright scripts and @playwright/test devDependency. |
| e2e/smoke.spec.ts | Adds basic console app smoke tests. |
| content/docs/guide/quick-start.md | Adds a new “Quick Start” guide page. |
| content/docs/guide/meta.json | Adds quick-start as the first guide nav entry. |
| ROADMAP.md | Checks off completed Q1 items. |
| .gitignore | Ignores Playwright artifacts (test-results, playwright-report). |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
| export function formatDateTime( | ||
| date: Date | string | number, | ||
| options: DateFormatOptions = {}, | ||
| ): string { | ||
| const { locale = 'en', style = 'medium' } = options; |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
formatDateTime ignores dateStyle/timeStyle even though they’re part of DateFormatOptions (only formatDate honors them). This makes the options interface misleading and prevents callers from using Intl’s built-in styles for date+time. Consider applying the same dateStyle/timeStyle override logic here as well.
| instance.init({ | ||
| lng, | ||
| fallbackLng: fallbackLanguage, | ||
| resources: mergedResources, |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
createI18n returns the instance immediately after calling instance.init(...), but init is async in i18next. Consumers may call t() before initialization completes and get missing/incorrect translations. Consider either (1) setting initImmediate: false to make init synchronous for in-memory resources, or (2) making createI18n async and awaiting instance.init() before returning.
| resources: mergedResources, | |
| resources: mergedResources, | |
| initImmediate: false, |
| "msw": "^2.12.7", | ||
| "msw-storybook-addon": "^2.0.6", | ||
| "@playwright/test": "^1.58.2", | ||
| "playwright": "^1.58.0", |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Version ranges for Playwright are mismatched: @playwright/test is ^1.58.2 while playwright is ^1.58.0. This can lead to multiple Playwright versions in the lockfile (and larger installs / inconsistent browser binaries). Consider aligning the versions (or removing the direct playwright dependency if @playwright/test is the intended entrypoint).
| "playwright": "^1.58.0", | |
| "playwright": "^1.58.2", |
| if (errorFallback) { | ||
| return ( | ||
| <PluginErrorBoundary fallback={errorFallback}> | ||
| {content} | ||
| </PluginErrorBoundary> |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The retry callback provided to errorFallback only resets the error boundary state, but it doesn’t restart the failed React.lazy() import. After a lazy import rejects, React caches the rejection for that lazy component type, so clicking Retry will keep rendering the same error. Consider recreating the lazy component on retry (e.g., a retry counter that changes the lazy initializer / key) so retry() actually triggers a fresh dynamic import.
| const { locale = 'en', currency = 'USD', minimumFractionDigits, maximumFractionDigits } = options; | ||
|
|
||
| return new Intl.NumberFormat(locale, { | ||
| style: 'currency', | ||
| currency, | ||
| minimumFractionDigits, | ||
| maximumFractionDigits, |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CurrencyFormatOptions defines a style option, but formatCurrency always forces style: 'currency' and never reads options.style. Either remove style from the options type or pass it through to Intl.NumberFormat (and only require currency when style is 'currency').
| const { locale = 'en', currency = 'USD', minimumFractionDigits, maximumFractionDigits } = options; | |
| return new Intl.NumberFormat(locale, { | |
| style: 'currency', | |
| currency, | |
| minimumFractionDigits, | |
| maximumFractionDigits, | |
| const { | |
| locale = 'en', | |
| style = 'currency', | |
| currency, | |
| minimumFractionDigits, | |
| maximumFractionDigits, | |
| } = options; | |
| const baseOptions: Intl.NumberFormatOptions = { | |
| style, | |
| minimumFractionDigits, | |
| maximumFractionDigits, | |
| }; | |
| const currencyOptions: Intl.NumberFormatOptions = | |
| style === 'currency' | |
| ? { currency: currency ?? 'USD' } | |
| : {}; | |
| return new Intl.NumberFormat(locale, { | |
| ...baseOptions, | |
| ...currencyOptions, |
| const { retries = 2, retryDelay = 1000, errorFallback } = options || {}; | ||
|
|
||
| const retryImport = retries > 0 | ||
| ? createRetryImport(importFn, retries, retryDelay) | ||
| : importFn; |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New behaviors (retries, retryDelay, errorFallback, and preloadPlugin) aren’t covered by tests in this PR. Since packages/react/src/__tests__/LazyPluginLoader.test.tsx already exists, please add/extend tests to cover: retry attempt count + delay behavior, rendering errorFallback on failure, and that retry() triggers a fresh import attempt.
| @@ -0,0 +1,228 @@ | |||
| import { describe, it, expect, beforeEach } from 'vitest'; | |||
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused import beforeEach.
| import { describe, it, expect, beforeEach } from 'vitest'; | |
| import { describe, it, expect } from 'vitest'; |
| isRTL, | ||
| RTL_LANGUAGES, | ||
| formatDate, | ||
| formatDateTime, |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused import formatDateTime.
| formatDateTime, |
|
|
||
| it('all locales have the same top-level keys', () => { | ||
| const enKeys = Object.keys(builtInLocales.en).sort(); | ||
| for (const [lang, locale] of Object.entries(builtInLocales)) { |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused variable lang.
|
|
||
| it('all locales have common section keys matching English', () => { | ||
| const enCommonKeys = Object.keys(builtInLocales.en.common).sort(); | ||
| for (const [lang, locale] of Object.entries(builtInLocales)) { |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused variable lang.
Implements the Q1 2026 roadmap items: i18n support, test system enhancement, performance optimization, and documentation upgrade.
@object-ui/i18n— new packageI18nProvider,useObjectTranslationhook,createI18nfactoryen,zh,ja,ko,de,fr,es,pt,ru,arisRTL(),getDirection(), autodocument.dirupdates)formatDate,formatDateTime,formatRelativeTime,formatCurrency,formatNumberTest system enhancement
playwright.config.ts) with Chromium/Firefox/WebKit/mobile projectse2e/smoke.spec.ts)SchemaBuilder(27) — all 7 builder typesSchemaValidator(15) — validate, assert, isValid, formatErrorsExpressionContext(14) — scopes, dot notation, child contextsPerformance utilities
createLazyPlugin()enhanced with configurable retry logic andPluginErrorBoundarypreloadPlugin()for anticipatory module loadingDocumentation
content/docs/guide/quick-start.md), added as first entry in guide navHousekeeping
vitest.config.mts: added@object-ui/i18nalias, excluded**/e2e/**.gitignore: addedtest-results/,playwright-report/ROADMAP.md: checked off completed Q1 items💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.