Skip to content
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

feat: support cjs and esm both by tshy #14

Merged
merged 5 commits into from
Jan 11, 2025
Merged

feat: support cjs and esm both by tshy #14

merged 5 commits into from
Jan 11, 2025

Conversation

fengmk2
Copy link
Member

@fengmk2 fengmk2 commented Jan 11, 2025

BREAKING CHANGE: drop Node.js < 18.19.0 support

part of eggjs/egg#3644

eggjs/egg#5257

Summary by CodeRabbit

Based on the comprehensive changes, here are the updated release notes:

  • New Features

    • Migrated package to TypeScript with improved type safety.
    • Enhanced internationalization (i18n) support with more flexible configuration.
    • Added comprehensive GitHub Actions workflows for CI/CD.
  • Improvements

    • Updated Node.js compatibility to version 18.19.0+.
    • Modernized module system with ES module support.
    • Refined configuration and localization mechanisms.
  • Breaking Changes

    • Package renamed from egg-i18n to @eggjs/i18n.
    • Switched from CommonJS to ES module syntax.
    • Removed legacy configuration files and testing infrastructure.
  • Chores

    • Cleaned up and simplified project structure.
    • Updated dependencies and development tooling.
    • Improved documentation and README.

BREAKING CHANGE: drop Node.js < 18.19.0 support

part of eggjs/egg#3644

eggjs/egg#5257
Copy link

coderabbitai bot commented Jan 11, 2025

Warning

Rate limit exceeded

@fengmk2 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 8 minutes and 4 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between a27747e and ca3b3f0.

📒 Files selected for processing (4)
  • README.md (4 hunks)
  • package.json (2 hunks)
  • src/types.ts (1 hunks)
  • test/i18n.test.ts (1 hunks)

Walkthrough

The pull request represents a comprehensive modernization of the @eggjs/i18n package, transitioning from a JavaScript-based implementation to a TypeScript-first approach. The changes include migrating configuration files, updating continuous integration workflows, refactoring the internationalization implementation, and adopting modern module systems. The project now supports Node.js versions 18.19.0 and above, with enhanced type safety and improved development workflows.

Changes

File/Directory Change Summary
.autod.conf.js Deleted configuration file for dependency management
.eslintignore Added test/fixtures and coverage to ignored directories
.eslintrc Updated ESLint configuration to use TypeScript and Node.js prefix enforcement
.github/workflows/nodejs.yml, .github/workflows/pkg.pr.new.yml, .github/workflows/release.yml Added new CI/CD workflows for Node.js testing, package publishing, and release management
.gitignore Updated with new file and directory exclusion patterns
.travis.yml, appveyor.yml Removed legacy CI configuration files
README.md Updated package name, badges, and documentation syntax
package.json Major restructuring with new dependencies, scripts, and module exports
src/ Introduced TypeScript implementation with new class-based approach
test/ Updated test suite to use TypeScript and modern testing practices
tsconfig.json Added TypeScript configuration with strict type checking

Sequence Diagram

sequenceDiagram
    participant App as Application
    participant I18n as I18n Plugin
    participant Locale as Locale Files
    participant Context as Request Context

    App->>I18n: Initialize
    I18n->>Locale: Load Translation Files
    Context->>I18n: Request Locale
    I18n->>Context: Provide Translation Method
    Context->>Locale: Retrieve Translated String
    Locale-->>Context: Return Localized Text
Loading

Poem

🐰 A Rabbit's Ode to Internationalization 🌍
From JavaScript to TypeScript we leap,
Locales dancing, no language too steep!
Workflows singing, dependencies bright,
Egg's i18n now shines with delight!
Multilingual magic, code clean and neat! 🚀


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

socket-security bot commented Jan 11, 2025

New, updated, and removed dependencies detected. Learn more about Socket for GitHub ↗︎

Package New capabilities Transitives Size Publisher
npm/@arethetypeswrong/[email protected] Transitive: environment, filesystem, network, shell, unsafe +49 31.4 MB andrewbranch
npm/@eggjs/[email protected] environment Transitive: eval, filesystem, network, shell, unsafe +228 20.6 MB fengmk2
npm/@eggjs/[email protected] environment Transitive: eval, filesystem, network, unsafe +90 4.3 MB fengmk2
npm/@eggjs/[email protected] environment Transitive: eval, filesystem, network, shell, unsafe +177 13.7 MB fengmk2
npm/@eggjs/[email protected] None 0 4.23 kB fengmk2
npm/@eggjs/[email protected] environment 0 143 kB fengmk2
npm/@types/[email protected] None 0 4.29 kB types
npm/@types/[email protected] None 0 9.12 kB types
npm/@types/[email protected] None 0 96.1 kB types
npm/@types/[email protected] None +1 2.37 MB types
npm/[email protected] 🔁 npm/[email protected] Transitive: environment, eval, shell +201 18.8 MB fengmk2
npm/[email protected] 🔁 npm/[email protected] Transitive: environment, eval, filesystem, unsafe +174 18.8 MB fengmk2
npm/[email protected] 🔁 npm/[email protected] environment Transitive: eval, shell +93 10.2 MB eslintbot
npm/[email protected] None +1 14 kB fengmk2
npm/[email protected] None 0 12.1 kB npm-cli-ops
npm/[email protected] 🔁 npm/[email protected] Transitive: environment, filesystem +1 576 kB vitaly
npm/[email protected] 🔁 npm/[email protected] environment Transitive: shell +29 2.55 MB isaacs
npm/[email protected] None 0 27.6 kB fengmk2
npm/[email protected] environment, filesystem, shell Transitive: unsafe +49 3.19 MB isaacs
npm/[email protected] None 0 22.7 MB andrewbranch, minestarks, rbuckton, ...5 more

View full report↗︎

Copy link

pkg-pr-new bot commented Jan 11, 2025

Open in Stackblitz

npm i https://pkg.pr.new/eggjs/i18n/@eggjs/i18n@14

commit: ca3b3f0

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (4)
src/config/config.default.ts (1)

3-12: Consider using type declaration instead of type assertion

While the type assertion works, consider declaring the type directly for better type safety:

-export default {
+export default <I18nConfig>{
   i18n: {
     defaultLocale: 'en_US',
     dirs: [],
     queryField: 'locale',
     cookieField: 'locale',
     cookieDomain: '',
     cookieMaxAge: '1y',
-  } as I18nConfig,
+  },
 };
test/fixtures/custom_egg/index.js (1)

24-28: Consider simplifying the startCluster function

The function could be simplified by using object spread and default parameters:

-export function startCluster(options, callback) {
-  options = options || {};
-  options.customEgg = EGG_PATH;
-  _startCluster(options, callback);
+export function startCluster(options = {}, callback) {
+  _startCluster({ ...options, customEgg: EGG_PATH }, callback);
 }
src/types.ts (1)

66-69: Track technical debt for koa-locales refactor

There's a TODO comment about removing methods after koa-locales refactor. Consider creating an issue to track this technical debt.

Would you like me to create a GitHub issue to track the koa-locales refactor work?

.github/workflows/pkg.pr.new.yml (1)

1-2: Optimize workflow trigger conditions.

The workflow currently runs on both push and pull request events without any conditions. Consider:

  1. Limiting to specific branches for push events
  2. Adding conditions to check if package version has changed
 name: Publish Any Commit
-on: [push, pull_request]
+on:
+  push:
+    branches: [ master ]
+    paths:
+      - 'package.json'
+  pull_request:
+    branches: [ master ]
+    paths:
+      - 'package.json'
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7ddd9f8 and 964165c.

📒 Files selected for processing (27)
  • .autod.conf.js (0 hunks)
  • .eslintignore (1 hunks)
  • .eslintrc (1 hunks)
  • .github/workflows/nodejs.yml (1 hunks)
  • .github/workflows/pkg.pr.new.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • .gitignore (1 hunks)
  • .travis.yml (0 hunks)
  • README.md (4 hunks)
  • app.js (0 hunks)
  • app/middleware/i18n.js (0 hunks)
  • appveyor.yml (0 hunks)
  • config/config.default.js (0 hunks)
  • package.json (2 hunks)
  • src/app.ts (1 hunks)
  • src/app/extend/context.ts (1 hunks)
  • src/config/config.default.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/types.ts (1 hunks)
  • src/typings/index.d.ts (1 hunks)
  • test/fixtures/apps/i18n/app/controller/message.js (0 hunks)
  • test/fixtures/apps/i18n/config/locales/zh-CN.js (1 hunks)
  • test/fixtures/custom_egg/config/locales/zh-CN.js (1 hunks)
  • test/fixtures/custom_egg/index.js (1 hunks)
  • test/fixtures/custom_egg/package.json (1 hunks)
  • test/i18n.test.ts (6 hunks)
  • tsconfig.json (1 hunks)
💤 Files with no reviewable changes (7)
  • appveyor.yml
  • .travis.yml
  • app/middleware/i18n.js
  • config/config.default.js
  • test/fixtures/apps/i18n/app/controller/message.js
  • .autod.conf.js
  • app.js
✅ Files skipped from review due to trivial changes (5)
  • src/typings/index.d.ts
  • .eslintignore
  • src/index.ts
  • .eslintrc
  • tsconfig.json
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Node.js / Test (windows-latest, 22)
  • GitHub Check: Node.js / Test (windows-latest, 20)
  • GitHub Check: Node.js / Test (windows-latest, 18.19.0)
🔇 Additional comments (19)
src/app.ts (1)

6-6: Verify that exists is an asynchronous function

Ensure that the exists function imported from 'utility' returns a Promise since you're using await exists(localePath).

If exists is synchronous, using await won't have the intended effect. Please verify the implementation of exists.

test/fixtures/custom_egg/config/locales/zh-CN.js (1)

1-3: Ensure ES module syntax is supported in your environment

Changing the export from module.exports to export default requires that your Node.js environment and module loader support ES modules for this file.

Ensure that your project is configured to handle ES module syntax for .js files, or consider renaming the file to .mjs or adding "type": "module" in your package.json.

test/fixtures/apps/i18n/config/locales/zh-CN.js (1)

6-6: Translation key added correctly

The new translation for "Hello %s, how are you today? How was your %s." has been added properly.

src/config/config.default.ts (1)

1-12: LGTM! Configuration structure is well-defined

The default configuration provides sensible defaults and follows ESM best practices with the .js extension in the import path.

src/app/extend/context.ts (1)

1-16: LGTM! Well-structured TypeScript implementation

The context extension is properly typed and documented. The getter/setter pattern is well implemented with proper type safety.

test/fixtures/custom_egg/index.js (1)

1-28: LGTM! Proper ESM migration

The migration to ESM follows best practices:

  • Uses node: protocol for built-in modules
  • Properly handles ESM paths with fileURLToPath
  • Clean export syntax
src/types.ts (1)

1-70: LGTM! Well-documented type definitions

The type definitions are comprehensive and well-documented:

  • Clear interface definitions with detailed JSDoc comments
  • Proper module augmentation for @eggjs/core
  • Type-safe method signatures
test/i18n.test.ts (4)

1-7: Well-structured ESM imports and module setup!

The code follows Node.js best practices for ES modules by:

  • Using the node: protocol for core modules
  • Properly handling __filename and __dirname in ESM context

9-16: Good use of TypeScript and modern async patterns!

The test suite setup demonstrates good practices with:

  • Explicit typing of the app variable
  • Use of async/await in hooks

58-74: Well-structured test for cookie-based locale!

The new test case thoroughly verifies locale retrieval from cookies with comprehensive assertions.


24-24: Verify cookie expiration behavior with max-age

The change from using only expires to including max-age is good practice. However, please verify that:

  1. The max-age=31557600 (1 year) aligns with your session management requirements
  2. Both max-age and expires are necessary for your browser compatibility needs

Also applies to: 43-43, 92-92, 111-111

✅ Verification successful

Cookie expiration configuration is correctly implemented

The cookie settings align with the codebase configuration:

  • cookieMaxAge: '1y' in default config correctly translates to max-age=31557600
  • Both max-age and expires are intentionally used for broad browser compatibility
  • The implementation allows flexible configuration via cookieMaxAge setting
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for consistent cookie expiration across the codebase
rg -l "max-age=31557600" | while read -r file; do
  echo "=== $file ==="
  rg "max-age=31557600|expires=" "$file"
done

Length of output: 1398


Script:

#!/bin/bash
# Find cookie-related implementation files and cookie setting code
echo "=== Searching for cookie/locale related files ==="
fd -e ts -e js -E '*.test.*' -E '*.spec.*' | xargs rg -l "setCookie|cookie|locale" || true

echo -e "\n=== Searching for cookie setting implementation ==="
ast-grep -p 'ctx.cookies.set($$$)' || true

Length of output: 689


Script:

#!/bin/bash
echo "=== Checking context extension implementation ==="
cat src/app/extend/context.ts

echo -e "\n=== Checking default configuration ==="
cat src/config/config.default.ts

echo -e "\n=== Searching for alternative cookie patterns ==="
rg "cookie" -A 5 -B 5 src/

Length of output: 3494

test/fixtures/custom_egg/package.json (1)

2-3: Verify ESM compatibility across the test fixtures

The addition of "type": "module" is necessary for ESM support. However, please verify that:

  1. All JavaScript files in the custom_egg fixture are ESM-compatible
  2. No CommonJS-specific features are used that might break
✅ Verification successful

ESM compatibility verified in custom_egg fixture

The "type": "module" declaration is correct and necessary as the fixture uses ESM features:

  • Native ESM imports from node: modules
  • Multiple export statements including classes and functions
  • No CommonJS patterns that could cause issues
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for potential CommonJS usage in the test fixture
echo "=== Checking for require() calls ==="
rg "require\(" "test/fixtures/custom_egg"

echo "=== Checking for module.exports ==="
rg "module\.exports" "test/fixtures/custom_egg"

echo "=== Checking for exports. assignments ==="
rg "exports\." "test/fixtures/custom_egg"

Length of output: 388


Script:

#!/bin/bash
# List all JavaScript files
echo "=== JavaScript files in custom_egg ==="
fd -e js . "test/fixtures/custom_egg"

echo -e "\n=== Checking for import statements ==="
rg "^import\s+.*from\s+" "test/fixtures/custom_egg" -n

echo -e "\n=== Checking for export statements ==="
rg "^export\s+" "test/fixtures/custom_egg" -n

Length of output: 951

.gitignore (1)

1-11: Comprehensive .gitignore patterns!

The updated .gitignore includes all necessary patterns for:

  • TypeScript build artifacts
  • Development tools
  • Dependency management
  • Test coverage
.github/workflows/release.yml (1)

1-13: Verify release workflow configuration

The workflow is well-structured but please verify:

  1. The required secrets (NPM_TOKEN, GIT_TOKEN) are configured in the repository
  2. The shared workflow from eggjs/github-actions is compatible with the new ESM setup
.github/workflows/nodejs.yml (1)

13-14: LGTM! Node.js version range aligns with project requirements.

The Node.js versions (18.19.0, 20, 22) align well with the PR objective of dropping support for older versions. The range covers both LTS and latest versions.

package.json (3)

9-13: LGTM! Well-structured exports configuration.

The eggPlugin exports configuration correctly defines paths for both ESM and CommonJS modules, with TypeScript source support.


71-83: Verify dual package hazards.

The exports field correctly defines both ESM and CommonJS entry points. However, we should verify for dual package hazards.

✅ Verification successful

Dual package hazard verification completed successfully

The package correctly implements dual-package support following Node.js best practices, with clean separation between ESM and CommonJS modules, consistent file extensions, and proper type definitions for both formats. No hazardous patterns were detected in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for dual package hazards using @arethetypeswrong/cli
# This tool is already in devDependencies

npx attw --pack

Length of output: 111


Script:

#!/bin/bash
# Check for mixed import/require usage and re-export patterns
echo "=== Checking for mixed import/require usage ==="
rg "require\(" -A 2 -B 2
echo -e "\n=== Checking for import statements ==="
rg "import .* from" -A 2 -B 2
echo -e "\n=== Checking for re-export patterns ==="
rg "export \* from|export \{.*\} from" -A 2 -B 2

echo -e "\n=== Checking index files for export patterns ==="
fd "index\.(js|ts|mjs|cjs)$" --exec cat {}

Length of output: 3154


34-36: Verify dependency compatibility.

Need to verify if the dependencies support both ESM and CommonJS formats.

✅ Verification successful

Dependencies are compatible with project's ESM setup

  • @eggjs/core and utility packages fully support both ESM and CommonJS
  • koa-locales is CommonJS-only but works in ESM context through Node.js module interop
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if dependencies support both ESM and CJS

# Check @eggjs/core
npx attw --dependency @eggjs/core

# Check koa-locales
npx attw --dependency koa-locales

# Check utility
npx attw --dependency utility

Length of output: 386


Script:

#!/bin/bash
# Search for import/require patterns for these dependencies
echo "=== Import/Require Patterns ==="
rg -A 2 "require\(['\"]@eggjs/core['\"]\)|import .* from ['\"]@eggjs/core['\"]" || true
rg -A 2 "require\(['\"]koa-locales['\"]\)|import .* from ['\"]koa-locales['\"]" || true
rg -A 2 "require\(['\"]utility['\"]\)|import .* from ['\"]utility['\"]" || true

# Check if there are any .mjs or .cjs files
echo -e "\n=== Module File Extensions ==="
fd "\.(mjs|cjs)$" || true

# Look for type:module in package.json
echo -e "\n=== Package Type ==="
rg "\"type\":\s*\"module\"" package.json || true

Length of output: 1131


Script:

#!/bin/bash
# Fetch package info from npm registry
echo "=== @eggjs/core Package Info ==="
curl -s https://registry.npmjs.org/@eggjs/core/6.2.13 | jq '.exports, .type, .main, .module'

echo -e "\n=== koa-locales Package Info ==="
curl -s https://registry.npmjs.org/koa-locales/1.12.0 | jq '.exports, .type, .main, .module'

echo -e "\n=== utility Package Info ==="
curl -s https://registry.npmjs.org/utility/2.4.0 | jq '.exports, .type, .main, .module'

Length of output: 1188

README.md (1)

141-143: LGTM! Clear priority documentation.

The documentation clearly explains the priority order for language selection through query parameters, cookies, and headers.

src/app.ts Outdated Show resolved Hide resolved
src/app.ts Show resolved Hide resolved
src/app.ts Show resolved Hide resolved
README.md Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (2)
src/app.ts (2)

80-84: ⚠️ Potential issue

Add only existing directories to i18nConfig.dirs

The code adds localePath to i18nConfig.dirs without confirming its existence.


92-94: ⚠️ Potential issue

Handle potential null values without using non-null assertion operator

The use of non-null assertion operator (!) should be avoided.

🧹 Nitpick comments (14)
src/locales.ts (4)

18-20: Consider Prepending options.dir to localeDirs

Currently, if options.dir is specified and not already included in localeDirs, it is added to the end of the array. If you want options.dir to take precedence over other directories, consider adding it to the beginning of the array.

Apply this diff to prepend options.dir:

-    localeDirs.push(options.dir);
+    localeDirs.unshift(options.dir);

22-25: Add Error Handling for Directory Existence Check

While checking if each directory exists using await exists(dir), there is no error handling in case of exceptions (e.g., permission issues). Consider wrapping this in a try-catch block to handle potential errors gracefully.

Apply this diff to add error handling:

-    if (!(await exists(dir))) {
-      continue;
-    }
+    try {
+      if (!(await exists(dir))) {
+        continue;
+      }
+    } catch (err) {
+      console.error(`Error accessing directory ${dir}:`, err);
+      continue;
+    }

34-44: Handle Unsupported File Types

Currently, files with unsupported extensions are silently ignored. It might be beneficial to log a warning or handle such cases explicitly, so that any unexpected files are accounted for, and potential misconfigurations are easier to debug.

Apply this diff to log a warning for unsupported file types:

          } else if (name.endsWith('.yml') || name.endsWith('.yaml')) {
            resource = flattening(yaml.load(await fs.readFile(filepath, 'utf8')));
          } else {
+           console.warn(`Unsupported file type for locale: ${filepath}`);
          }

55-73: Specify Types in flattening Function for Type Safety

The flattening function currently uses any types, which reduces type safety. Specify the parameter and return types to improve type checking and maintainability.

Apply this diff to add explicit types:

- function flattening(data: any) {
+ function flattening(data: Record<string, any>): Record<string, string> {

And update the deepFlat function accordingly:

      function deepFlat(data: any, prefix: string) {
src/app/extend/application.ts (1)

69-91: Handle Missing Values in formatWithObject Function

In formatWithObject, if a placeholder doesn't have a corresponding value in the values object, it returns the original placeholder. Consider providing a default value or throwing an error to handle missing values more gracefully.

Apply this diff to provide a default value:

        const value = values[matched];
-       if (value) {
+       if (value !== undefined) {
          return value;
        }

Or consider logging a warning:

        if (value !== undefined) {
          return value;
        }
+       console.warn(`No value provided for placeholder: ${matched}`);
src/app/extend/context.ts (1)

88-157: Refactor Locale Determination Logic for Readability

The __getLocale method contains complex logic with nested conditions. Breaking it down into smaller helper methods can improve readability and maintainability.

Consider extracting parts of the logic into separate functions:

  • getLocaleFromQuery()
  • getLocaleFromCookie()
  • getLocaleFromHeader()
  • normalizeLocale(locale: string): string

This refactoring will make each method easier to understand and test.

test/i18n.test.ts (2)

81-81: Avoid redeclaring the app variable in nested describe blocks

The app variable is already declared in the outer scope at line 10. Redeclaring it within nested describe blocks at lines 81 and 130 can lead to confusion or unintended side effects. Consider reusing the existing app variable or using a different variable name within these blocks.

Also applies to: 130-130


290-303: Improve test readability by avoiding hardcoded assertions

In the test starting at line 290, multiple assertions check for specific cookie header patterns. Using regular expressions directly in assertions can make the test less readable and maintainable. Consider using helper functions or constants to improve clarity.

src/utils.ts (1)

1-1: Consider using unknown instead of any for isObject parameter

Using unknown instead of any provides better type safety and encourages explicit type checking within the function.

Apply this diff if you agree:

-export function isObject(obj: any) {
+export function isObject(obj: unknown) {
   return Object.prototype.toString.call(obj) === '[object Object]';
 }
src/config/config.default.ts (1)

3-15: Consider improving type safety and documentation.

  1. Replace type assertion with explicit typing for better type safety.
  2. Add inline documentation for default values.

Apply this diff:

-export default {
+export default <const>{
   i18n: {
+    // Default locale for the application
     defaultLocale: 'en_US',
+    // Array of paths to locale resource directories
     dirs: [],
+    // Query parameter name for locale
     queryField: 'locale',
+    // Cookie name for storing locale preference
     cookieField: 'locale',
+    // Cookie domain, empty for current domain only
     cookieDomain: '',
+    // Cookie expiration time (1 year)
     cookieMaxAge: '1y',
+    // Mapping of locale aliases (e.g., zh_CN -> cn)
     localeAlias: {},
+    // Whether to persist locale in cookie
     writeCookie: true,
+    // Deprecated: use dirs instead
     dir: undefined,
-  } as I18nConfig,
+  } satisfies I18nConfig,
 };
src/types.ts (3)

7-9: Translate Chinese comments to English for international collaboration.

The JSDoc comments contain Chinese text which should be translated to English.

Replace:

-   * 默认语言是美式英语,毕竟支持多语言,基本都是以英语为母板
-   * 默认值是 `en_US`
+   * Default language is American English (en_US), as English typically serves as the base language for multilingual support
+   * Default value is `en_US`

68-69: Improve type safety for rest parameters.

The ...args: any[] type is too permissive and could be more strictly typed based on the expected usage.

Consider using a more specific type:

-    gettext(key: string, ...args: any[]): string;
-    __(key: string, ...args: any[]): string;
+    gettext(key: string, ...args: (string | number)[]): string;
+    __(key: string, ...args: (string | number)[]): string;

77-78: Document optional value parameter.

The value parameter's purpose and usage are not clear from the type signature.

Add JSDoc to clarify the parameter usage:

+    /**
+     * Get localized text for the given key
+     * @param locale - The target locale
+     * @param key - The translation key
+     * @param value - Optional default value if key is not found
+     * @param args - Values to interpolate into the translated string
+     */
     gettext(locale: string, key: string, value?: any, ...args: any[]): string;
src/app.ts (1)

90-98: Consider using arrow function to preserve this context.

The gettextInContext function could be simplified using an arrow function.

Apply this diff:

-    function gettextInContext(key: string, ...args: any[]) {
-      const ctx = app.ctxStorage.getStore()!;
-      return ctx.gettext(key, ...args);
-    }
+    const gettextInContext = (key: string, ...args: any[]) => {
+      const ctx = app.ctxStorage.getStore();
+      if (!ctx) {
+        throw new Error('Context store is not available');
+      }
+      return ctx.gettext(key, ...args);
+    };
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 964165c and a27747e.

📒 Files selected for processing (12)
  • package.json (2 hunks)
  • src/app.ts (1 hunks)
  • src/app/extend/application.ts (1 hunks)
  • src/app/extend/context.ts (1 hunks)
  • src/config/config.default.ts (1 hunks)
  • src/locales.ts (1 hunks)
  • src/types.ts (1 hunks)
  • src/utils.ts (1 hunks)
  • test/fixtures/apps/loader/a/config/locales/zh-CN.ts (1 hunks)
  • test/fixtures/apps/loader/a/config/locales/zh-CN.yaml (1 hunks)
  • test/fixtures/apps/loader/a/config/locales/zh_CN.properties (1 hunks)
  • test/i18n.test.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • test/fixtures/apps/loader/a/config/locales/zh_CN.properties
  • test/fixtures/apps/loader/a/config/locales/zh-CN.yaml
🔇 Additional comments (12)
package.json (7)

2-6: LGTM! Package identity changes follow best practices.

The package rename to @eggjs/i18n and public access configuration are correctly implemented.


8-13: LGTM! Dual module format support is well configured.

The exports configuration correctly supports both ESM and CommonJS, with proper TypeScript source exposure.


18-18: LGTM! Repository URLs are consistently updated.

All repository-related URLs are correctly updated to reflect the new repository name.

Also applies to: 27-27, 29-29


60-69: LGTM! Comprehensive build and test scripts.

The scripts configuration provides a complete development workflow with proper type checking, linting, testing, and build steps.


70-96: LGTM! Excellent dual-format module configuration.

The module configuration follows Node.js best practices for dual CJS/ESM packages:

  • Proper type declarations for both formats
  • Clear entry points for different module systems
  • Correct package exports configuration

34-59: Verify removal of debug package and consider pinning dependency versions.

  1. The debug package has been removed. Verify that all debug logging has been migrated to a new solution.
  2. Consider pinning dependency versions more strictly for better reproducibility.

Consider updating the dependencies to use exact versions or tighter version ranges for better reproducibility:

-    "@eggjs/core": "^6.2.13",
+    "@eggjs/core": "~6.2.13",
✅ Verification successful

Debug package removal verified - successfully migrated to Node.js built-in debuglog

The codebase has been properly migrated from the debug package to Node's built-in debuglog utility from the node:util module, which is a good practice for reducing external dependencies.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for any remaining debug package usage
rg "require\(['\"']debug['\"]" || rg "import.*debug.*from"

Length of output: 308


31-31: Verify breaking change documentation.

The Node.js version requirement has been significantly increased to >= 18.19.0. This is a breaking change that needs to be prominently documented in the changelog and release notes.

src/app/extend/application.ts (2)

69-79: 🛠️ Refactor suggestion

Correct Variable Name to Follow Naming Conventions

The constant Object_INDEX_RE should be renamed to follow naming conventions. Since it's a constant, consider renaming it to OBJECT_INDEX_RE for clarity and consistency.

Apply this diff to rename the constant:

- const Object_INDEX_RE = /\{(.+?)\}/g;
+ const OBJECT_INDEX_RE = /\{(.+?)\}/g;

And update its usage:

- return text.replace(Object_INDEX_RE, (original, matched) => {
+ return text.replace(OBJECT_INDEX_RE, (original, matched) => {

Likely invalid or redundant comment.


9-10: 🛠️ Refactor suggestion

Ensure Proper Type Augmentation for Application Class

The I18nApplication class extends EggCore and adds new properties and methods. To ensure TypeScript recognizes these extensions, consider using module augmentation to properly declare the new members.

Apply this diff to augment the EggApplication interface:

declare module '@eggjs/core' {
  interface EggApplication {
    [I18N_RESOURCES]: Record<string, Record<string, string>>;
    isSupportLocale(locale: string): boolean;
    gettext(locale: string, key: string, value?: any, ...args: any[]): string;
    __(locale: string, key: string, value?: any, ...args: any[]): string;
  }
}

Ensure that this augmentation is placed in a .d.ts file and is correctly referenced.

✅ Verification successful

Type Augmentation Suggestion is Correct and Beneficial

The suggested type augmentation is accurate and should be added to src/typings/index.d.ts, which is already set up for declaration merging. This will properly type the extensions to the EggApplication interface and improve TypeScript's ability to recognize these members.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Find all TypeScript declaration files
echo "=== TypeScript Declaration Files ==="
fd -e d.ts

# Look for existing type augmentations
echo -e "\n=== Existing Type Augmentations ==="
rg "declare module.*EggApplication" -A 5

# Examine I18nApplication implementation
echo -e "\n=== I18nApplication Implementation ==="
ast-grep --pattern 'class I18nApplication extends EggCore {
  $$$
}'

Length of output: 3778


Script:

#!/bin/bash
# Check contents of the typings file
echo "=== Contents of index.d.ts ==="
cat src/typings/index.d.ts

# Also check if EggCore is imported/used elsewhere
echo -e "\n=== EggCore Usage ==="
rg "import.*EggCore" -A 1

Length of output: 537

src/app/extend/context.ts (2)

183-189: Specify SameSite Attribute for Locale Cookie

For enhanced security against CSRF attacks, specify the sameSite attribute for the locale cookie. Consider setting it to 'lax' or 'strict' based on the application's requirements.

Apply this diff to add the sameSite attribute:

      const cookieOptions = {
        // make sure browser javascript can read the cookie
        httpOnly: true,
        maxAge: cookieMaxAge as number,
        signed: false,
        domain: cookieDomain,
        overwrite: true,
+       sameSite: 'lax',
      };

Decide on the appropriate sameSite value ('lax', 'strict', or 'none') based on the application's needs.

✅ Verification successful

SameSite=Lax is Appropriate for Locale Cookie

The locale cookie is used for UI customization (storing language preferences) and doesn't contain sensitive data. Setting sameSite: 'lax' provides a good balance between security and functionality while matching modern browser defaults.

    const cookieOptions = {
      // make sure browser javascript can read the cookie
      httpOnly: false,
      maxAge: cookieMaxAge as number,
      signed: false,
      domain: cookieDomain,
      overwrite: true,
+     sameSite: 'lax',
    };
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Check the complete context.ts file for better understanding
cat src/app/extend/context.ts

# Search for CORS-related configurations
rg -l "cors" --type ts

# Search for other cookie configurations
rg "cookie" --type ts -C 2

Length of output: 11858


155-157: Check for Header Sent Before Setting Cookie

Before setting the locale cookie, the code checks !this.headerSent. However, headerSent might not always reflect the correct state. Consider using this.res.headersSent for accuracy.

Ensure that this.headerSent correctly indicates if the headers have been sent. If not, update the condition:

- if (writeCookie && cookieLocale !== locale && !this.headerSent) {
+ if (writeCookie && cookieLocale !== locale && !this.res.headersSent) {
test/fixtures/apps/loader/a/config/locales/zh-CN.ts (1)

1-4: Locale configuration exported correctly

The locale data for 'zh-CN' is properly exported with the expected keys and values. This ensures correct localization for the Chinese locale.

src/locales.ts Show resolved Hide resolved
src/app/extend/context.ts Show resolved Hide resolved
src/app/extend/context.ts Show resolved Hide resolved
src/utils.ts Show resolved Hide resolved
src/app.ts Show resolved Hide resolved
@fengmk2 fengmk2 merged commit ccc8eaa into master Jan 11, 2025
16 checks passed
@fengmk2 fengmk2 deleted the egg-v4 branch January 11, 2025 16:50
fengmk2 pushed a commit that referenced this pull request Jan 11, 2025
[skip ci]

## [3.0.0](v2.1.1...v3.0.0) (2025-01-11)

### ⚠ BREAKING CHANGES

* drop Node.js < 18.19.0 support

part of eggjs/egg#3644

eggjs/egg#5257

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

Based on the comprehensive changes, here are the updated release notes:

- **New Features**
  - Migrated package to TypeScript with improved type safety.
- Enhanced internationalization (i18n) support with more flexible
configuration.
  - Added comprehensive GitHub Actions workflows for CI/CD.

- **Improvements**
  - Updated Node.js compatibility to version 18.19.0+.
  - Modernized module system with ES module support.
  - Refined configuration and localization mechanisms.

- **Breaking Changes**
  - Package renamed from `egg-i18n` to `@eggjs/i18n`.
  - Switched from CommonJS to ES module syntax.
  - Removed legacy configuration files and testing infrastructure.

- **Chores**
  - Cleaned up and simplified project structure.
  - Updated dependencies and development tooling.
  - Improved documentation and README.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

### Features

* support cjs and esm both by tshy ([#14](#14)) ([ccc8eaa](ccc8eaa))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant