Class: BetterTranslate::VariableExtractor
- Inherits:
-
Object
- Object
- BetterTranslate::VariableExtractor
- Defined in:
- lib/better_translate/variable_extractor.rb
Overview
Extracts and preserves interpolation variables during translation
Supports multiple variable formats:
- Rails I18n: %name, %count
- I18n.js: {user}, {email}
- ES6 templates: $var
- Simple braces: name
Variables are extracted before translation, replaced with safe placeholders, and then restored after translation to ensure they remain unchanged.
Constant Summary collapse
- VARIABLE_PATTERNS =
Variable patterns to detect and preserve
{ rails_template: /%\{[^}]+\}/, # %{name}, %{count} rails_annotated: /%<[^>]+>[a-z]/i, # %<name>s, %<count>d i18n_js: /\{\{[^}]+\}\}/, # {{user}}, {{email}} es6: /\$\{[^}]+\}/, # ${var} simple: /\{[a-zA-Z_][a-zA-Z0-9_]*\}/ # {name} but not {1,2,3} }.freeze
- COMBINED_PATTERN =
Combined pattern to match any variable format
Regexp.union(*VARIABLE_PATTERNS.values).freeze
- PLACEHOLDER_PREFIX =
Placeholder prefix
"VARIABLE_"- PLACEHOLDER_SUFFIX =
Placeholder suffix
""
Instance Attribute Summary collapse
-
#original_text ⇒ String
readonly
Original text with variables.
-
#placeholder_map ⇒ Hash<String, String>
readonly
Mapping of placeholders to original variables.
-
#variables ⇒ Array<String>
readonly
Extracted variables in order.
Class Method Summary collapse
-
.contains_variables?(text) ⇒ Boolean
Check if text contains variables.
-
.find_variables(text) ⇒ Array<String>
Extract variables from text without creating instance.
Instance Method Summary collapse
-
#extract ⇒ String
Extract variables and replace with placeholders.
-
#initialize(text) ⇒ VariableExtractor
constructor
Initialize extractor with text.
-
#restore(translated_text, strict: true) ⇒ String
Restore variables from placeholders in translated text.
-
#validate_variables!(text) ⇒ true
Validate that all original variables are present in text.
-
#variable_count ⇒ Integer
Get count of variables.
-
#variables? ⇒ Boolean
Check if text contains variables.
Constructor Details
#initialize(text) ⇒ VariableExtractor
Initialize extractor with text
65 66 67 68 69 70 |
# File 'lib/better_translate/variable_extractor.rb', line 65 def initialize(text) @original_text = text @variables = [] @placeholder_map = {} @reverse_map = {} end |
Instance Attribute Details
#original_text ⇒ String (readonly)
50 51 52 |
# File 'lib/better_translate/variable_extractor.rb', line 50 def original_text @original_text end |
#placeholder_map ⇒ Hash<String, String> (readonly)
56 57 58 |
# File 'lib/better_translate/variable_extractor.rb', line 56 def placeholder_map @placeholder_map end |
#variables ⇒ Array<String> (readonly)
53 54 55 |
# File 'lib/better_translate/variable_extractor.rb', line 53 def variables @variables end |
Class Method Details
.contains_variables?(text) ⇒ Boolean
Check if text contains variables
Static method to quickly check if text contains any supported variable format.
253 254 255 256 257 |
# File 'lib/better_translate/variable_extractor.rb', line 253 def self.contains_variables?(text) return false if text.nil? || text.empty? text.match?(COMBINED_PATTERN) end |
.find_variables(text) ⇒ Array<String>
Extract variables from text without creating instance
Static method to find all variables in text without needing to instantiate the extractor.
235 236 237 238 239 |
# File 'lib/better_translate/variable_extractor.rb', line 235 def self.find_variables(text) return [] if text.nil? || text.empty? text.scan(COMBINED_PATTERN) end |
Instance Method Details
#extract ⇒ String
Extract variables and replace with placeholders
Scans the text for all supported variable formats and replaces them with numbered placeholders (VARIABLE_0, VARIABLE_1, etc.).
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/better_translate/variable_extractor.rb', line 83 def extract return "" if original_text.nil? || original_text.empty? result = original_text.dup index = 0 # Find and replace all variables result.gsub!(COMBINED_PATTERN) do |match| placeholder = "#{PLACEHOLDER_PREFIX}#{index}#{PLACEHOLDER_SUFFIX}" @variables << match @placeholder_map[placeholder] = match @reverse_map[match] = placeholder index += 1 placeholder end result end |
#restore(translated_text, strict: true) ⇒ String
Restore variables from placeholders in translated text
Replaces all placeholders with their original variable formats. In strict mode, validates that all original variables are present.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/better_translate/variable_extractor.rb', line 122 def restore(translated_text, strict: true) return "" if translated_text.nil? || translated_text.empty? result = translated_text.dup # Restore all placeholders @placeholder_map.each do |placeholder, original_var| result.gsub!(placeholder, original_var) end # Validate all variables are present validate_variables!(result) if strict result end |
#validate_variables!(text) ⇒ true
Validate that all original variables are present in text
Checks that:
- All original variables are still present
- No unexpected/extra variables have been added
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/better_translate/variable_extractor.rb', line 184 def validate_variables!(text) # @type var missing: Array[String] missing = [] # @type var extra: Array[String] extra = [] # Check for missing variables @variables.each do |var| var_str = var.is_a?(String) ? var : var.to_s missing << var_str unless text.include?(var_str) end # Check for extra/unknown variables (potential corruption) found_vars = text.scan(COMBINED_PATTERN) found_vars.each do |var| var_str = var.is_a?(String) ? var : var.to_s extra << var_str unless @variables.include?(var_str) end if missing.any? || extra.any? # @type var error_msg: Array[String] error_msg = [] error_msg << "Missing variables: #{missing.join(", ")}" if missing.any? error_msg << "Unexpected variables: #{extra.join(", ")}" if extra.any? raise ValidationError.new( "Variable validation failed: #{error_msg.join("; ")}", context: { original_variables: @variables, missing: missing, extra: extra, text: text } ) end true end |
#variable_count ⇒ Integer
Get count of variables
160 161 162 |
# File 'lib/better_translate/variable_extractor.rb', line 160 def variable_count @variables.size end |
#variables? ⇒ Boolean
Check if text contains variables
147 148 149 |
# File 'lib/better_translate/variable_extractor.rb', line 147 def variables? !@variables.empty? end |