Class: BetterTranslate::JsonHandler
- Inherits:
-
Object
- Object
- BetterTranslate::JsonHandler
- Defined in:
- lib/better_translate/json_handler.rb
Overview
Handles JSON file operations
Provides methods for:
- Reading and parsing JSON files
- Writing JSON files with proper formatting
- Merging translations (incremental mode)
- Handling exclusions
- Flattening/unflattening nested structures
Instance Attribute Summary collapse
-
#config ⇒ Configuration
readonly
Configuration object.
Instance Method Summary collapse
-
#build_output_path(target_lang_code) ⇒ String
Build output file path for target language.
-
#create_backup_file(file_path) ⇒ void
private
private
Create backup file with rotation support.
-
#filter_exclusions(strings, target_lang_code) ⇒ Hash
Filter out excluded keys for a specific language.
-
#get_source_strings ⇒ Hash
Get translatable strings from source JSON.
-
#initialize(config) ⇒ JsonHandler
constructor
Initialize JSON handler.
-
#merge_translations(file_path, new_translations) ⇒ Hash
Merge translated strings with existing file (incremental mode).
-
#read_json(file_path) ⇒ Hash
Read and parse JSON file.
-
#rotate_backups(file_path) ⇒ void
private
private
Rotate backup files, keeping only max_backups.
-
#write_json(file_path, data, diff_preview: nil) ⇒ Hash?
Write hash to JSON file.
Constructor Details
#initialize(config) ⇒ JsonHandler
Initialize JSON handler
35 36 37 |
# File 'lib/better_translate/json_handler.rb', line 35 def initialize(config) @config = config end |
Instance Attribute Details
#config ⇒ Configuration (readonly)
Returns Configuration object.
25 26 27 |
# File 'lib/better_translate/json_handler.rb', line 25 def config @config end |
Instance Method Details
#build_output_path(target_lang_code) ⇒ String
Build output file path for target language
174 175 176 177 178 |
# File 'lib/better_translate/json_handler.rb', line 174 def build_output_path(target_lang_code) return "#{target_lang_code}.json" unless config.output_folder File.join(config.output_folder, "#{target_lang_code}.json") end |
#create_backup_file(file_path) ⇒ void (private)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Create backup file with rotation support
188 189 190 191 192 193 194 195 196 197 |
# File 'lib/better_translate/json_handler.rb', line 188 def create_backup_file(file_path) return unless File.exist?(file_path) # Rotate existing backups if max_backups > 1 rotate_backups(file_path) if config.max_backups > 1 # Create primary backup backup_path = "#{file_path}.bak" FileUtils.cp(file_path, backup_path) end |
#filter_exclusions(strings, target_lang_code) ⇒ Hash
Filter out excluded keys for a specific language
131 132 133 134 135 136 |
# File 'lib/better_translate/json_handler.rb', line 131 def filter_exclusions(strings, target_lang_code) excluded_keys = config.global_exclusions.dup excluded_keys += config.exclusions_per_language[target_lang_code] || [] strings.reject { |key, _| excluded_keys.include?(key) } end |
#get_source_strings ⇒ Hash
Get translatable strings from source JSON
Reads the input file and returns a flattened hash of strings. Removes the root language key if present.
112 113 114 115 116 117 118 119 120 |
# File 'lib/better_translate/json_handler.rb', line 112 def get_source_strings return {} unless config.input_file source_data = read_json(config.input_file) # Remove root language key if present (e.g., "en:") source_data = source_data[config.source_language] || source_data Utils::HashFlattener.flatten(source_data) end |
#merge_translations(file_path, new_translations) ⇒ Hash
Merge translated strings with existing file (incremental mode)
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/better_translate/json_handler.rb', line 147 def merge_translations(file_path, new_translations) if File.exist?(file_path) existing = read_json(file_path) # Extract actual translations (remove language wrapper if present) target_lang = config.target_languages.first[:short_name] existing = existing[target_lang] || existing else existing = {} # : Hash[untyped, untyped] end existing_flat = Utils::HashFlattener.flatten(existing) # Merge: existing takes precedence merged = new_translations.merge(existing_flat) Utils::HashFlattener.unflatten(merged) end |
#read_json(file_path) ⇒ Hash
Read and parse JSON file
50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/better_translate/json_handler.rb', line 50 def read_json(file_path) Validator.validate_file_exists!(file_path) content = File.read(file_path) return {} if content.strip.empty? JSON.parse(content) rescue Errno::ENOENT => e raise FileError.new("File does not exist: #{file_path}", context: { error: e. }) rescue JSON::ParserError => e raise JsonError.new("Invalid JSON syntax in #{file_path}", context: { error: e. }) end |
#rotate_backups(file_path) ⇒ void (private)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Rotate backup files, keeping only max_backups
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/better_translate/json_handler.rb', line 205 def rotate_backups(file_path) primary_backup = "#{file_path}.bak" return unless File.exist?(primary_backup) # Clean up ANY backups that would exceed max_backups after rotation 10.downto(config.max_backups) do |i| numbered_backup = "#{file_path}.bak.#{i}" FileUtils.rm_f(numbered_backup) if File.exist?(numbered_backup) end # Rotate numbered backups from high to low to avoid overwrites (config.max_backups - 2).downto(1) do |i| old_path = "#{file_path}.bak.#{i}" new_path = "#{file_path}.bak.#{i + 1}" FileUtils.mv(old_path, new_path) if File.exist?(old_path) end # Move primary backup to .bak.1 FileUtils.mv(primary_backup, "#{file_path}.bak.1") end |
#write_json(file_path, data, diff_preview: nil) ⇒ Hash?
Write hash to JSON file
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/better_translate/json_handler.rb', line 74 def write_json(file_path, data, diff_preview: nil) summary = nil # Show diff preview if in dry run mode if config.dry_run && diff_preview existing_data = File.exist?(file_path) ? read_json(file_path) : {} # : Hash[untyped, untyped] summary = diff_preview.show_diff(existing_data, data, file_path) end return summary if config.dry_run # Create backup if enabled and file exists create_backup_file(file_path) if config.create_backup && File.exist?(file_path) # Ensure output directory exists FileUtils.mkdir_p(File.dirname(file_path)) # Write JSON with proper indentation File.write(file_path, JSON.pretty_generate(data)) nil rescue Errno::EACCES => e raise FileError.new("Permission denied: #{file_path}", context: { error: e. }) rescue StandardError => e raise FileError.new("Failed to write JSON: #{file_path}", context: { error: e. }) end |