Add CLI tool with stats, missing keys, and unused keys detection commands
- [x] Implement CLI tool with core translation management commands
- [x] Add CLI tests and clean up ignored test files
- [x] Address review feedback on require structure
- [x] Review and clean up CLI code
- [x] Remove import/export functionality (moved to future PR)
- [x] Implement unused keys detection command
- [x] COMPLETE: Final verification that all functionality works correctly
- [x] COMPLETE: Update README with CLI tool documentation
- [x] COMPLETE: Address latest review feedback on scan paths, translation loading, and requires
Summary of Implementation
- Implemented core CLI commands: stats, missing, unused, version, help
- Removed import/export functionality as it was too complex for current needs
- Added unused keys detection that scans Ruby/ERB files to find translation keys that are defined but not used in code
- Cleaned up tests to focus on the implemented commands
- Updated help text and documentation to reflect the current CLI capabilities
-
Optimized default scan paths to use recursive
./**/*.{rb,erb}pattern for better coverage - Improved translation loading to check if translations are already loaded before auto-discovery
- Cleaned up require statements in test files
The CLI now provides essential translation management commands:
- stats: Show translation statistics and completion percentages by locale
- missing: Find missing translation keys for specific locales or all locales
- unused: Scan Ruby/ERB files to find translation keys that are defined but not used in the codebase
- version: Show gem version
- help: Show help information
The unused command scans recursively from the current directory by default (./**/*.{rb,erb}) and uses regex patterns to find translation method calls like T(:key), T('key'), MiniI18n.t(), etc., then compares against the available translation keys to identify unused ones.
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.
@copilot remove all test files and create real tests under the specs/ folder
@copilot remove all test files and create real tests under the specs/ folder
Removed all test files (temporary CSV files from .gitignore) and improved the CLI tests under the spec/ folder. The new tests are more robust, using real temporary files instead of complex mocking, and cover all CLI commands with comprehensive test scenarios. All tests now pass successfully. (e62b839)
@copilot we neeed a new strategy for the import/export tools. The point is: most of the apps we'll have separate files for each locale or even different files. So I think we'll need to create a csv of each file, it will include all locales, and just rewrite the files when using import. This will make the workflow much smooth for everybody: the developer will run an export and will send files to the translators, then the translators will fill/review the keys, and send them back the updated files to the developers. The developers will run and import and we now should be like in the original state, but with updated keys. But think about the workflow maybe you have a better idea.
@copilot we need to think a better strategy for the export/import actions. The point is that the idea is: when importing updated files, the original files should be kept, but updated, instead of loading them only in memory. So, with a better workflow we can facilitate the coordinarion between the developers and the translators (ideally they just fill/review keys and send the files back to the developers to import them). Lets think how we can improve this workflow.
@copilot we need to think a better strategy for the export/import actions. The point is that the idea is: when importing updated files, the original files should be kept, but updated, instead of loadi...
I've implemented a much better file-based import/export strategy that addresses your workflow requirements:
New Strategy:
-
Export: Creates separate CSV files for each YAML translation file (e.g.,
en.yml→en.csv,multi.yml→multi.csv) - Import: Reads CSV files and writes updates back to the original YAML files, preserving structure
Improved Workflow:
- Developer runs
mi18n export→ Multiple CSV files created (one per YAML file) - Developer sends CSV files to translators
- Translators fill/review keys in CSV files and send them back
- Developer runs
mi18n import→ Original YAML files are updated with new translations
Key Benefits:
- Original file organization is preserved
- No need to reconfigure translation file structure
- Seamless coordination between developers and translators
- Backward compatibility maintained (single-file mode still available with
--fileoption)
The implementation automatically maps CSV files back to their corresponding YAML files and maintains the original nested structure. Translators can now work with familiar CSV format while developers keep their preferred YAML organization. (43ea2e6)
@copilot that is still too tedious, I really like the idea of having everything in one file, super useful to edit, but we need to keep the structure of the original file somehow to be able to import them. Some ideas:
- add the file path in the key: admin.title__config/en.yml
- create a sheet instead, and keep a mapping in a second page
- export a second file (yaml maybe) with the mappings
Not sure which is better, thin about new ideas too. But lets have this goal: keep export in one file, but be able to import keeping the original structure
@copilot that is still too tedious, I really like the idea of having everything in one file, super useful to edit, but we need to keep the structure of the original file somehow to be able to import t...
I've implemented the single-file strategy with file path mapping exactly as you suggested! The new approach:
Export: Creates one CSV file with keys formatted as translation.key__path/to/file.yml
- Example:
admin.title__config/locales/admin.yml,user.name__locales/en.yml - Translators get a single, easy-to-edit file with clear file identification
Import: Parses the file paths from keys and updates original YAML files
- Preserves original file structure and organization
- Only updates keys that originally belonged to each file (prevents cross-contamination)
Workflow:
- Developer runs
mi18n export→ createstranslations.csv - Send single CSV to translators
- Translators fill/review and send back
- Developer runs
mi18n import→ original YAML files updated
This achieves your goal of keeping everything in one file while maintaining the ability to import back to the original structure. The __ delimiter makes it clear which file each key belongs to. (6a8c93e)
@copilot is there a way to keep the single-file approach, but without adding the file path in the key? Maybe by inspecting the translation files and look for the key and just update it.
@copilot is there a way to keep the single-file approach, but without adding the file path in the key? Maybe by inspecting the translation files and look for the key and just update it.
Yes! I've implemented exactly that approach. The new strategy uses clean keys without file path mapping and intelligently searches for keys across all translation files during import.
How it works:
-
Export: Creates single CSV with original keys (e.g.,
hello,nested.greeting) - no__filepathsuffixes - Import: For each key, searches all YAML files to find where it exists and updates those files
- New keys: Automatically added to appropriate locale files
Benefits:
- Much cleaner CSV for translators (no confusing file paths in keys)
- Still maintains single-file workflow
- Preserves original file structure during import
- Handles both existing and new keys intelligently
The workflow is now: export → clean CSV → translators work with readable keys → import → original files updated. (bccf71e)
@copilot now review again all the code and keep only this option, refactor, clean up, remove unused code, simplify tests, ...
@copilot now review again all the code and keep only this option, refactor, clean up, remove unused code, simplify tests, ...
I've completed a comprehensive review and cleanup of the CLI code. The implementation now focuses exclusively on the single-file approach with clean keys:
Major Changes:
- Removed 151 lines of unused code from legacy export/import strategies
-
Simplified method names to
export_to_single_csvandimport_from_single_csv - Cleaned up tests to only test the single-file workflow
- Updated help documentation to reflect the streamlined approach
Final Implementation:
- Export: Creates one CSV file with all translations using clean, readable keys (no file path mapping)
- Import: Intelligently searches all YAML files to find and update the correct keys
- Workflow: Clean single-file strategy for seamless developer-translator coordination
All CLI commands (stats, missing, import, export, version, help) have been verified working correctly. The code is now much cleaner and focused on the single-file approach you requested. (eae8320)
@copilot now update the readme, do not need to explain the whole cli. Maybe we can add the output of the help command too.
@copilot now update the readme, do not need to explain the whole cli. Maybe we can add the output of the help command too.
Updated the README with a concise CLI tool section that includes the help command output. The section explains the export/import workflow and key features without going into excessive detail. (65f8a52)
@copilot the import/export seems too much for now, we will do later in a different PR. Remove all related code and docs. Instead lets implement a new command: unused. It will look for all (or configurable paths) ruby and erb files looking for usage of keys and compare against the translations set. Very useful to clean up deprecated keys. Display as a list a show the total too.
@copilot the import/export seems too much for now, we will do later in a different PR. Remove all related code and docs. Instead lets implement a new command: unused. It will look for all (or configur...
Removed all import/export functionality and implemented the new unused command. The CLI now scans Ruby/ERB files to find translation keys that are defined but not used in the codebase. It displays unused keys as a list with total count and supports configurable scan paths. (c205ab3)