Add objectstack-i18n skill for internationalization design guidance#1124
Add objectstack-i18n skill for internationalization design guidance#1124
Conversation
Agent-Logs-Url: https://github.com/objectstack-ai/framework/sessions/3156366a-443c-4d91-b432-20d589cf5dac Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Adds a new objectstack-i18n skill with comprehensive internationalization design guidance and bundles relevant spec references for AI consumption, plus updates the repo’s Copilot instructions to include the new skill.
Changes:
- Added
skills/objectstack-i18n/SKILL.mdwith i18n configuration, bundle structures, coverage/suggestions concepts, and workflow guidance. - Added
skills/objectstack-i18n/references/**containing copied Zod schemas/contracts for i18n-related protocols. - Updated
.github/copilot-instructions.mdto listobjectstack-i18nin the skills inventory and integration table.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| skills/objectstack-i18n/SKILL.md | New i18n design skill documentation (config, bundle structure, coverage, workflows, integration). |
| skills/objectstack-i18n/references/system/translation.zod.ts | Bundled reference copy of translation/i18n schemas for the skill. |
| skills/objectstack-i18n/references/contracts/i18n-service.ts | Bundled reference copy of the II18nService contract for the skill. |
| skills/objectstack-i18n/references/ui/i18n.zod.ts | Bundled reference copy of UI-level i18n schemas for the skill. |
| skills/objectstack-i18n/references/_index.md | Index page describing included reference schemas and dependencies. |
| .github/copilot-instructions.md | Adds the new skill to the skills list and “AI Skills Integration” table; updates sync date. |
| Use `{variable}` placeholders: | ||
|
|
||
| ```json | ||
| { | ||
| "messages": { | ||
| "welcome": "Welcome, {userName}!", | ||
| "pagination": "Showing {start} to {end} of {total} items" |
There was a problem hiding this comment.
The “Simple Format” interpolation syntax here uses {variable}, but the current built-in i18n implementations (e.g. createMemoryI18n in packages/core/src/fallbacks/memory-i18n.ts and FileI18nAdapter in packages/services/service-i18n/src/file-i18n-adapter.ts) interpolate {{variable}}. Update this section (and examples below) to match the actual {{paramName}} convention, or explicitly document the difference if {variable} is intended for a different implementation.
| Use `{variable}` placeholders: | |
| ```json | |
| { | |
| "messages": { | |
| "welcome": "Welcome, {userName}!", | |
| "pagination": "Showing {start} to {end} of {total} items" | |
| Use `{{paramName}}` placeholders: | |
| ```json | |
| { | |
| "messages": { | |
| "welcome": "Welcome, {{userName}}!", | |
| "pagination": "Showing {{start}} to {{end}} of {{total}} items" |
| ```typescript | ||
| i18n.t('messages.welcome', 'en', { userName: 'Alice' }); | ||
| // "Welcome, Alice!" |
There was a problem hiding this comment.
This usage example relies on the placeholder format described above; with the current runtime interpolation ({{paramName}}), the message template and/or this example call should be adjusted so that it matches what II18nService.t() actually replaces at runtime.
| | `defaultLocale` | `string` | `'en'` | Default BCP-47 locale code | | ||
| | `supportedLocales` | `string[]` | `['en']` | All supported locales | | ||
| | `fallbackLocale` | `string` | same as `defaultLocale` | Fallback when translation missing | |
There was a problem hiding this comment.
This table lists defaults for defaultLocale and supportedLocales, but in the actual TranslationConfigSchema (packages/spec/src/system/translation.zod.ts) those fields are required whenever i18n config is provided (only fileOrganization, messageFormat, lazyLoad, cache have schema defaults). Consider marking these as required and only documenting defaults for fields that truly default in the schema/runtime.
| | `defaultLocale` | `string` | `'en'` | Default BCP-47 locale code | | |
| | `supportedLocales` | `string[]` | `['en']` | All supported locales | | |
| | `fallbackLocale` | `string` | same as `defaultLocale` | Fallback when translation missing | | |
| | `defaultLocale` | `string` | Required | Default BCP-47 locale code | | |
| | `supportedLocales` | `string[]` | Required | All supported locales | | |
| | `fallbackLocale` | `string?` | — | Fallback when translation missing | |
| import { I18nServicePlugin } from '@objectstack/service-i18n'; | ||
|
|
||
| const kernel = new ObjectKernel(); | ||
| kernel.use(new I18nServicePlugin({ |
There was a problem hiding this comment.
ObjectKernel.use() is async (returns a Promise) in @objectstack/core; without await, plugin registration may race with kernel.bootstrap(). Update this snippet to await kernel.use(...) (or clarify if this is intentionally showing LiteKernel-style sync usage).
| kernel.use(new I18nServicePlugin({ | |
| await kernel.use(new I18nServicePlugin({ |
| Use the CLI or API to extract all translatable keys from your metadata: | ||
|
|
||
| ```bash | ||
| objectstack i18n extract --locale zh-CN --output i18n/zh-CN.json | ||
| ``` |
There was a problem hiding this comment.
These CLI commands (objectstack i18n extract/suggest/coverage) don’t appear to exist in the current CLI command set (packages/cli/src/commands has no i18n command). Either update this workflow to reference the actual commands/API endpoints available today, or clearly label these as planned/proposed commands to avoid sending readers down a dead end.
| The `II18nService.getCoverage()` method compares a translation bundle against source metadata to detect: | ||
|
|
||
| 1. **Missing** — Keys that exist in metadata but not in the translation bundle | ||
| 2. **Redundant** — Keys in the bundle that have no matching metadata | ||
| 3. **Stale** — Keys where the source metadata has changed since translation | ||
|
|
||
| ```typescript | ||
| const coverage = i18nService.getCoverage('zh-CN', 'account'); | ||
|
|
||
| console.log(coverage); | ||
| // { | ||
| // locale: 'zh-CN', | ||
| // objectName: 'account', | ||
| // totalKeys: 120, | ||
| // translatedKeys: 105, | ||
| // missingKeys: 12, | ||
| // redundantKeys: 3, | ||
| // staleKeys: 0, |
There was a problem hiding this comment.
This section treats II18nService.getCoverage() as a guaranteed capability, but the contract marks it optional and there is currently no implementation in the shipped i18n services (packages/services/service-i18n only implements t/getTranslations/loadTranslations/getLocales). Consider rephrasing as “if implemented” and advising callers to feature-detect (typeof i18nService.getCoverage === 'function') before calling.
| The `II18nService.getCoverage()` method compares a translation bundle against source metadata to detect: | |
| 1. **Missing** — Keys that exist in metadata but not in the translation bundle | |
| 2. **Redundant** — Keys in the bundle that have no matching metadata | |
| 3. **Stale** — Keys where the source metadata has changed since translation | |
| ```typescript | |
| const coverage = i18nService.getCoverage('zh-CN', 'account'); | |
| console.log(coverage); | |
| // { | |
| // locale: 'zh-CN', | |
| // objectName: 'account', | |
| // totalKeys: 120, | |
| // translatedKeys: 105, | |
| // missingKeys: 12, | |
| // redundantKeys: 3, | |
| // staleKeys: 0, | |
| If implemented by the active `II18nService`, the optional `getCoverage()` method can compare a translation bundle against source metadata to detect: | |
| 1. **Missing** — Keys that exist in metadata but not in the translation bundle | |
| 2. **Redundant** — Keys in the bundle that have no matching metadata | |
| 3. **Stale** — Keys where the source metadata has changed since translation | |
| Feature-detect `getCoverage()` before calling it: | |
| ```typescript | |
| if (typeof i18nService.getCoverage === 'function') { | |
| const coverage = i18nService.getCoverage('zh-CN', 'account'); | |
| console.log(coverage); | |
| // { | |
| // locale: 'zh-CN', | |
| // objectName: 'account', | |
| // totalKeys: 120, | |
| // translatedKeys: 105, | |
| // missingKeys: 12, | |
| // redundantKeys: 3, | |
| // staleKeys: 0, |
| ├── skills/ # 🤖 AI skill definitions (for Copilot/Cursor) | ||
| │ ├── objectstack-data/ | ||
| │ ├── objectstack-api/ | ||
| │ ├── objectstack-ui/ | ||
| │ ├── objectstack-automation/ |
There was a problem hiding this comment.
The “Monorepo Structure” skills list is labeled as “Current State” and the header says it was synced on 2026-04-13, but it omits existing skill directories (e.g. skills/objectstack-kernel/, skills/objectstack-quickstart/, skills/objectstack-hooks/). Either include the full set of skills here or make it explicit that the list is partial (e.g. add an ellipsis).
Created comprehensive skill documentation for internationalization (i18n) design in ObjectStack applications.
Changes
New Skill:
skills/objectstack-i18n/SKILL.md (696 lines) — Complete i18n design guide covering:
AppTranslationBundle,ObjectTranslationNode)II18nService.suggestTranslations(){variable}vs ICU MessageFormat)II18nServiceandI18nServicePluginReference schemas copied from
packages/spec/src/:system/translation.zod.ts— Translation bundle schemascontracts/i18n-service.ts— Service interface contractui/i18n.zod.ts— UI-level i18n schemasUpdated Custom Instructions
.github/copilot-instructions.md:Example Usage
Aligns with Salesforce/Dynamics 365 object-first translation conventions where all translatable content for an object is grouped under a single namespace (
o.{object_name}).