Skip to content

Conversation

@aqu1les
Copy link

@aqu1les aqu1les commented Nov 14, 2025

This PR fixes the hot-reload behavior when using additional translation directories.

The current HMR validation only checks for files matching lang/.*.php$, which prevents from triggering when translations in custom paths changes.
This update replaces the hardcoded pattern with a dynamic check based on langPath and additionalLangPaths.

Please, let me know if you'd like any adjustments.

closes #212

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Improved hot reload detection for language files, now properly monitoring all configured language directories during development instead of just the primary directory.

@coderabbitai
Copy link

coderabbitai bot commented Nov 14, 2025

Walkthrough

The pull request modifies the hot update handler in the Vite plugin to watch all configured language paths (both primary langPath and additionalLangPaths) for PHP file changes, instead of only monitoring the main lang directory. This enables hot reload functionality for translations stored in additional language directories.

Changes

Cohort / File(s) Summary
Hot Update Handler Condition Expansion
src/vite.ts
Updated handleHotUpdate conditional logic to trigger file regeneration when PHP files change in any configured language path, including additionalLangPaths, rather than only the primary lang directory

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

  • Specific attention areas:
    • Verify that the new condition correctly evaluates all language paths in additionalLangPaths
    • Confirm the pattern matching handles nested subdirectories and PHP extensions properly
    • Validate that no edge cases are introduced (e.g., empty arrays, undefined paths)

Poem

🐰 A hop and a skip through the lang paths we go,
Hot reloading translations, watching them grow,
No more restarts when translations are spun,
Additional paths now included—the fix is done! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: fixing HMR functionality for additional translation paths, which is the core issue addressed in the PR.
Linked Issues check ✅ Passed The code change directly addresses the requirement in issue #212 by updating the HMR condition to watch all configured language paths, enabling live translation updates without requiring server restart.
Out of Scope Changes check ✅ Passed The changes are tightly scoped to the HMR condition logic in src/vite.ts and directly address the linked issue; no unrelated modifications are present.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 758ddbf and 04ab50d.

📒 Files selected for processing (1)
  • src/vite.ts (1 hunks)

},
handleHotUpdate(ctx) {
if (/lang\/.*\.php$/.test(ctx.file)) {
if ([langPath, ...additionalLangPaths].some(path => new RegExp(`${path}.*\\.php$`).test(ctx.file))) {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Escape special regex characters in path strings.

The path strings are inserted directly into the RegExp constructor without escaping. If any path contains special regex metacharacters (e.g., ., \, [, ], (, ), etc.), they will be interpreted as regex syntax rather than literal characters, causing incorrect matching behavior.

For example:

  • Windows paths like C:\Users\Project\lang\ contain backslashes
  • Paths with dots like lang.backup would match langXbackup due to the unescaped .

Apply this diff to escape regex special characters:

-      if ([langPath, ...additionalLangPaths].some(path => new RegExp(`${path}.*\\.php$`).test(ctx.file))) {
+      if ([langPath, ...additionalLangPaths].some(path => new RegExp(`${path.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}.*\\.php$`).test(ctx.file))) {

Alternatively, for better readability, you could extract a helper function:

const escapeRegex = (str: string) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
// Then use:
if ([langPath, ...additionalLangPaths].some(path => new RegExp(`${escapeRegex(path)}.*\\.php$`).test(ctx.file))) {
🤖 Prompt for AI Agents
In src/vite.ts around line 57, the RegExp is built from raw path strings so
special regex characters in langPath or additionalLangPaths (e.g., backslashes,
dots, brackets) are treated as regex metacharacters and break matching; fix by
escaping regex metacharacters in each path before interpolating into the RegExp
(implement or call a small escapeRegex helper that replaces characters like . *
+ ? ^ $ { } ( ) | [ ] \ with escaped versions) and then use the escaped path
when constructing the pattern so the test matches literal paths ending with
.php.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify path matching behavior with absolute paths and path separators.

The implementation needs verification for several path-handling concerns:

  1. ctx.file format: Vite's ctx.file is typically an absolute path. Ensure the pattern matching works correctly with absolute paths from ctx.file.

  2. Path separator consistency: langPath has a trailing path.sep appended at line 10, but elements in additionalLangPaths may not. This inconsistency could cause:

    • Overly broad matches (e.g., lang pattern would match lang-backup/file.php)
    • Missing matches if separators don't align
  3. Test coverage: Verify the fix works with:

    • Files in langPath directory
    • Files in additionalLangPaths directories
    • Nested subdirectories within those paths
    • Both Windows and Unix path separators

Run the following script to check how ctx.file is used in similar Vite plugins:

Consider normalizing all paths consistently:

const normalizedAdditionalPaths = additionalLangPaths.map(p => p.replace(/[\\/]$/, '') + path.sep)
if ([langPath, ...normalizedAdditionalPaths].some(path => ...)) {

🏁 Script executed:

#!/bin/bash
# Search for handleHotUpdate usage patterns in similar contexts
rg -n -C3 'handleHotUpdate.*ctx\.file' --type=ts

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Examine the context around line 57 in src/vite.ts
cat src/vite.ts | head -80 | tail -40

Length of output: 1107


🏁 Script executed:

#!/bin/bash
# Search for langPath definition and context
rg -n -B5 -A5 'langPath' src/vite.ts

Length of output: 1923


🏁 Script executed:

#!/bin/bash
# Search for additionalLangPaths
rg -n -B3 -A3 'additionalLangPaths' src/vite.ts

Length of output: 954


🏁 Script executed:

#!/bin/bash
# Look for the original regex pattern to compare
rg -n 'lang.*php' src/vite.ts

Length of output: 110


🏁 Script executed:

#!/bin/bash
# Search for git history or any comments about the original pattern
git log -p --all -S '/lang/.*\.php$' -- src/vite.ts 2>/dev/null | head -50

Length of output: 59


🏁 Script executed:

#!/bin/bash
# Check if there are any test files that show expected behavior
fd -e 'test|spec' -t f | head -20

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for handleHotUpdate in node_modules or docs to understand ctx.file
rg -n 'ctx.file' --type=ts -B2 -A2 2>/dev/null | head -30

Length of output: 329


🌐 Web query:

Vite handleHotUpdate ctx.file absolute or relative path format

💡 Result:

ctx.file is a filesystem path pointing to the changed file — it is an absolute path (you usually call path.relative(root, ctx.file) or normalizePath on it when you need a project-relative or POSIX-normalized path). [1][2]

Sources:

  • Vite HMR hook HmrContext (ctx.file property). [1]
  • Vite plugin code/examples using ctx.file as an absolute path and calling path.relative/normalizePath. [2]

Fix path normalization and absolute path matching in handleHotUpdate.

Critical issues found during verification:

  1. Absolute path mismatch: ctx.file is an absolute path (e.g., /home/user/project/resources/lang/en.php), but the regex pattern uses relative paths like lang/.*\.php$. This pattern will never match because the absolute path contains the full directory structure.

  2. Path separator inconsistency: langPath is normalized with path.sep at line 10, but additionalLangPaths are not. This causes:

    • langPath pattern: lang/.*\.php$ (correct boundary)
    • additionalLangPaths pattern: extra.*\.php$ (matches extra-dir/file.php unintentionally)
  3. Missing normalization: additionalLangPaths must be normalized the same way as langPath before use in the regex at line 57.

Required fixes:

  • Normalize all paths to absolute form for proper matching against ctx.file
  • Ensure all paths in the array have consistent separators
  • Use path.resolve() to convert relative paths to absolute, or use path.relative(root, ctx.file) to convert ctx.file to project-relative for matching

Example correction:

const pathsToCheck = [langPath, ...additionalLangPaths].map(p => 
  p.replace(/[\\/]$/, '') // normalize separators
)
if (pathsToCheck.some(p => new RegExp(`${p.replace(/\\/g, '/')}.*\\.php$`).test(ctx.file.replace(/\\/g, '/')))) {

Or use path.relative() for more robust matching against the absolute ctx.file.

🤖 Prompt for AI Agents
In src/vite.ts around line 57, the hot-update path test fails because ctx.file
is an absolute path while langPath and additionalLangPaths are relative and
inconsistently normalized; normalize and compare on the same basis by converting
all language paths to absolute with path.resolve(root, p) (or convert ctx.file
to project-relative with path.relative(root, ctx.file)), normalize separators
(e.g., replace backslashes with forward slashes or use path.posix) and trim any
trailing slashes, then build the regex/tests from those normalized values so the
.some(...) check compares like-with-like (absolute-to-absolute or
relative-to-relative) before testing for .*\.php$ matches.

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.

Hot reload is not injecting new translations

1 participant