class Rubustrings::Action

Public Instance Methods

add_line_numbers(file_data) click to toggle source
# File lib/rubustrings/action.rb, line 53
def add_line_numbers(file_data)
  line_num = 0
  result = ''
  file_data.each_line do |line|
    line_num += 1
    result += "#{line_num} #{line}"
  end
  result
end
check_translation_length(translation_key, translation_value) click to toggle source
# File lib/rubustrings/action.rb, line 140
def check_translation_length(translation_key, translation_value)
  translation_value.length / translation_key.length < 3
end
log_output(level, file_name, line_number, message) click to toggle source

Possible levels are :error, :result_error, :warning, :result_success, :info

# File lib/rubustrings/action.rb, line 24
def log_output(level, file_name, line_number, message)
  message = message.chomp
  case level
  when :error
    puts "#{file_name}:#{line_number}: error: #{message}"
  when :warning
    puts "#{file_name}:#{line_number}: warning: #{message}"
  when :result_success
    puts "\nResult: ✓ #{message}".bold.green
  when :result_error
    puts "\nResult: ✘ #{message}".bold.red
  when :info
    puts message.to_s.blue
  end
end
open_and_read_file(file_name) click to toggle source
# File lib/rubustrings/action.rb, line 63
def open_and_read_file(file_name)
  return nil unless File.exist?(file_name)

  begin
    File.open(file_name, 'rb:utf-16:utf-8').read
  rescue
    File.open(file_name, 'rb:utf-8:utf-8').read
  end
end
remove_comments_and_empty_lines(file_data) click to toggle source
# File lib/rubustrings/action.rb, line 73
def remove_comments_and_empty_lines(file_data)
  multiline_comments_regex = %r{/\*.*?\*/}m
  empty_lines_regex = /^[1-9]\d* $\n/

  file_data_with_lines = add_line_numbers file_data
  file_data_with_lines.gsub(multiline_comments_regex, '').gsub(empty_lines_regex, '') if file_data
end
validate(filenames, only_format) click to toggle source
# File lib/rubustrings/action.rb, line 7
def validate(filenames, only_format)
  abort 'No strings file provided' unless filenames
  filenames.each do |file_name|
    log_output(:info, '', 0, "Processing file: \"#{file_name}\"\n")
    result = validate_localizable_string_file file_name, only_format

    if result
      log_output(:result_success, file_name, 0, 'Strings file validated succesfully')
      return true
    else
      log_output(:result_error, file_name, 0, 'Some errors detected')
      return false
    end
  end
end
validate_format(line) click to toggle source
# File lib/rubustrings/action.rb, line 81
def validate_format(line)
  localizable_strings_format_regex = /^\"((?:\\.|[^\\"])*?)\"\s=\s\"((?:\\.|[^\\"])*?)\";/
  localizable_strings_format_regex.match line
end
validate_localizable_string_file(file_name, only_format) click to toggle source
# File lib/rubustrings/action.rb, line 40
def validate_localizable_string_file(file_name, only_format) 
  file_data = open_and_read_file file_name
  cleaned_strings = remove_comments_and_empty_lines file_data

  return log_output(:error, file_name, 0, "no translations found in file: #{file_name}") if cleaned_strings.empty?

  validation_result = true
  cleaned_strings.each_line do |line|
    validation_result &= validate_translation_line file_name, line, only_format
  end
  validation_result
end
validate_special_beginning(translation_key, translation_value) click to toggle source
# File lib/rubustrings/action.rb, line 126
def validate_special_beginning(translation_key, translation_value)
  beginning_regex = /^(?:\s|\n|\r)/

  return true unless translation_key =~ beginning_regex || translation_value =~ beginning_regex
  translation_key.chars.first == translation_value.chars.first
end
validate_special_characters(translation_key, translation_value) click to toggle source
# File lib/rubustrings/action.rb, line 86
def validate_special_characters(translation_key, translation_value)
  # Remove %% to avoid ambiguous scenarios with adjacent formats like "%s%%s"
  translation_key = translation_key.gsub("%%", " ")
  translation_value = translation_value.gsub("%%", " ")

  variables_regex = /\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?(hh|ll|[hlLzjt])?([b-fiosuxX@])/
  position_index = 0
  length_index = 7
  format_index = 8

  # sort by according to parameter field, if specified
  key_variables = translation_key.scan(variables_regex).stable_sort_by{ |r| r[position_index].to_i }
  value_variables = translation_value.scan(variables_regex).stable_sort_by{ |r| r[position_index].to_i }

  return true unless key_variables.any? || value_variables.any?
  return false unless key_variables.count == value_variables.count

  # we should not have any parameter fields in the keys
  return false unless key_variables.last[position_index] == nil

  # if we do have parameter fields, we need to include all of them
  if value_variables[0][position_index] != nil
    return false unless value_variables.last[position_index] != nil
    validation_result = true
    value_variables.each_with_index { |v, idx|
      if v[position_index].to_i != idx + 1
        validation_result = false
      end
    }
    return false unless validation_result
  else
    return false unless value_variables.last[position_index] == nil
  end

  # remove parameter field
  key_variables = key_variables.map{ |v| [v[length_index], v[format_index]] }
  value_variables = value_variables.map{ |v| [v[length_index], v[format_index]] }
  key_variables == value_variables
end
validate_special_ending(translation_key, translation_value) click to toggle source
# File lib/rubustrings/action.rb, line 133
def validate_special_ending(translation_key, translation_value)
  ending_regex = /(?:\s|\n|\r)$/

  return true unless translation_key =~ ending_regex || translation_value =~ ending_regex
  translation_key.chars.last == translation_value.chars.last
end
validate_translation_line(file_name, line, only_format) click to toggle source
# File lib/rubustrings/action.rb, line 144
def validate_translation_line(file_name, line, only_format)
  line_number = 0

  empty_regex = /^\d+\s*\n?$/
  return true if empty_regex.match line

  numbered_line_regex = /^(\d+) (.*)/
  numbered_line_match = numbered_line_regex.match line

  return log_output(:error, file_name, line_number, 'internal error') unless numbered_line_match
  line_number = numbered_line_match[1]
  line = numbered_line_match[2]

  match = validate_format line
  return log_output(:error, file_name, line_number, "invalid format: #{line}") unless match

  return true if only_format

  match_key = match[1]
  match_value = match[2]

  log_output(:warning, file_name, line_number, "no translated string: #{line}") if match_value.empty?

  log_output(:warning, file_name, line_number, "translation significantly large: #{line}") unless check_translation_length match_key, match_value

  validation_special_characters = validate_special_characters match_key, match_value
  log_output(:error, file_name, line_number, "variables mismatch: #{line}") unless validation_special_characters

  validation_special_beginning = validate_special_beginning match_key, match_value
  log_output(:error, file_name, line_number, "beginning mismatch: #{line}") unless validation_special_beginning

  validation_special_ending = validate_special_ending match_key, match_value
  log_output(:error, file_name, line_number, "ending mismatch: #{line}") unless validation_special_ending

  validation_special_characters && validation_special_beginning && validation_special_ending
end