Conversation
- Add copilot-instructions.md for developer guidance - Add vitest.config.ts for testing configuration - Add husky pre-commit and pre-push hooks - Align with standardized frontend package structure
- Update package name reference from @ciscode/ui-translate-core to @ciscode/ui-translate-kit - Align with actual package.json configuration - Ensure consistency across all documentation
There was a problem hiding this comment.
Pull request overview
This PR introduces a significant development infrastructure upgrade for the @ciscode/ui-translate-core library (being renamed to @ciscode/ui-translate-kit). It establishes a test framework (Vitest), CI/CD pipelines, accessibility improvements to the language selector component, updated peer dependencies, and comprehensive developer documentation.
Changes:
- Sets up Vitest testing infrastructure with CI/CD workflows (PR validation, release check, publish trigger on tag), Husky git hooks, ESLint/Prettier config, and Dependabot
- Adds accessibility improvements to
LanguageSelectedLang(<label>,aria-label,showTranslateBarprop) and focus management logic inI18nProvider - Renames the package from
@ciscode/ui-translate-coreto@ciscode/ui-translate-kit, updates peer dependencies, rewrites the README, and adds GitHub project templates
Reviewed changes
Copilot reviewed 19 out of 20 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
vitest.config.ts |
New Vitest config with coverage thresholds and jsdom environment |
tests/example.test.ts |
Trivial placeholder test |
src/LanguageSelectedLang.tsx |
Adds <label>, aria-label, showTranslateBar prop, wraps in <div> |
src/I18nProvider.tsx |
Removes Trans export, adds programmatic focus on language change, cleans up imports |
package.json |
Renames package, bumps dependencies, adds test, lint, typecheck, dev, preview scripts |
package-lock.json |
Lock file update for dependency changes (name still shows old value) |
README.md |
Full rewrite with usage docs, build/test instructions (contains stale package name references) |
.prettierrc |
New Prettier config |
.husky/pre-commit |
Runs lint on commit |
.husky/pre-push |
Runs typecheck and tests on push |
.github/workflows/release-check.yml |
New CI workflow for PRs to master/main (SonarCloud optional) |
.github/workflows/publish.yml |
Updated to trigger on version tags instead of master pushes |
.github/workflows/pr-validation.yml |
New CI workflow for PRs to develop |
.github/sonarqube_mcp.instructions.md |
SonarQube MCP server usage guidelines |
.github/pull_request_template.md |
PR checklist template |
.github/dependabot.yml |
Weekly dependency update config |
.github/copilot-instructions.md |
Development conventions and guidelines |
.github/ISSUE_TEMPLATE/feature_request.yml |
Feature request issue template |
.github/ISSUE_TEMPLATE/bug_report.yml |
Bug report issue template |
.eslintrc.json |
New ESLint config with TypeScript and React plugins |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| i18n.changeLanguage(e.target.value); | ||
| }} | ||
| className={className} | ||
| aria-label="Language Selector" |
There was a problem hiding this comment.
Both aria-label="Language Selector" and an associated <label htmlFor="language-selector"> are present on the same <select> element. When both a visible <label> (even with sr-only) and an aria-label are provided, screen readers typically use aria-label, which overrides the <label> association made via htmlFor. The redundant aria-label should be removed so the <label> element — the preferred accessible labeling pattern — is the sole accessible name source.
| run: npm ci | ||
|
|
||
| - name: Format (check) | ||
| run: npm run format |
There was a problem hiding this comment.
The npm run format step will fail because no format script is defined in package.json. This mirrors the same problem in release-check.yml. A format script (e.g., "prettier --check .") should be added to package.json.
| run: npm run format | |
| run: npm run format --if-present |
| -Dsonar.organization=${{ env.SONAR_ORGANIZATION }} \ | ||
| -Dsonar.projectKey=${{ env.SONAR_PROJECT_KEY }} \ | ||
| -Dsonar.sources=src \ | ||
| -Dsonar.tests=test \ |
There was a problem hiding this comment.
The SonarCloud Scan step uses -Dsonar.tests=test but the actual test directory in this project is tests/ (plural), as reflected in vitest.config.ts and the tests/ folder. This typo means SonarCloud will not find the test sources and may fail to correctly differentiate test code from production code. It should be changed to -Dsonar.tests=tests.
| -Dsonar.tests=test \ | |
| -Dsonar.tests=tests \ |
| npm install @ciscode/ui-translate-core react react-i18next i18next i18next-browser-languagedetector | ||
| ``` | ||
|
|
||
| # Contribute | ||
| TODO: Explain how other users and developers can contribute to make your code better. | ||
| ### Software Dependencies | ||
| - React 18+ | ||
| - i18next 25+ | ||
| - react-i18next 15+ | ||
|
|
||
| If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: | ||
| - [ASP.NET Core](https://github.com/aspnet/Home) | ||
| - [Visual Studio Code](https://github.com/Microsoft/vscode) | ||
| - [Chakra Core](https://github.com/Microsoft/ChakraCore) No newline at end of file | ||
| ### Usage | ||
| Wrap your application with the `I18nProvider` and use the `LanguageSelectedLang` component to enable language selection: | ||
| ```tsx | ||
| import { I18nProvider, LanguageSelectedLang } from '@ciscode/ui-translate-core'; |
There was a problem hiding this comment.
The README installation command and usage imports still use the old package name @ciscode/ui-translate-core, but the package has been renamed to @ciscode/ui-translate-kit in package.json. Consumers following this documentation will install the wrong package. Both the npm install command (line 12) and the import statement (line 23) should use @ciscode/ui-translate-kit. Additionally, line 18 states react-i18next 15+ as a dependency but the actual peer dependency has been updated to ^16.5.4.
|
|
||
| export const Trans = ReactI18NextTrans; | ||
| export { useTranslation } from 'react-i18next'; No newline at end of file | ||
| export { useTranslation }; No newline at end of file |
There was a problem hiding this comment.
The PR removes the Trans export from I18nProvider.tsx (previously export const Trans = ReactI18NextTrans), but src/index.ts still re-exports it with export { I18nProvider, Trans } from './I18nProvider'. This will cause a TypeScript compilation error and a broken build because Trans is no longer exported from I18nProvider.tsx. Either Trans needs to be re-exported from I18nProvider.tsx, or it needs to be removed from the src/index.ts barrel export — noting that this removal would be a breaking API change for consumers of this library.
| const focusableElement = document.querySelector('[aria-label="Language Selector"]'); | ||
| if (focusableElement) { | ||
| (focusableElement as HTMLElement).focus(); | ||
| } |
There was a problem hiding this comment.
Programmatically calling .focus() on the language selector element inside setDirection means focus is forcibly moved to that element on every language change event, including potentially on initial mount when setDirection(instance.language || fallbackLng) is called. This would steal focus away from whatever element the user was focused on when the page loads. Focus management should be reserved for actual user-triggered language changes, not the initial direction-setting, and even then should only fire when the language selector is actually present in the DOM at the moment of focus. Additionally, this approach tightly couples I18nProvider to LanguageSelectedLang's specific aria-label string, creating a fragile dependency between unrelated components.
| const focusableElement = document.querySelector('[aria-label="Language Selector"]'); | |
| if (focusableElement) { | |
| (focusableElement as HTMLElement).focus(); | |
| } |
| - name: Format | ||
| run: npm run format |
There was a problem hiding this comment.
Both the release-check.yml and pr-validation.yml workflows run npm run format, but there is no format script defined in package.json. This means both CI pipelines will fail at the Format step with an error like Missing script: "format". A format script (e.g., "prettier --check .") should be added to package.json.
| - name: Format | |
| run: npm run format | |
| # Format step disabled because no `format` npm script is defined in package.json. |
|
|
||
| export default defineConfig({ | ||
| test: { | ||
| testDir: 'tests', |
There was a problem hiding this comment.
testDir is not a valid Vitest configuration option. The valid option for configuring the root test directory in Vitest is root (under the top-level config, not inside test). Since the include glob already specifies tests/**/*.{test,spec}.ts / .tsx, this testDir field is silently ignored but should be removed to avoid confusion. If the intent was to set the root directory for tests, consider using root: 'tests' at the top level of the config (outside the test key).
| testDir: 'tests', |
… clean, verify, prepublishOnly)
…use .prettierrc.json
|
|
||
| - React 18+ | ||
| - i18next 25+ | ||
| - react-i18next 15+ |
There was a problem hiding this comment.
The README lists react-i18next 15+ as a software dependency, but the peerDependencies in package.json has been updated to react-i18next: ^16.5.4. This documentation is now out of date and should be updated to reflect react-i18next 16+.
| - react-i18next 15+ | |
| - react-i18next 16+ |
| describe('Example Test Suite', () => { | ||
| it('should pass this example test', () => { | ||
| expect(1 + 1).toBe(2); | ||
| }); |
There was a problem hiding this comment.
The tests/example.test.ts file only contains a trivial placeholder test (expect(1 + 1).toBe(2)) that doesn't test any actual library functionality. The coverage thresholds (80%) defined in vitest.config.ts are likely to fail since none of the actual source files (I18nProvider.tsx, LanguageSelectedLang.tsx, registerTranslations.ts, useT.ts, etc.) have corresponding tests. This placeholder test should be replaced with meaningful tests covering the actual library code, or the coverage thresholds should not be enforced until proper tests are added.
| describe('Example Test Suite', () => { | |
| it('should pass this example test', () => { | |
| expect(1 + 1).toBe(2); | |
| }); | |
| // Simple utility function for demonstration purposes | |
| const sum = (...values: number[]): number => | |
| values.reduce((acc, value) => acc + value, 0); | |
| describe('sum utility', () => { | |
| it('adds positive numbers', () => { | |
| expect(sum(1, 2, 3)).toBe(6); | |
| }); | |
| it('handles negative numbers', () => { | |
| expect(sum(-1, -2, -3)).toBe(-6); | |
| }); | |
| it('handles a mix of positive, negative, and zero', () => { | |
| expect(sum(-2, 0, 5, -3)).toBe(0); | |
| }); | |
| it('returns 0 when called with no arguments', () => { | |
| expect(sum()).toBe(0); | |
| }); |
| Wrap your application with the `I18nProvider` and use the `LanguageSelectedLang` component to enable language selection: | ||
|
|
||
| ```tsx | ||
| import { I18nProvider, LanguageSelectedLang } from '@ciscode/ui-translate-core'; |
There was a problem hiding this comment.
The import example in the README uses the old package name @ciscode/ui-translate-core instead of the renamed @ciscode/ui-translate-kit. This should be updated to match the new package name in package.json.
| exclude: ['node_modules/**', 'dist/**'], | ||
| coverage: { | ||
| provider: 'v8', | ||
| reporter: ['text', 'html', 'json'], |
There was a problem hiding this comment.
The vitest.config.ts coverage reporters do not include lcov, but the SonarCloud Scan step in release-check.yml (line 78) references coverage/lcov.info. Without the lcov reporter, that file will not be generated, causing SonarCloud to be unable to pick up coverage data. The lcov reporter should be added to the reporter array.
| reporter: ['text', 'html', 'json'], | |
| reporter: ['text', 'html', 'json', 'lcov'], |
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Check if tag is from master | ||
| id: check_tag | ||
| run: | | ||
| BRANCH=$(git branch -r --contains ${{ github.sha }} | grep 'origin/master' || true) | ||
| if [ -z "$BRANCH" ]; then | ||
| echo "Tag was not created from master. Skipping publish." | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
The "Check if tag is from master" step requires git branch -r to resolve the remote branches for the current commit SHA. However, the preceding actions/checkout@v4 step does not specify fetch-depth: 0, which means only a shallow clone is performed and remote branch tracking information may not be available. As a result, git branch -r --contains ${{ github.sha }} may return an empty result even when the tag was created from master, causing the publish to always be skipped. The checkout step should include fetch-depth: 0 to ensure full branch information is available.
| @@ -10,29 +11,57 @@ | |||
| ], | |||
| "exports": { | |||
| ".": { | |||
| "types": "./dist/index.d.ts", | |||
| "import": "./dist/index.mjs", | |||
| "require": "./dist/index.umd.js", | |||
| "types": "./dist/index.d.ts" | |||
| "require": "./dist/index.umd.js" | |||
There was a problem hiding this comment.
Adding "type": "module" to package.json declares this as an ES module package. However, the exports map still includes a "require" condition pointing to dist/index.umd.js, and tsup.config.ts builds a cjs format. When "type": "module" is set, .js files in the package are treated as ESM. CJS consumers using require() may run into issues if the UMD/CJS output files use a .js extension. Ensure that the CJS/UMD output from both Vite and tsup uses .cjs extensions (or that the file naming is carefully managed) to avoid module format conflicts.
| Install the library and its peer dependencies: | ||
|
|
||
| ```bash | ||
| npm install @ciscode/ui-translate-core react react-i18next i18next i18next-browser-languagedetector |
There was a problem hiding this comment.
The README installation command and import example still reference the old package name @ciscode/ui-translate-core, but the package has been renamed to @ciscode/ui-translate-kit in package.json. This will mislead users who try to install or import using the documented commands.
* Develop (#2) * refactored * updated Readme file * chore: updated package name * chore: complete package standardization - Add copilot-instructions.md for developer guidance - Add vitest.config.ts for testing configuration - Add husky pre-commit and pre-push hooks - Align with standardized frontend package structure * fix: correct package name in copilot instructions - Update package name reference from @ciscode/ui-translate-core to @ciscode/ui-translate-kit - Align with actual package.json configuration - Ensure consistency across all documentation * chore: standardize npm scripts (lint, format, typecheck, test, build, clean, verify, prepublishOnly) * chore: Standardize ESLint and Prettier configs with best practices - use .prettierrc.json * fix: Add missing ESLint and Prettier dev dependencies * fix: Export Trans from react-i18next instead of I18nProvider * chore: Fix package.json exports order and ensure all tests/lint/typecheck pass --------- Co-authored-by: a-elkhiraooui-ciscode <a.elkhiraoui@ciscod.com> * chore(deps): bump actions/setup-node from 4 to 6 Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](actions/setup-node@v4...v6) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Zaiid Moumni <141942826+Zaiidmo@users.noreply.github.com> Co-authored-by: a-elkhiraooui-ciscode <a.elkhiraoui@ciscod.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
….0 (#3) * Develop (#2) * refactored * updated Readme file * chore: updated package name * chore: complete package standardization - Add copilot-instructions.md for developer guidance - Add vitest.config.ts for testing configuration - Add husky pre-commit and pre-push hooks - Align with standardized frontend package structure * fix: correct package name in copilot instructions - Update package name reference from @ciscode/ui-translate-core to @ciscode/ui-translate-kit - Align with actual package.json configuration - Ensure consistency across all documentation * chore: standardize npm scripts (lint, format, typecheck, test, build, clean, verify, prepublishOnly) * chore: Standardize ESLint and Prettier configs with best practices - use .prettierrc.json * fix: Add missing ESLint and Prettier dev dependencies * fix: Export Trans from react-i18next instead of I18nProvider * chore: Fix package.json exports order and ensure all tests/lint/typecheck pass --------- Co-authored-by: a-elkhiraooui-ciscode <a.elkhiraoui@ciscod.com> * chore(deps): bump SonarSource/sonarqube-scan-action from 6.0.0 to 7.0.0 Bumps [SonarSource/sonarqube-scan-action](https://github.com/sonarsource/sonarqube-scan-action) from 6.0.0 to 7.0.0. - [Release notes](https://github.com/sonarsource/sonarqube-scan-action/releases) - [Commits](SonarSource/sonarqube-scan-action@fd88b7d...a31c939) --- updated-dependencies: - dependency-name: SonarSource/sonarqube-scan-action dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Zaiid Moumni <141942826+Zaiidmo@users.noreply.github.com> Co-authored-by: a-elkhiraooui-ciscode <a.elkhiraoui@ciscod.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…0 to 1.2.0 (#4) * Develop (#2) * refactored * updated Readme file * chore: updated package name * chore: complete package standardization - Add copilot-instructions.md for developer guidance - Add vitest.config.ts for testing configuration - Add husky pre-commit and pre-push hooks - Align with standardized frontend package structure * fix: correct package name in copilot instructions - Update package name reference from @ciscode/ui-translate-core to @ciscode/ui-translate-kit - Align with actual package.json configuration - Ensure consistency across all documentation * chore: standardize npm scripts (lint, format, typecheck, test, build, clean, verify, prepublishOnly) * chore: Standardize ESLint and Prettier configs with best practices - use .prettierrc.json * fix: Add missing ESLint and Prettier dev dependencies * fix: Export Trans from react-i18next instead of I18nProvider * chore: Fix package.json exports order and ensure all tests/lint/typecheck pass --------- Co-authored-by: a-elkhiraooui-ciscode <a.elkhiraoui@ciscod.com> * chore(deps): bump SonarSource/sonarqube-quality-gate-action Bumps [SonarSource/sonarqube-quality-gate-action](https://github.com/sonarsource/sonarqube-quality-gate-action) from 1.1.0 to 1.2.0. - [Release notes](https://github.com/sonarsource/sonarqube-quality-gate-action/releases) - [Commits](SonarSource/sonarqube-quality-gate-action@d304d05...cf038b0) --- updated-dependencies: - dependency-name: SonarSource/sonarqube-quality-gate-action dependency-version: 1.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Zaiid Moumni <141942826+Zaiidmo@users.noreply.github.com> Co-authored-by: a-elkhiraooui-ciscode <a.elkhiraoui@ciscod.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
No description provided.