better_translate 1.0.0.1 → 1.1.1

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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +28 -0
  3. data/.rubocop_todo.yml +291 -0
  4. data/CHANGELOG.md +88 -0
  5. data/CLAUDE.md +12 -7
  6. data/CONTRIBUTING.md +432 -0
  7. data/README.md +240 -1
  8. data/Rakefile +14 -1
  9. data/SECURITY.md +160 -0
  10. data/Steepfile +0 -1
  11. data/brakeman.yml +37 -0
  12. data/codecov.yml +34 -0
  13. data/lib/better_translate/analyzer/code_scanner.rb +149 -0
  14. data/lib/better_translate/analyzer/key_scanner.rb +109 -0
  15. data/lib/better_translate/analyzer/orphan_detector.rb +91 -0
  16. data/lib/better_translate/analyzer/reporter.rb +155 -0
  17. data/lib/better_translate/cli.rb +81 -2
  18. data/lib/better_translate/configuration.rb +76 -3
  19. data/lib/better_translate/errors.rb +9 -0
  20. data/lib/better_translate/json_handler.rb +227 -0
  21. data/lib/better_translate/translator.rb +205 -23
  22. data/lib/better_translate/version.rb +1 -1
  23. data/lib/better_translate/yaml_handler.rb +59 -0
  24. data/lib/better_translate.rb +7 -0
  25. data/lib/generators/better_translate/install/install_generator.rb +2 -2
  26. data/lib/generators/better_translate/install/templates/initializer.rb.tt +22 -34
  27. data/lib/generators/better_translate/translate/translate_generator.rb +65 -46
  28. data/lib/tasks/better_translate.rake +62 -45
  29. data/sig/better_translate/analyzer/code_scanner.rbs +59 -0
  30. data/sig/better_translate/analyzer/key_scanner.rbs +40 -0
  31. data/sig/better_translate/analyzer/orphan_detector.rbs +43 -0
  32. data/sig/better_translate/analyzer/reporter.rbs +70 -0
  33. data/sig/better_translate/cli.rbs +2 -0
  34. data/sig/better_translate/configuration.rbs +6 -0
  35. data/sig/better_translate/errors.rbs +4 -0
  36. data/sig/better_translate/json_handler.rbs +65 -0
  37. data/sig/better_translate/progress_tracker.rbs +1 -1
  38. data/sig/better_translate/translator.rbs +12 -1
  39. data/sig/better_translate/yaml_handler.rbs +6 -0
  40. data/sig/better_translate.rbs +4 -0
  41. data/sig/csv.rbs +16 -0
  42. metadata +32 -3
  43. data/regenerate_vcr.rb +0 -47
@@ -9,59 +9,75 @@ unless Rake::Task.task_defined?(:environment)
9
9
  end
10
10
  end
11
11
 
12
+ # rubocop:disable Metrics/BlockLength
12
13
  namespace :better_translate do
13
14
  desc "Translate YAML locale files using AI providers"
14
15
  task translate: :environment do
15
- config_file = Rails.root.join("config", "better_translate.yml")
16
+ # Check if configuration is already loaded (from initializer)
17
+ if BetterTranslate.configuration.provider.nil?
18
+ # No initializer configuration found, try loading from YAML
19
+ config_file = Rails.root.join("config", "better_translate.yml")
16
20
 
17
- unless File.exist?(config_file)
18
- puts "Error: Configuration file not found at #{config_file}"
19
- puts "Run 'rake better_translate:config:generate' to create one."
20
- exit 1
21
- end
21
+ unless File.exist?(config_file)
22
+ puts "Error: No configuration found"
23
+ puts "Either:"
24
+ puts " 1. Create config/initializers/better_translate.rb (recommended)"
25
+ puts " 2. Run 'rake better_translate:config:generate' to create YAML config"
26
+ exit 1
27
+ end
22
28
 
23
- # Load configuration from YAML
24
- yaml_config = YAML.load_file(config_file)
25
-
26
- # Configure BetterTranslate
27
- BetterTranslate.configure do |config|
28
- config.provider = yaml_config["provider"]&.to_sym
29
- config.openai_key = yaml_config["openai_key"] || ENV["OPENAI_API_KEY"]
30
- config.gemini_key = yaml_config["gemini_key"] || ENV["GEMINI_API_KEY"]
31
- config.anthropic_key = yaml_config["anthropic_key"] || ENV["ANTHROPIC_API_KEY"]
32
-
33
- config.source_language = yaml_config["source_language"]
34
- config.target_languages = yaml_config["target_languages"]&.map do |lang|
35
- if lang.is_a?(Hash)
36
- { short_name: lang["short_name"], name: lang["name"] }
37
- else
38
- lang
29
+ # Load configuration from YAML
30
+ yaml_config = YAML.load_file(config_file)
31
+
32
+ # Configure BetterTranslate
33
+ BetterTranslate.configure do |config|
34
+ config.provider = yaml_config["provider"]&.to_sym
35
+ config.openai_key = yaml_config["openai_key"] || ENV["OPENAI_API_KEY"]
36
+ config.gemini_key = yaml_config["gemini_key"] || ENV["GEMINI_API_KEY"]
37
+ config.anthropic_key = yaml_config["anthropic_key"] || ENV["ANTHROPIC_API_KEY"]
38
+
39
+ config.source_language = yaml_config["source_language"]
40
+ config.target_languages = yaml_config["target_languages"]&.map do |lang|
41
+ if lang.is_a?(Hash)
42
+ { short_name: lang["short_name"], name: lang["name"] }
43
+ else
44
+ lang
45
+ end
39
46
  end
47
+
48
+ config.input_file = yaml_config["input_file"]
49
+ config.output_folder = yaml_config["output_folder"]
50
+ config.verbose = yaml_config.fetch("verbose", true)
51
+ config.dry_run = yaml_config.fetch("dry_run", false)
52
+
53
+ # Map "full" to :override for backward compatibility
54
+ translation_mode = yaml_config.fetch("translation_mode", "override")
55
+ translation_mode = "override" if translation_mode == "full"
56
+ config.translation_mode = translation_mode.to_sym
57
+
58
+ config.preserve_variables = yaml_config.fetch("preserve_variables", true)
59
+
60
+ # Exclusions
61
+ config.global_exclusions = yaml_config["global_exclusions"] || []
62
+ config.exclusions_per_language = yaml_config["exclusions_per_language"] || {}
63
+
64
+ # Provider options
65
+ config.model = yaml_config["model"] if yaml_config["model"]
66
+ config.temperature = yaml_config["temperature"] if yaml_config["temperature"]
67
+ config.max_tokens = yaml_config["max_tokens"] if yaml_config["max_tokens"]
68
+ config.timeout = yaml_config["timeout"] if yaml_config["timeout"]
69
+ config.max_retries = yaml_config["max_retries"] if yaml_config["max_retries"]
70
+ config.rate_limit = yaml_config["rate_limit"] if yaml_config["rate_limit"]
40
71
  end
72
+ end
41
73
 
42
- config.input_file = yaml_config["input_file"]
43
- config.output_folder = yaml_config["output_folder"]
44
- config.verbose = yaml_config.fetch("verbose", true)
45
- config.dry_run = yaml_config.fetch("dry_run", false)
46
-
47
- # Map "full" to :override for backward compatibility
48
- translation_mode = yaml_config.fetch("translation_mode", "override")
49
- translation_mode = "override" if translation_mode == "full"
50
- config.translation_mode = translation_mode.to_sym
51
-
52
- config.preserve_variables = yaml_config.fetch("preserve_variables", true)
53
-
54
- # Exclusions
55
- config.global_exclusions = yaml_config["global_exclusions"] || []
56
- config.exclusions_per_language = yaml_config["exclusions_per_language"] || {}
57
-
58
- # Provider options
59
- config.model = yaml_config["model"] if yaml_config["model"]
60
- config.temperature = yaml_config["temperature"] if yaml_config["temperature"]
61
- config.max_tokens = yaml_config["max_tokens"] if yaml_config["max_tokens"]
62
- config.timeout = yaml_config["timeout"] if yaml_config["timeout"]
63
- config.max_retries = yaml_config["max_retries"] if yaml_config["max_retries"]
64
- config.rate_limit = yaml_config["rate_limit"] if yaml_config["rate_limit"]
74
+ # Validate configuration (whether from initializer or YAML)
75
+ begin
76
+ BetterTranslate.configuration.validate!
77
+ rescue BetterTranslate::ConfigurationError => e
78
+ puts "Error: Invalid configuration"
79
+ puts e.message
80
+ exit 1
65
81
  end
66
82
 
67
83
  # Perform translation
@@ -134,3 +150,4 @@ namespace :better_translate do
134
150
  end
135
151
  end
136
152
  end
153
+ # rubocop:enable Metrics/BlockLength
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BetterTranslate
4
+ module Analyzer
5
+ # Scans code files to find i18n key references
6
+ class CodeScanner
7
+ # I18n patterns to match
8
+ I18N_PATTERNS: Array[Regexp]
9
+
10
+ # File extensions to scan
11
+ SCANNABLE_EXTENSIONS: Array[String]
12
+
13
+ # Path to scan (file or directory)
14
+ attr_reader path: String
15
+
16
+ # Found i18n keys
17
+ attr_reader keys: Set[String]
18
+
19
+ # List of scanned files
20
+ attr_reader files_scanned: Array[String]
21
+
22
+ # Initialize scanner with path
23
+ #
24
+ # @param path File or directory path to scan
25
+ def initialize: (String path) -> void
26
+
27
+ # Scan path and extract i18n keys
28
+ #
29
+ # @return Set of found i18n keys
30
+ def scan: () -> Set[String]
31
+
32
+ # Get count of unique keys found
33
+ #
34
+ # @return Number of unique keys
35
+ def key_count: () -> Integer
36
+
37
+ private
38
+
39
+ # Validate that path exists
40
+ def validate_path!: () -> void
41
+
42
+ # Collect all scannable files from path
43
+ #
44
+ # @return List of file paths
45
+ def collect_files: () -> Array[String]
46
+
47
+ # Check if file should be scanned
48
+ #
49
+ # @param file File path
50
+ # @return Boolean
51
+ def scannable_file?: (String file) -> bool
52
+
53
+ # Scan single file and extract keys
54
+ #
55
+ # @param file File path
56
+ def scan_file: (String file) -> void
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BetterTranslate
4
+ module Analyzer
5
+ # Scans YAML translation files and extracts all keys in flatten format
6
+ class KeyScanner
7
+ # Path to the YAML file
8
+ attr_reader file_path: String
9
+
10
+ # Flatten keys extracted from YAML
11
+ attr_reader keys: Hash[String, untyped]
12
+
13
+ # Initialize scanner with YAML file path
14
+ #
15
+ # @param file_path Path to YAML file
16
+ def initialize: (String file_path) -> void
17
+
18
+ # Scan YAML file and extract all flatten keys
19
+ #
20
+ # @return Flatten keys with their values
21
+ def scan: () -> Hash[String, untyped]
22
+
23
+ # Get total count of keys
24
+ #
25
+ # @return Number of keys
26
+ def key_count: () -> Integer
27
+
28
+ private
29
+
30
+ # Validate that file exists
31
+ def validate_file!: () -> void
32
+
33
+ # Flatten nested hash into dot-notation keys
34
+ #
35
+ # @param hash Nested hash to flatten
36
+ # @param prefix Prefix for current level
37
+ def flatten_keys: (Hash[untyped, untyped] hash, ?String? prefix) -> void
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BetterTranslate
4
+ module Analyzer
5
+ # Detects orphan i18n keys (keys defined but never used in code)
6
+ class OrphanDetector
7
+ # All translation keys with their values
8
+ attr_reader all_keys: Hash[String, untyped]
9
+
10
+ # Keys that are used in code
11
+ attr_reader used_keys: Set[String]
12
+
13
+ # Orphan keys (not used in code)
14
+ attr_reader orphans: Array[String]
15
+
16
+ # Initialize detector
17
+ #
18
+ # @param all_keys All translation keys from YAML files
19
+ # @param used_keys Keys found in code
20
+ def initialize: (Hash[String, untyped] all_keys, Set[String] used_keys) -> void
21
+
22
+ # Detect orphan keys
23
+ #
24
+ # @return List of orphan key names
25
+ def detect: () -> Array[String]
26
+
27
+ # Get count of orphan keys
28
+ #
29
+ # @return Number of orphan keys
30
+ def orphan_count: () -> Integer
31
+
32
+ # Get details of orphan keys with their values
33
+ #
34
+ # @return Hash of orphan keys and their translation values
35
+ def orphan_details: () -> Hash[String, untyped]
36
+
37
+ # Calculate usage percentage
38
+ #
39
+ # @return Percentage of keys that are used (0.0 to 100.0)
40
+ def usage_percentage: () -> Float
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BetterTranslate
4
+ module Analyzer
5
+ # Generates reports for orphan key analysis
6
+ class Reporter
7
+ # List of orphan keys
8
+ attr_reader orphans: Array[String]
9
+
10
+ # Orphan keys with their values
11
+ attr_reader orphan_details: Hash[String, untyped]
12
+
13
+ # Total number of keys
14
+ attr_reader total_keys: Integer
15
+
16
+ # Number of used keys
17
+ attr_reader used_keys: Integer
18
+
19
+ # Usage percentage
20
+ attr_reader usage_percentage: Float
21
+
22
+ # Output format (:text, :json, :csv)
23
+ attr_reader format: Symbol
24
+
25
+ # Initialize reporter
26
+ #
27
+ # @param orphans List of orphan keys
28
+ # @param orphan_details Orphan keys with values
29
+ # @param total_keys Total number of keys
30
+ # @param used_keys Number of used keys
31
+ # @param usage_percentage Usage percentage
32
+ # @param format Output format (:text, :json, :csv)
33
+ def initialize: (
34
+ orphans: Array[String],
35
+ orphan_details: Hash[String, untyped],
36
+ total_keys: Integer,
37
+ used_keys: Integer,
38
+ usage_percentage: Float,
39
+ ?format: Symbol
40
+ ) -> void
41
+
42
+ # Generate report in specified format
43
+ #
44
+ # @return Generated report
45
+ def generate: () -> String
46
+
47
+ # Save report to file
48
+ #
49
+ # @param file_path Output file path
50
+ def save_to_file: (String file_path) -> void
51
+
52
+ private
53
+
54
+ # Generate text format report
55
+ #
56
+ # @return Text report
57
+ def generate_text: () -> String
58
+
59
+ # Generate JSON format report
60
+ #
61
+ # @return JSON report
62
+ def generate_json: () -> String
63
+
64
+ # Generate CSV format report
65
+ #
66
+ # @return CSV report
67
+ def generate_csv: () -> String
68
+ end
69
+ end
70
+ end
@@ -20,5 +20,7 @@ module BetterTranslate
20
20
  def run_generate: () -> void
21
21
 
22
22
  def run_direct: () -> void
23
+
24
+ def run_analyze: () -> void
23
25
  end
24
26
  end
@@ -27,6 +27,9 @@ module BetterTranslate
27
27
  @global_exclusions: Array[String]
28
28
  @exclusions_per_language: Hash[String, Array[String]]
29
29
  @preserve_variables: bool
30
+ @input_files: (String | Array[String])?
31
+ @create_backup: bool
32
+ @max_backups: Integer
30
33
 
31
34
  attr_accessor provider: (Symbol | nil)
32
35
  attr_accessor openai_key: String?
@@ -56,6 +59,9 @@ module BetterTranslate
56
59
  attr_accessor global_exclusions: Array[String]
57
60
  attr_accessor exclusions_per_language: Hash[String, Array[String]]
58
61
  attr_accessor preserve_variables: bool
62
+ attr_accessor input_files: (String | Array[String])?
63
+ attr_accessor create_backup: bool
64
+ attr_accessor max_backups: Integer
59
65
 
60
66
  # Provider-specific options
61
67
  attr_accessor model: String?
@@ -40,6 +40,10 @@ module BetterTranslate
40
40
  class YamlError < Error
41
41
  end
42
42
 
43
+ # Raised when JSON parsing fails
44
+ class JsonError < Error
45
+ end
46
+
43
47
  # Raised when a provider is not found
44
48
  class ProviderNotFoundError < Error
45
49
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BetterTranslate
4
+ # Handles JSON file operations
5
+ class JsonHandler
6
+ # Configuration object
7
+ attr_reader config: Configuration
8
+
9
+ # Initialize JSON handler
10
+ #
11
+ # @param config Configuration object
12
+ def initialize: (Configuration config) -> void
13
+
14
+ # Read and parse JSON file
15
+ #
16
+ # @param file_path Path to JSON file
17
+ # @return Parsed JSON content
18
+ def read_json: (String file_path) -> Hash[untyped, untyped]
19
+
20
+ # Write hash to JSON file
21
+ #
22
+ # @param file_path Output file path
23
+ # @param data Data to write
24
+ # @param diff_preview Optional diff preview instance
25
+ # @return Summary hash if dry_run, nil otherwise
26
+ def write_json: (String file_path, Hash[untyped, untyped] data, ?diff_preview: untyped) -> (Hash[Symbol, untyped] | nil)
27
+
28
+ # Get translatable strings from source JSON
29
+ #
30
+ # @return Flattened hash of translatable strings
31
+ def get_source_strings: () -> Hash[String, untyped]
32
+
33
+ # Filter out excluded keys for a specific language
34
+ #
35
+ # @param strings Flattened strings
36
+ # @param target_lang_code Target language code
37
+ # @return Filtered strings
38
+ def filter_exclusions: (Hash[String, untyped] strings, String target_lang_code) -> Hash[String, untyped]
39
+
40
+ # Merge translated strings with existing file (incremental mode)
41
+ #
42
+ # @param file_path Existing file path
43
+ # @param new_translations New translations (flattened)
44
+ # @return Merged translations (nested)
45
+ def merge_translations: (String file_path, Hash[String, untyped] new_translations) -> Hash[String, untyped]
46
+
47
+ # Build output file path for target language
48
+ #
49
+ # @param target_lang_code Target language code
50
+ # @return Output file path
51
+ def build_output_path: (String target_lang_code) -> String
52
+
53
+ private
54
+
55
+ # Create backup file with rotation support
56
+ #
57
+ # @param file_path Path to file to backup
58
+ def create_backup_file: (String file_path) -> void
59
+
60
+ # Rotate backup files, keeping only max_backups
61
+ #
62
+ # @param file_path Base file path
63
+ def rotate_backups: (String file_path) -> void
64
+ end
65
+ end
@@ -14,7 +14,7 @@ module BetterTranslate
14
14
 
15
15
  def complete: (String language, Integer total_strings) -> void
16
16
 
17
- def error: (String language, StandardError error) -> void
17
+ def error: (String language, Exception error) -> void
18
18
 
19
19
  def reset: () -> void
20
20
 
@@ -10,6 +10,7 @@ module BetterTranslate
10
10
  @provider: Providers::BaseHttpProvider
11
11
  @yaml_handler: YAMLHandler
12
12
  @progress_tracker: ProgressTracker
13
+ @input_files: Array[String]
13
14
 
14
15
  attr_reader config: Configuration
15
16
 
@@ -19,6 +20,16 @@ module BetterTranslate
19
20
 
20
21
  private
21
22
 
22
- def translate_language: (Hash[String, untyped] source_strings, Hash[Symbol, String] lang) -> void
23
+ def resolve_input_files: () -> Array[String]
24
+
25
+ def translate_parallel: (Hash[String, untyped] source_strings, (YAMLHandler | JsonHandler) handler) -> translation_results
26
+
27
+ def translate_sequential: (Hash[String, untyped] source_strings, (YAMLHandler | JsonHandler) handler) -> translation_results
28
+
29
+ def translate_language: (Hash[String, untyped] source_strings, Hash[Symbol, String] lang, (YAMLHandler | JsonHandler) handler) -> void
30
+
31
+ def record_error: (translation_results results, Hash[Symbol, String] lang, Exception error) -> void
32
+
33
+ def build_output_path_for_file: (String input_file, String target_lang_code) -> String
23
34
  end
24
35
  end
@@ -25,5 +25,11 @@ module BetterTranslate
25
25
  def merge_translations: (String file_path, Hash[String, untyped] new_translations) -> Hash[String, untyped]
26
26
 
27
27
  def build_output_path: (String target_lang_code) -> String
28
+
29
+ private
30
+
31
+ def create_backup_file: (String file_path) -> void
32
+
33
+ def rotate_backups: (String file_path) -> void
28
34
  end
29
35
  end
@@ -5,6 +5,10 @@
5
5
  module BetterTranslate
6
6
  type translation_results = { success_count: Integer, failure_count: Integer, errors: Array[Hash[Symbol, untyped]] }
7
7
 
8
+ # Analyzer module for translation file analysis
9
+ module Analyzer
10
+ end
11
+
8
12
  # Module-level instance variable (for singleton methods)
9
13
  self.@configuration: Configuration?
10
14
 
data/sig/csv.rbs ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # CSV library type signatures
4
+ class CSV
5
+ # Generate CSV string
6
+ #
7
+ # @yield CSV instance for writing rows
8
+ # @return CSV string
9
+ def self.generate: () { (CSV) -> void } -> String
10
+
11
+ # Add row to CSV
12
+ #
13
+ # @param row Array of values
14
+ # @return CSV instance
15
+ def <<: (Array[untyped]) -> CSV
16
+ end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_translate
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.1
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - alessiobussolari
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-10-22 00:00:00.000000000 Z
11
+ date: 2025-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: csv
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: faraday
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -36,15 +50,20 @@ files:
36
50
  - ".env.example"
37
51
  - ".rspec"
38
52
  - ".rubocop.yml"
53
+ - ".rubocop_todo.yml"
39
54
  - ".yardopts"
40
55
  - CHANGELOG.md
41
56
  - CLAUDE.md
42
57
  - CODE_OF_CONDUCT.md
58
+ - CONTRIBUTING.md
43
59
  - LICENSE.txt
44
60
  - README.md
45
61
  - RELEASE_NOTES_v1.0.0.md
46
62
  - Rakefile
63
+ - SECURITY.md
47
64
  - Steepfile
65
+ - brakeman.yml
66
+ - codecov.yml
48
67
  - docs/implementation/00-overview.md
49
68
  - docs/implementation/01-setup_dependencies.md
50
69
  - docs/implementation/02-error_handling.md
@@ -61,11 +80,16 @@ files:
61
80
  - docs/implementation/12-cli_standalone.md
62
81
  - exe/better_translate
63
82
  - lib/better_translate.rb
83
+ - lib/better_translate/analyzer/code_scanner.rb
84
+ - lib/better_translate/analyzer/key_scanner.rb
85
+ - lib/better_translate/analyzer/orphan_detector.rb
86
+ - lib/better_translate/analyzer/reporter.rb
64
87
  - lib/better_translate/cache.rb
65
88
  - lib/better_translate/cli.rb
66
89
  - lib/better_translate/configuration.rb
67
90
  - lib/better_translate/direct_translator.rb
68
91
  - lib/better_translate/errors.rb
92
+ - lib/better_translate/json_handler.rb
69
93
  - lib/better_translate/progress_tracker.rb
70
94
  - lib/better_translate/provider_factory.rb
71
95
  - lib/better_translate/providers/anthropic_provider.rb
@@ -93,13 +117,17 @@ files:
93
117
  - lib/generators/better_translate/translate/USAGE
94
118
  - lib/generators/better_translate/translate/translate_generator.rb
95
119
  - lib/tasks/better_translate.rake
96
- - regenerate_vcr.rb
97
120
  - sig/better_translate.rbs
121
+ - sig/better_translate/analyzer/code_scanner.rbs
122
+ - sig/better_translate/analyzer/key_scanner.rbs
123
+ - sig/better_translate/analyzer/orphan_detector.rbs
124
+ - sig/better_translate/analyzer/reporter.rbs
98
125
  - sig/better_translate/cache.rbs
99
126
  - sig/better_translate/cli.rbs
100
127
  - sig/better_translate/configuration.rbs
101
128
  - sig/better_translate/direct_translator.rbs
102
129
  - sig/better_translate/errors.rbs
130
+ - sig/better_translate/json_handler.rbs
103
131
  - sig/better_translate/progress_tracker.rbs
104
132
  - sig/better_translate/provider_factory.rbs
105
133
  - sig/better_translate/providers/anthropic_provider.rbs
@@ -118,6 +146,7 @@ files:
118
146
  - sig/better_translate/variable_extractor.rbs
119
147
  - sig/better_translate/version.rbs
120
148
  - sig/better_translate/yaml_handler.rbs
149
+ - sig/csv.rbs
121
150
  - sig/faraday.rbs
122
151
  - sig/generators/better_translate/analyze/analyze_generator.rbs
123
152
  - sig/generators/better_translate/install/install_generator.rbs
data/regenerate_vcr.rb DELETED
@@ -1,47 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "bundler/setup"
5
- require "dotenv/load"
6
- require "vcr"
7
- require "webmock/rspec"
8
- require_relative "lib/better_translate"
9
- require "tmpdir"
10
-
11
- # Setup VCR
12
- VCR.configure do |config|
13
- config.cassette_library_dir = "spec/vcr_cassettes"
14
- config.hook_into :webmock
15
- config.filter_sensitive_data("<GEMINI_API_KEY>") { ENV["GEMINI_API_KEY"] }
16
- config.default_cassette_options = { record: :all }
17
- end
18
-
19
- test_dir = Dir.mktmpdir("gemini_test")
20
- puts "Test output dir: #{test_dir}"
21
-
22
- VCR.use_cassette("rails/dummy_app_gemini_translation", record: :all) do
23
- config = BetterTranslate::Configuration.new
24
- config.provider = :gemini
25
- config.gemini_key = ENV["GEMINI_API_KEY"]
26
- config.source_language = "en"
27
- config.target_languages = [{ short_name: "fr", name: "French" }]
28
- config.input_file = "spec/dummy/config/locales/en.yml"
29
- config.output_folder = test_dir
30
- config.cache_enabled = false
31
- config.verbose = true
32
- config.validate!
33
-
34
- puts "Starting translation..."
35
- translator = BetterTranslate::Translator.new(config)
36
- results = translator.translate_all
37
-
38
- puts "\nResults: #{results.inspect}"
39
- puts "\nFiles created:"
40
- Dir.entries(test_dir).each { |f| puts " - #{f}" unless f.start_with?(".") }
41
-
42
- if results[:success_count].positive?
43
- puts "\n✓ Successfully regenerated VCR cassette!"
44
- else
45
- puts "\n✗ Translation failed"
46
- end
47
- end