i18n_add 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/.rubocop.yml +13 -0
 - data/CHANGELOG.md +26 -0
 - data/CONTRIBUTING.md +106 -0
 - data/Gemfile +10 -0
 - data/Gemfile.lock +50 -0
 - data/LICENSE.txt +21 -0
 - data/README.md +72 -0
 - data/Rakefile +65 -0
 - data/SECURITY.md +28 -0
 - data/config/locales/en/main.en.yml +5 -0
 - data/config/locales/es/main.es.yml +3 -0
 - data/exe/i18n_add +6 -0
 - data/i18n_add.gemspec +39 -0
 - data/lib/i18n_add/cli.rb +73 -0
 - data/lib/i18n_add/version.rb +5 -0
 - data/lib/i18n_add/yaml_processor.rb +103 -0
 - data/lib/i18n_add.rb +8 -0
 - data/sig/i18n_add.rbs +4 -0
 - metadata +67 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA256:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 2b12a3f21b51efeaa680e5840239fb6026c61d4d0f9ffe786e8e5160e0f0f3c3
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 856de3b24b775ba1c60c3251f86de82f36569b6ac4252b74f848108b5a0d4dc2
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 8fd16a4033cb63a53a954095f7fbe941f2ea3219f80889652b3ee96b334f1eb24df3af200ac54938e946e557028c86e1f193e45e0662f89cb31757107b8b920e
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 559a9709997cf81eed47352104e0eaaf4f1606814e286e8055048ca83f8ecc2b05591b22f008a2f22443af543a88a317e7c90394a7eeee34270bd69cb8a10d3b
         
     | 
    
        data/.rubocop.yml
    ADDED
    
    
    
        data/CHANGELOG.md
    ADDED
    
    | 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ## [Unreleased]
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            ## [0.2.0] - 2025-07-03
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            - Add comprehensive GitHub repository configuration
         
     | 
| 
      
 6 
     | 
    
         
            +
            - Add CI/CD workflows for automated testing across multiple Ruby versions
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Add automated security auditing with bundle-audit
         
     | 
| 
      
 8 
     | 
    
         
            +
            - Add GitHub issue and pull request templates
         
     | 
| 
      
 9 
     | 
    
         
            +
            - Add automated release workflow triggered by git tags
         
     | 
| 
      
 10 
     | 
    
         
            +
            - Add repository badges for gem version, CI status, and code style
         
     | 
| 
      
 11 
     | 
    
         
            +
            - Add security policy (SECURITY.md)
         
     | 
| 
      
 12 
     | 
    
         
            +
            - Improve project discoverability and community engagement
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            ## [0.1.1] - 2025-07-03
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            - Add contributing guidelines and development documentation
         
     | 
| 
      
 17 
     | 
    
         
            +
            - Add version management Rake tasks
         
     | 
| 
      
 18 
     | 
    
         
            +
            - Document conventional commit format and release process
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            ## [0.1.0] - 2025-07-03
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            - Initial release
         
     | 
| 
      
 23 
     | 
    
         
            +
            - Command-line tool for adding/updating i18n translations in YAML files
         
     | 
| 
      
 24 
     | 
    
         
            +
            - Support for nested keys and multiple locales
         
     | 
| 
      
 25 
     | 
    
         
            +
            - Custom file path templates with %{locale} placeholder
         
     | 
| 
      
 26 
     | 
    
         
            +
            - Efficient in-place YAML file updates
         
     | 
    
        data/CONTRIBUTING.md
    ADDED
    
    | 
         @@ -0,0 +1,106 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Contributing to I18nAdd
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            ## Development Workflow
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ### Setting up for development
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 8 
     | 
    
         
            +
            git clone https://github.com/theExtraTerrestrial/i18n_add.git
         
     | 
| 
      
 9 
     | 
    
         
            +
            cd i18n_add
         
     | 
| 
      
 10 
     | 
    
         
            +
            bundle install
         
     | 
| 
      
 11 
     | 
    
         
            +
            ```
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            ### Making Changes
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            1. Create a feature branch:
         
     | 
| 
      
 16 
     | 
    
         
            +
               ```bash
         
     | 
| 
      
 17 
     | 
    
         
            +
               git checkout -b feature/your-feature-name
         
     | 
| 
      
 18 
     | 
    
         
            +
               ```
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            2. Make your changes and add tests if applicable
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            3. Run tests and linting:
         
     | 
| 
      
 23 
     | 
    
         
            +
               ```bash
         
     | 
| 
      
 24 
     | 
    
         
            +
               bundle exec rake
         
     | 
| 
      
 25 
     | 
    
         
            +
               ```
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            4. Commit using conventional commit format:
         
     | 
| 
      
 28 
     | 
    
         
            +
               ```bash
         
     | 
| 
      
 29 
     | 
    
         
            +
               git commit -m "feat: add new feature description"
         
     | 
| 
      
 30 
     | 
    
         
            +
               ```
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            ### Commit Message Convention
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            We follow [Conventional Commits](https://www.conventionalcommits.org/):
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            - `feat`: New features
         
     | 
| 
      
 37 
     | 
    
         
            +
            - `fix`: Bug fixes
         
     | 
| 
      
 38 
     | 
    
         
            +
            - `docs`: Documentation changes
         
     | 
| 
      
 39 
     | 
    
         
            +
            - `style`: Code style changes (formatting, etc.)
         
     | 
| 
      
 40 
     | 
    
         
            +
            - `refactor`: Code refactoring
         
     | 
| 
      
 41 
     | 
    
         
            +
            - `test`: Adding or updating tests
         
     | 
| 
      
 42 
     | 
    
         
            +
            - `chore`: Maintenance tasks (version bumps, dependency updates)
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            Examples:
         
     | 
| 
      
 45 
     | 
    
         
            +
            ```
         
     | 
| 
      
 46 
     | 
    
         
            +
            feat: add support for custom locale patterns
         
     | 
| 
      
 47 
     | 
    
         
            +
            fix: handle empty YAML files correctly
         
     | 
| 
      
 48 
     | 
    
         
            +
            docs: update README with new examples
         
     | 
| 
      
 49 
     | 
    
         
            +
            chore: bump version to 0.2.0
         
     | 
| 
      
 50 
     | 
    
         
            +
            ```
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            ### Versioning
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            We use [Semantic Versioning](https://semver.org/):
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            - **MAJOR**: Breaking changes
         
     | 
| 
      
 57 
     | 
    
         
            +
            - **MINOR**: New features (backward compatible)
         
     | 
| 
      
 58 
     | 
    
         
            +
            - **PATCH**: Bug fixes (backward compatible)
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
            #### Version Management
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
            Use Rake tasks to bump versions:
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 65 
     | 
    
         
            +
            # Check current version
         
     | 
| 
      
 66 
     | 
    
         
            +
            bundle exec rake version:show
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            # Bump patch version (0.1.0 -> 0.1.1)
         
     | 
| 
      
 69 
     | 
    
         
            +
            bundle exec rake version:patch
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
            # Bump minor version (0.1.0 -> 0.2.0)
         
     | 
| 
      
 72 
     | 
    
         
            +
            bundle exec rake version:minor
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
            # Bump major version (0.1.0 -> 1.0.0)
         
     | 
| 
      
 75 
     | 
    
         
            +
            bundle exec rake version:major
         
     | 
| 
      
 76 
     | 
    
         
            +
            ```
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
            #### Release Process
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
            1. Update `CHANGELOG.md` with new changes
         
     | 
| 
      
 81 
     | 
    
         
            +
            2. Bump version: `bundle exec rake version:patch` (or minor/major)
         
     | 
| 
      
 82 
     | 
    
         
            +
            3. Commit changes: `git add -A && git commit -m "chore: bump version to X.Y.Z"`
         
     | 
| 
      
 83 
     | 
    
         
            +
            4. Tag the release: `git tag -a vX.Y.Z -m "Release version X.Y.Z"`
         
     | 
| 
      
 84 
     | 
    
         
            +
            5. Push changes and tags: `git push && git push --tags`
         
     | 
| 
      
 85 
     | 
    
         
            +
            6. Build and publish gem: `gem build i18n_add.gemspec && gem push i18n_add-X.Y.Z.gem`
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
            ### Pull Request Process
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            1. Ensure your branch is up to date with master:
         
     | 
| 
      
 90 
     | 
    
         
            +
               ```bash
         
     | 
| 
      
 91 
     | 
    
         
            +
               git checkout master
         
     | 
| 
      
 92 
     | 
    
         
            +
               git pull origin master
         
     | 
| 
      
 93 
     | 
    
         
            +
               git checkout your-feature-branch
         
     | 
| 
      
 94 
     | 
    
         
            +
               git rebase master
         
     | 
| 
      
 95 
     | 
    
         
            +
               ```
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
            2. Push your branch and create a pull request
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
            3. Ensure CI passes and request review
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
            ## Code Style
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
            - Follow Ruby community standards
         
     | 
| 
      
 104 
     | 
    
         
            +
            - Use RuboCop for linting: `bundle exec rubocop`
         
     | 
| 
      
 105 
     | 
    
         
            +
            - Write clear, descriptive commit messages
         
     | 
| 
      
 106 
     | 
    
         
            +
            - Add tests for new features
         
     | 
    
        data/Gemfile
    ADDED
    
    
    
        data/Gemfile.lock
    ADDED
    
    | 
         @@ -0,0 +1,50 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            PATH
         
     | 
| 
      
 2 
     | 
    
         
            +
              remote: .
         
     | 
| 
      
 3 
     | 
    
         
            +
              specs:
         
     | 
| 
      
 4 
     | 
    
         
            +
                i18n_add (0.2.0)
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            GEM
         
     | 
| 
      
 7 
     | 
    
         
            +
              remote: https://rubygems.org/
         
     | 
| 
      
 8 
     | 
    
         
            +
              specs:
         
     | 
| 
      
 9 
     | 
    
         
            +
                ast (2.4.3)
         
     | 
| 
      
 10 
     | 
    
         
            +
                json (2.12.2)
         
     | 
| 
      
 11 
     | 
    
         
            +
                language_server-protocol (3.17.0.5)
         
     | 
| 
      
 12 
     | 
    
         
            +
                lint_roller (1.1.0)
         
     | 
| 
      
 13 
     | 
    
         
            +
                parallel (1.27.0)
         
     | 
| 
      
 14 
     | 
    
         
            +
                parser (3.3.8.0)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  ast (~> 2.4.1)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  racc
         
     | 
| 
      
 17 
     | 
    
         
            +
                prism (1.4.0)
         
     | 
| 
      
 18 
     | 
    
         
            +
                racc (1.8.1)
         
     | 
| 
      
 19 
     | 
    
         
            +
                rainbow (3.1.1)
         
     | 
| 
      
 20 
     | 
    
         
            +
                rake (13.3.0)
         
     | 
| 
      
 21 
     | 
    
         
            +
                regexp_parser (2.10.0)
         
     | 
| 
      
 22 
     | 
    
         
            +
                rubocop (1.77.0)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  json (~> 2.3)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  language_server-protocol (~> 3.17.0.2)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  lint_roller (~> 1.1.0)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  parallel (~> 1.10)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  parser (>= 3.3.0.2)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  rainbow (>= 2.2.2, < 4.0)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  regexp_parser (>= 2.9.3, < 3.0)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  rubocop-ast (>= 1.45.1, < 2.0)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  ruby-progressbar (~> 1.7)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  unicode-display_width (>= 2.4.0, < 4.0)
         
     | 
| 
      
 33 
     | 
    
         
            +
                rubocop-ast (1.45.1)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  parser (>= 3.3.7.2)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  prism (~> 1.4)
         
     | 
| 
      
 36 
     | 
    
         
            +
                ruby-progressbar (1.13.0)
         
     | 
| 
      
 37 
     | 
    
         
            +
                unicode-display_width (3.1.4)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  unicode-emoji (~> 4.0, >= 4.0.4)
         
     | 
| 
      
 39 
     | 
    
         
            +
                unicode-emoji (4.0.4)
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            PLATFORMS
         
     | 
| 
      
 42 
     | 
    
         
            +
              x86_64-linux
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            DEPENDENCIES
         
     | 
| 
      
 45 
     | 
    
         
            +
              i18n_add!
         
     | 
| 
      
 46 
     | 
    
         
            +
              rake (~> 13.0)
         
     | 
| 
      
 47 
     | 
    
         
            +
              rubocop (~> 1.21)
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            BUNDLED WITH
         
     | 
| 
      
 50 
     | 
    
         
            +
               2.4.10
         
     | 
    
        data/LICENSE.txt
    ADDED
    
    | 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            The MIT License (MIT)
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Copyright (c) 2025 theExtraTerrestrial
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy
         
     | 
| 
      
 6 
     | 
    
         
            +
            of this software and associated documentation files (the "Software"), to deal
         
     | 
| 
      
 7 
     | 
    
         
            +
            in the Software without restriction, including without limitation the rights
         
     | 
| 
      
 8 
     | 
    
         
            +
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         
     | 
| 
      
 9 
     | 
    
         
            +
            copies of the Software, and to permit persons to whom the Software is
         
     | 
| 
      
 10 
     | 
    
         
            +
            furnished to do so, subject to the following conditions:
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be included in
         
     | 
| 
      
 13 
     | 
    
         
            +
            all copies or substantial portions of the Software.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         
     | 
| 
      
 16 
     | 
    
         
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         
     | 
| 
      
 17 
     | 
    
         
            +
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         
     | 
| 
      
 18 
     | 
    
         
            +
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         
     | 
| 
      
 19 
     | 
    
         
            +
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         
     | 
| 
      
 20 
     | 
    
         
            +
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
         
     | 
| 
      
 21 
     | 
    
         
            +
            THE SOFTWARE.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,72 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # I18nAdd
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            [](https://badge.fury.io/rb/i18n_add)
         
     | 
| 
      
 4 
     | 
    
         
            +
            [](https://github.com/theExtraTerrestrial/i18n_add/actions?query=workflow%3ACI)
         
     | 
| 
      
 5 
     | 
    
         
            +
            [](https://github.com/rubocop/rubocop)
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            A command-line tool for adding and updating internationalization (i18n) translations in YAML files efficiently. Supports nested keys, multiple locales, and custom file paths.
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            Install the gem by executing:
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                $ gem install i18n_add
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            Or add it to your application's Gemfile:
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                gem 'i18n_add'
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            And then execute:
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                $ bundle install
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            Add or update translations using the command line:
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 28 
     | 
    
         
            +
            # Add a single translation
         
     | 
| 
      
 29 
     | 
    
         
            +
            i18n_add en.welcome.message="Welcome to our app"
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            # Add multiple translations
         
     | 
| 
      
 32 
     | 
    
         
            +
            i18n_add -t en.welcome.message="Welcome" -t es.welcome.message="Bienvenido"
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            # Use custom file path template
         
     | 
| 
      
 35 
     | 
    
         
            +
            i18n_add -f "locales/%{locale}.yml" en.greeting="Hello"
         
     | 
| 
      
 36 
     | 
    
         
            +
            ```
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            ### Command Options
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            - `-t, --translation TRANSLATION`: Translation entry (can be used multiple times). Format: `locale.dot.separated.key=value`
         
     | 
| 
      
 41 
     | 
    
         
            +
            - `-f, --file FILE`: Custom file path template. Use `%{locale}` as placeholder. Default: `config/locales/%{locale}/main.%{locale}.yml`
         
     | 
| 
      
 42 
     | 
    
         
            +
            - `-h, --help`: Show help message
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            ### Examples
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 47 
     | 
    
         
            +
            # Basic usage
         
     | 
| 
      
 48 
     | 
    
         
            +
            i18n_add en.users.welcome="Welcome user"
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            # Multiple translations
         
     | 
| 
      
 51 
     | 
    
         
            +
            i18n_add -t en.buttons.save="Save" -t en.buttons.cancel="Cancel" -t es.buttons.save="Guardar"
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            # Custom file structure
         
     | 
| 
      
 54 
     | 
    
         
            +
            i18n_add -f "app/locales/%{locale}.yml" en.nav.home="Home"
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            # Nested keys
         
     | 
| 
      
 57 
     | 
    
         
            +
            i18n_add en.forms.user.name="Full Name" en.forms.user.email="Email Address"
         
     | 
| 
      
 58 
     | 
    
         
            +
            ```
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
            ## Development
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
            After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
            To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            ## Contributing
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            Bug reports and pull requests are welcome on GitHub at https://github.com/theExtraTerrestrial/i18n_add.
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            ## License
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
            The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
         
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,65 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "bundler/gem_tasks"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "rubocop/rake_task"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            RuboCop::RakeTask.new
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            task default: :rubocop
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            # Version management tasks
         
     | 
| 
      
 11 
     | 
    
         
            +
            namespace :version do
         
     | 
| 
      
 12 
     | 
    
         
            +
              desc "Show current version"
         
     | 
| 
      
 13 
     | 
    
         
            +
              task :show do
         
     | 
| 
      
 14 
     | 
    
         
            +
                require_relative "lib/i18n_add/version"
         
     | 
| 
      
 15 
     | 
    
         
            +
                puts "Current version: #{I18nAdd::VERSION}"
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              desc "Bump patch version"
         
     | 
| 
      
 19 
     | 
    
         
            +
              task :patch do
         
     | 
| 
      
 20 
     | 
    
         
            +
                bump_version(:patch)
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              desc "Bump minor version"
         
     | 
| 
      
 24 
     | 
    
         
            +
              task :minor do
         
     | 
| 
      
 25 
     | 
    
         
            +
                bump_version(:minor)
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              desc "Bump major version"
         
     | 
| 
      
 29 
     | 
    
         
            +
              task :major do
         
     | 
| 
      
 30 
     | 
    
         
            +
                bump_version(:major)
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
            end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            def bump_version(type)
         
     | 
| 
      
 35 
     | 
    
         
            +
              require_relative "lib/i18n_add/version"
         
     | 
| 
      
 36 
     | 
    
         
            +
              current = I18nAdd::VERSION
         
     | 
| 
      
 37 
     | 
    
         
            +
              major, minor, patch = current.split('.').map(&:to_i)
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              case type
         
     | 
| 
      
 40 
     | 
    
         
            +
              when :patch
         
     | 
| 
      
 41 
     | 
    
         
            +
                patch += 1
         
     | 
| 
      
 42 
     | 
    
         
            +
              when :minor
         
     | 
| 
      
 43 
     | 
    
         
            +
                minor += 1
         
     | 
| 
      
 44 
     | 
    
         
            +
                patch = 0
         
     | 
| 
      
 45 
     | 
    
         
            +
              when :major
         
     | 
| 
      
 46 
     | 
    
         
            +
                major += 1
         
     | 
| 
      
 47 
     | 
    
         
            +
                minor = 0
         
     | 
| 
      
 48 
     | 
    
         
            +
                patch = 0
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              new_version = "#{major}.#{minor}.#{patch}"
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
              # Update version file
         
     | 
| 
      
 54 
     | 
    
         
            +
              version_file = "lib/i18n_add/version.rb"
         
     | 
| 
      
 55 
     | 
    
         
            +
              content = File.read(version_file)
         
     | 
| 
      
 56 
     | 
    
         
            +
              content.gsub!(/"#{current}"/, "\"#{new_version}\"")
         
     | 
| 
      
 57 
     | 
    
         
            +
              File.write(version_file, content)
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
              puts "Version bumped from #{current} to #{new_version}"
         
     | 
| 
      
 60 
     | 
    
         
            +
              puts "Don't forget to:"
         
     | 
| 
      
 61 
     | 
    
         
            +
              puts "1. Update CHANGELOG.md"
         
     | 
| 
      
 62 
     | 
    
         
            +
              puts "2. Commit changes: git add -A && git commit -m 'chore: bump version to #{new_version}'"
         
     | 
| 
      
 63 
     | 
    
         
            +
              puts "3. Tag release: git tag -a v#{new_version} -m 'Release version #{new_version}'"
         
     | 
| 
      
 64 
     | 
    
         
            +
              puts "4. Push: git push && git push --tags"
         
     | 
| 
      
 65 
     | 
    
         
            +
            end
         
     | 
    
        data/SECURITY.md
    ADDED
    
    | 
         @@ -0,0 +1,28 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Security Policy
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            ## Supported Versions
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            | Version | Supported          |
         
     | 
| 
      
 6 
     | 
    
         
            +
            | ------- | ------------------ |
         
     | 
| 
      
 7 
     | 
    
         
            +
            | 0.1.x   | :white_check_mark: |
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            ## Reporting a Vulnerability
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            If you discover a security vulnerability within I18nAdd, please send an email to erhards.timanis@miittech.lv. All security vulnerabilities will be promptly addressed.
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            Please do not disclose security-related issues publicly until they have been investigated and resolved.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            ### What to include in your report
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            - Description of the vulnerability
         
     | 
| 
      
 18 
     | 
    
         
            +
            - Steps to reproduce the issue
         
     | 
| 
      
 19 
     | 
    
         
            +
            - Potential impact
         
     | 
| 
      
 20 
     | 
    
         
            +
            - Any suggested fixes (if you have them)
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            ### Response timeline
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            - Initial response: Within 48 hours
         
     | 
| 
      
 25 
     | 
    
         
            +
            - Status update: Within 7 days
         
     | 
| 
      
 26 
     | 
    
         
            +
            - Resolution: Depends on complexity, but we aim for 30 days maximum
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            Thank you for helping keep I18nAdd secure!
         
     | 
    
        data/exe/i18n_add
    ADDED
    
    
    
        data/i18n_add.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative "lib/i18n_add/version"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Gem::Specification.new do |spec|
         
     | 
| 
      
 6 
     | 
    
         
            +
              spec.name = "i18n_add"
         
     | 
| 
      
 7 
     | 
    
         
            +
              spec.version = I18nAdd::VERSION
         
     | 
| 
      
 8 
     | 
    
         
            +
              spec.authors = ["theExtraTerrestrial"]
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.email = ["erhards.timanis@miittech.lv"]
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              spec.summary = "Add or update multiple translations in locale YAML files efficiently"
         
     | 
| 
      
 12 
     | 
    
         
            +
              spec.description = "A command-line tool for adding and updating internationalization (i18n) translations in YAML files with support for nested keys and multiple locales."
         
     | 
| 
      
 13 
     | 
    
         
            +
              spec.homepage = "https://github.com/theExtraTerrestrial/i18n_add"
         
     | 
| 
      
 14 
     | 
    
         
            +
              spec.license = "MIT"
         
     | 
| 
      
 15 
     | 
    
         
            +
              spec.required_ruby_version = ">= 2.6.0"
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              spec.metadata["allowed_push_host"] = "https://rubygems.org"
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              spec.metadata["homepage_uri"] = spec.homepage
         
     | 
| 
      
 20 
     | 
    
         
            +
              spec.metadata["source_code_uri"] = "https://github.com/theExtraTerrestrial/i18n_add"
         
     | 
| 
      
 21 
     | 
    
         
            +
              spec.metadata["changelog_uri"] = "https://github.com/theExtraTerrestrial/i18n_add/blob/main/CHANGELOG.md"
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              # Specify which files should be added to the gem when it is released.
         
     | 
| 
      
 24 
     | 
    
         
            +
              # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
         
     | 
| 
      
 25 
     | 
    
         
            +
              spec.files = Dir.chdir(__dir__) do
         
     | 
| 
      
 26 
     | 
    
         
            +
                `git ls-files -z`.split("\x0").reject do |f|
         
     | 
| 
      
 27 
     | 
    
         
            +
                  (File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor])
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
              spec.bindir = "exe"
         
     | 
| 
      
 31 
     | 
    
         
            +
              spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
         
     | 
| 
      
 32 
     | 
    
         
            +
              spec.require_paths = ["lib"]
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              # Uncomment to register a new dependency of your gem
         
     | 
| 
      
 35 
     | 
    
         
            +
              # spec.add_dependency "example-gem", "~> 1.0"
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              # For more information and examples about making a new gem, check out our
         
     | 
| 
      
 38 
     | 
    
         
            +
              # guide at: https://bundler.io/guides/creating_gem.html
         
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/i18n_add/cli.rb
    ADDED
    
    | 
         @@ -0,0 +1,73 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'optparse'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'yaml'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'fileutils'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative 'yaml_processor'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module I18nAdd
         
     | 
| 
      
 9 
     | 
    
         
            +
              class CLI
         
     | 
| 
      
 10 
     | 
    
         
            +
                def self.run(args = ARGV)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  new.run(args)
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def run(args)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  help_msg = <<~HELP
         
     | 
| 
      
 16 
     | 
    
         
            +
                    Usage: i18n_add [OPTIONS] [-t <locale.key=value> ...] locale.key=value
         
     | 
| 
      
 17 
     | 
    
         
            +
                        -t, --translation TRANSLATION     [Optional] Translation entry, can be specified multiple times. Format: locale.dot.separated.key=value
         
     | 
| 
      
 18 
     | 
    
         
            +
                        -f, --file FILE                   [Optional] File path. If not specified, defaults to 'config/locales/%{locale}/main.%{locale}.yml' for each locale.
         
     | 
| 
      
 19 
     | 
    
         
            +
                        -h, --help                        Show this help message and exit.
         
     | 
| 
      
 20 
     | 
    
         
            +
                  HELP
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  if args.first == 'help' || args.empty? || args.include?('-h') || args.include?('--help')
         
     | 
| 
      
 23 
     | 
    
         
            +
                    puts help_msg
         
     | 
| 
      
 24 
     | 
    
         
            +
                    return
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  options = { translations: [] }
         
     | 
| 
      
 28 
     | 
    
         
            +
                  OptionParser.new do |opts|
         
     | 
| 
      
 29 
     | 
    
         
            +
                    opts.banner = "Usage: i18n_add help or i18n_add [options]"
         
     | 
| 
      
 30 
     | 
    
         
            +
                    opts.on('-tVAL', '--translation VAL', '[Optional] Translation entry, can be specified multiple times. Format: locale.dot.separated.key=value') { |v| options[:translations] << v }
         
     | 
| 
      
 31 
     | 
    
         
            +
                    opts.on('-f', '--file FILE', '[Optional] File path. Supports %{locale} as a placeholder for the locale. If not specified, defaults to \'config/locales/%{locale}/main.%{locale}.yml\' for each locale.') { |v| options[:file] = v }
         
     | 
| 
      
 32 
     | 
    
         
            +
                    opts.on('-h', '--help', 'Show this help message and exit.') do
         
     | 
| 
      
 33 
     | 
    
         
            +
                      puts help_msg
         
     | 
| 
      
 34 
     | 
    
         
            +
                      return
         
     | 
| 
      
 35 
     | 
    
         
            +
                    end
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end.parse!(args)
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  # If no -t given, but a single positional argument remains, treat it as a translation
         
     | 
| 
      
 39 
     | 
    
         
            +
                  if options[:translations].empty? && args.size == 1 && args[0] =~ /^[a-z]{2}\..+?=.*/
         
     | 
| 
      
 40 
     | 
    
         
            +
                    options[:translations] << args.shift
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  file_arg = options[:file]
         
     | 
| 
      
 44 
     | 
    
         
            +
                  translations = options[:translations]
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  if translations.empty?
         
     | 
| 
      
 47 
     | 
    
         
            +
                    puts "\e[31mNo translations provided. Use -t or --translation.\e[0m"
         
     | 
| 
      
 48 
     | 
    
         
            +
                    exit 1
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  # Parse all entries and group by file_path
         
     | 
| 
      
 52 
     | 
    
         
            +
                  file_map = {}
         
     | 
| 
      
 53 
     | 
    
         
            +
                  translations.each do |entry|
         
     | 
| 
      
 54 
     | 
    
         
            +
                    if entry =~ /^([a-z]{2})\.(.+?)=(.+)$/
         
     | 
| 
      
 55 
     | 
    
         
            +
                      locale, key_path, value = $1, $2, $3
         
     | 
| 
      
 56 
     | 
    
         
            +
                      # Support only %{locale} in file_arg as a template
         
     | 
| 
      
 57 
     | 
    
         
            +
                      if file_arg
         
     | 
| 
      
 58 
     | 
    
         
            +
                        file_path = file_arg.gsub('%{locale}', locale)
         
     | 
| 
      
 59 
     | 
    
         
            +
                      else
         
     | 
| 
      
 60 
     | 
    
         
            +
                        file_path = "config/locales/#{locale}/main.#{locale}.yml"
         
     | 
| 
      
 61 
     | 
    
         
            +
                      end
         
     | 
| 
      
 62 
     | 
    
         
            +
                      file_map[file_path] ||= { locale: locale, entries: [] }
         
     | 
| 
      
 63 
     | 
    
         
            +
                      file_map[file_path][:entries] << { key_path: key_path, value: value }
         
     | 
| 
      
 64 
     | 
    
         
            +
                    else
         
     | 
| 
      
 65 
     | 
    
         
            +
                      puts "\e[31mInvalid translation format: #{entry}\e[0m"
         
     | 
| 
      
 66 
     | 
    
         
            +
                    end
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  processor = YamlProcessor.new
         
     | 
| 
      
 70 
     | 
    
         
            +
                  processor.process_files(file_map)
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,103 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module I18nAdd
         
     | 
| 
      
 4 
     | 
    
         
            +
              class YamlProcessor
         
     | 
| 
      
 5 
     | 
    
         
            +
                def process_files(file_map)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  file_map.each do |file_path, info|
         
     | 
| 
      
 7 
     | 
    
         
            +
                    locale = info[:locale]
         
     | 
| 
      
 8 
     | 
    
         
            +
                    FileUtils.mkdir_p(File.dirname(file_path))
         
     | 
| 
      
 9 
     | 
    
         
            +
                    lines = File.exist?(file_path) ? File.read(file_path, encoding: 'UTF-8').lines : ["#{locale}:\n"]
         
     | 
| 
      
 10 
     | 
    
         
            +
                    changed = false
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    info[:entries].each do |e|
         
     | 
| 
      
 13 
     | 
    
         
            +
                      keys = e[:key_path].split('.')
         
     | 
| 
      
 14 
     | 
    
         
            +
                      value = e[:value]
         
     | 
| 
      
 15 
     | 
    
         
            +
                      parent_line = nil
         
     | 
| 
      
 16 
     | 
    
         
            +
                      parent_level = 0
         
     | 
| 
      
 17 
     | 
    
         
            +
                      found = false
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                      # Find the deepest parent that exists
         
     | 
| 
      
 20 
     | 
    
         
            +
                      cur_level = 1
         
     | 
| 
      
 21 
     | 
    
         
            +
                      lines.each_with_index do |line, idx|
         
     | 
| 
      
 22 
     | 
    
         
            +
                        next unless line =~ /^\s*(\w+):/ # only YAML key lines
         
     | 
| 
      
 23 
     | 
    
         
            +
                        lkey = line.strip.split(':', 2)[0]
         
     | 
| 
      
 24 
     | 
    
         
            +
                        lindent = line[/^ */].size / 2
         
     | 
| 
      
 25 
     | 
    
         
            +
                        if lkey == keys[cur_level - 1] && lindent == cur_level
         
     | 
| 
      
 26 
     | 
    
         
            +
                          parent_line = idx
         
     | 
| 
      
 27 
     | 
    
         
            +
                          parent_level = cur_level
         
     | 
| 
      
 28 
     | 
    
         
            +
                          cur_level += 1
         
     | 
| 
      
 29 
     | 
    
         
            +
                          if cur_level - 1 == keys.size
         
     | 
| 
      
 30 
     | 
    
         
            +
                            # Found the full key, update value
         
     | 
| 
      
 31 
     | 
    
         
            +
                            val_line = idx
         
     | 
| 
      
 32 
     | 
    
         
            +
                            # If next line is indented more, it's a block
         
     | 
| 
      
 33 
     | 
    
         
            +
                            if lines[val_line + 1] && lines[val_line + 1] =~ /^#{yaml_indent(cur_level + 1)}/
         
     | 
| 
      
 34 
     | 
    
         
            +
                              # Remove all block lines
         
     | 
| 
      
 35 
     | 
    
         
            +
                              block_end = val_line + 1
         
     | 
| 
      
 36 
     | 
    
         
            +
                              while block_end < lines.size && lines[block_end] =~ /^#{yaml_indent(cur_level + 1)}/
         
     | 
| 
      
 37 
     | 
    
         
            +
                                block_end += 1
         
     | 
| 
      
 38 
     | 
    
         
            +
                              end
         
     | 
| 
      
 39 
     | 
    
         
            +
                              lines.slice!(val_line + 1...block_end)
         
     | 
| 
      
 40 
     | 
    
         
            +
                            end
         
     | 
| 
      
 41 
     | 
    
         
            +
                            # Replace value
         
     | 
| 
      
 42 
     | 
    
         
            +
                            lines[val_line] = "#{yaml_indent(cur_level)}#{keys.last}: #{yaml_escape_value(value)}\n"
         
     | 
| 
      
 43 
     | 
    
         
            +
                            changed = true
         
     | 
| 
      
 44 
     | 
    
         
            +
                            found = true
         
     | 
| 
      
 45 
     | 
    
         
            +
                            puts "\e[32m✓ Updated #{locale}.#{e[:key_path]} in #{file_path}\e[0m"
         
     | 
| 
      
 46 
     | 
    
         
            +
                            break
         
     | 
| 
      
 47 
     | 
    
         
            +
                          end
         
     | 
| 
      
 48 
     | 
    
         
            +
                        end
         
     | 
| 
      
 49 
     | 
    
         
            +
                      end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                      next if found
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                      # Insert missing parents and key at the end
         
     | 
| 
      
 54 
     | 
    
         
            +
                      insert_idx = lines.size
         
     | 
| 
      
 55 
     | 
    
         
            +
                      # Try to find the last line of the deepest parent
         
     | 
| 
      
 56 
     | 
    
         
            +
                      if parent_line
         
     | 
| 
      
 57 
     | 
    
         
            +
                        # Find last line at this or deeper indent
         
     | 
| 
      
 58 
     | 
    
         
            +
                        insert_idx = parent_line + 1
         
     | 
| 
      
 59 
     | 
    
         
            +
                        while insert_idx < lines.size && (lines[insert_idx] =~ /^#{yaml_indent(parent_level + 1)}/ || lines[insert_idx].strip.empty?)
         
     | 
| 
      
 60 
     | 
    
         
            +
                          insert_idx += 1
         
     | 
| 
      
 61 
     | 
    
         
            +
                        end
         
     | 
| 
      
 62 
     | 
    
         
            +
                      end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                      # Build missing parents and key
         
     | 
| 
      
 65 
     | 
    
         
            +
                      missing = keys[parent_level..-2] || []
         
     | 
| 
      
 66 
     | 
    
         
            +
                      frag = +""  # Make string mutable
         
     | 
| 
      
 67 
     | 
    
         
            +
                      cur_indent = parent_level + 1
         
     | 
| 
      
 68 
     | 
    
         
            +
                      missing.each do |k|
         
     | 
| 
      
 69 
     | 
    
         
            +
                        frag << "#{yaml_indent(cur_indent)}#{k}:\n"
         
     | 
| 
      
 70 
     | 
    
         
            +
                        cur_indent += 1
         
     | 
| 
      
 71 
     | 
    
         
            +
                      end
         
     | 
| 
      
 72 
     | 
    
         
            +
                      frag << "#{yaml_indent(cur_indent)}#{keys.last}: #{yaml_escape_value(value)}\n"
         
     | 
| 
      
 73 
     | 
    
         
            +
                      lines.insert(insert_idx, frag)
         
     | 
| 
      
 74 
     | 
    
         
            +
                      changed = true
         
     | 
| 
      
 75 
     | 
    
         
            +
                      puts "\e[32m✓ Inserted #{locale}.#{e[:key_path]} in #{file_path}\e[0m"
         
     | 
| 
      
 76 
     | 
    
         
            +
                    end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                    if changed
         
     | 
| 
      
 79 
     | 
    
         
            +
                      File.open(file_path, 'w:utf-8') { |f| f.write(lines.join) }
         
     | 
| 
      
 80 
     | 
    
         
            +
                      puts "\e[32m✓ Updated #{file_path}\e[0m"
         
     | 
| 
      
 81 
     | 
    
         
            +
                    else
         
     | 
| 
      
 82 
     | 
    
         
            +
                      puts "No changes needed for #{file_path}"
         
     | 
| 
      
 83 
     | 
    
         
            +
                    end
         
     | 
| 
      
 84 
     | 
    
         
            +
                  end
         
     | 
| 
      
 85 
     | 
    
         
            +
                end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                private
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                def yaml_indent(level)
         
     | 
| 
      
 90 
     | 
    
         
            +
                  '  ' * level
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                def yaml_escape_value(val)
         
     | 
| 
      
 94 
     | 
    
         
            +
                  if val.include?("\n")
         
     | 
| 
      
 95 
     | 
    
         
            +
                    # Multiline block
         
     | 
| 
      
 96 
     | 
    
         
            +
                    "|\n" + val.split("\n").map { |l| "  " + l }.join("\n")
         
     | 
| 
      
 97 
     | 
    
         
            +
                  else
         
     | 
| 
      
 98 
     | 
    
         
            +
                    # Single line, quote if needed
         
     | 
| 
      
 99 
     | 
    
         
            +
                    val =~ /[\":{}\[\],#&*!|>'%@`]/ ? '"' + val.gsub('"', '\\"') + '"' : val
         
     | 
| 
      
 100 
     | 
    
         
            +
                  end
         
     | 
| 
      
 101 
     | 
    
         
            +
                end
         
     | 
| 
      
 102 
     | 
    
         
            +
              end
         
     | 
| 
      
 103 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/i18n_add.rb
    ADDED
    
    
    
        data/sig/i18n_add.rbs
    ADDED
    
    
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,67 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: i18n_add
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.2.0
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 7 
     | 
    
         
            +
            - theExtraTerrestrial
         
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 9 
     | 
    
         
            +
            bindir: exe
         
     | 
| 
      
 10 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2025-07-03 00:00:00.000000000 Z
         
     | 
| 
      
 12 
     | 
    
         
            +
            dependencies: []
         
     | 
| 
      
 13 
     | 
    
         
            +
            description: A command-line tool for adding and updating internationalization (i18n)
         
     | 
| 
      
 14 
     | 
    
         
            +
              translations in YAML files with support for nested keys and multiple locales.
         
     | 
| 
      
 15 
     | 
    
         
            +
            email:
         
     | 
| 
      
 16 
     | 
    
         
            +
            - erhards.timanis@miittech.lv
         
     | 
| 
      
 17 
     | 
    
         
            +
            executables:
         
     | 
| 
      
 18 
     | 
    
         
            +
            - i18n_add
         
     | 
| 
      
 19 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 20 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 21 
     | 
    
         
            +
            files:
         
     | 
| 
      
 22 
     | 
    
         
            +
            - ".rubocop.yml"
         
     | 
| 
      
 23 
     | 
    
         
            +
            - CHANGELOG.md
         
     | 
| 
      
 24 
     | 
    
         
            +
            - CONTRIBUTING.md
         
     | 
| 
      
 25 
     | 
    
         
            +
            - Gemfile
         
     | 
| 
      
 26 
     | 
    
         
            +
            - Gemfile.lock
         
     | 
| 
      
 27 
     | 
    
         
            +
            - LICENSE.txt
         
     | 
| 
      
 28 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 29 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 30 
     | 
    
         
            +
            - SECURITY.md
         
     | 
| 
      
 31 
     | 
    
         
            +
            - config/locales/en/main.en.yml
         
     | 
| 
      
 32 
     | 
    
         
            +
            - config/locales/es/main.es.yml
         
     | 
| 
      
 33 
     | 
    
         
            +
            - exe/i18n_add
         
     | 
| 
      
 34 
     | 
    
         
            +
            - i18n_add.gemspec
         
     | 
| 
      
 35 
     | 
    
         
            +
            - lib/i18n_add.rb
         
     | 
| 
      
 36 
     | 
    
         
            +
            - lib/i18n_add/cli.rb
         
     | 
| 
      
 37 
     | 
    
         
            +
            - lib/i18n_add/version.rb
         
     | 
| 
      
 38 
     | 
    
         
            +
            - lib/i18n_add/yaml_processor.rb
         
     | 
| 
      
 39 
     | 
    
         
            +
            - sig/i18n_add.rbs
         
     | 
| 
      
 40 
     | 
    
         
            +
            homepage: https://github.com/theExtraTerrestrial/i18n_add
         
     | 
| 
      
 41 
     | 
    
         
            +
            licenses:
         
     | 
| 
      
 42 
     | 
    
         
            +
            - MIT
         
     | 
| 
      
 43 
     | 
    
         
            +
            metadata:
         
     | 
| 
      
 44 
     | 
    
         
            +
              allowed_push_host: https://rubygems.org
         
     | 
| 
      
 45 
     | 
    
         
            +
              homepage_uri: https://github.com/theExtraTerrestrial/i18n_add
         
     | 
| 
      
 46 
     | 
    
         
            +
              source_code_uri: https://github.com/theExtraTerrestrial/i18n_add
         
     | 
| 
      
 47 
     | 
    
         
            +
              changelog_uri: https://github.com/theExtraTerrestrial/i18n_add/blob/main/CHANGELOG.md
         
     | 
| 
      
 48 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 49 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 50 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 51 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 52 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 53 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 54 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 55 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 56 
     | 
    
         
            +
                  version: 2.6.0
         
     | 
| 
      
 57 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 58 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 59 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 60 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 61 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 62 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 63 
     | 
    
         
            +
            rubygems_version: 3.2.33
         
     | 
| 
      
 64 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 65 
     | 
    
         
            +
            specification_version: 4
         
     | 
| 
      
 66 
     | 
    
         
            +
            summary: Add or update multiple translations in locale YAML files efficiently
         
     | 
| 
      
 67 
     | 
    
         
            +
            test_files: []
         
     |