Module: LostInTranslation

Included in:
Lit
Defined in:
lib/lit/hash.rb,
lib/tasks/count.rb,
lib/tasks/start.rb,
lib/lit/railties.rb,
lib/tasks/recent.rb,
lib/tasks/compare.rb,
lib/lit/difference.rb,
lib/tasks/sort_file.rb,
lib/tasks/split_file.rb,
lib/lit/file_functions.rb,
lib/lit/user_interface.rb,
lib/lost_in_translation.rb,
lib/tasks/delete_missing.rb,
lib/tasks/half_automatic.rb,
lib/tasks/fully_automatic.rb

Defined Under Namespace

Classes: Railtie

Class Method Summary collapse

Class Method Details

.ask_for_file(master, namespace = '') ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/lit/user_interface.rb', line 7

def self.ask_for_file(master, namespace = '')
  text = master ? "# Master-Locale (e.g. 'en'): " : "# Slave-Locale (e.g. 'de'): "
  file = {}
  file[:lang] = [(print text), Readline.readline()][1]
  file[:filename] = namespace.blank? ? file[:lang] : "#{namespace}.#{file[:lang]}"
  file[:path] = defined?(Rails) ? "#{Rails.root}/config/locales/#{file[:filename]}.yml" : ask_for_path
  if !File.exist?(file[:path]) && master
    log "File #{file[:path]} not found!"
    file[:path] = ask_for_path
  elsif !File.exist?(file[:path]) && !master
    log "File #{file[:filename]} not found! It will be created!"
    File.open(file[:path], 'w') { |f| f.write({ file[:lang] => {} }.to_yaml(line_width: -1)) }
  end
  file[:app_name] = Rails&.application&.class&.parent_name
  file
end

.ask_for_locales_pathObject



24
25
26
27
28
29
30
31
# File 'lib/lit/user_interface.rb', line 24

def self.ask_for_locales_path
  return "#{Rails.root}/config/locales" if defined?(Rails)
  log
  log 'Please type in the absolute path your locales-folder?'
  log 'e.g. /home/youruser/Documents/your-awesome-app/config/locales'
  path = [(print '# '), Readline.readline()][1]
  path
end

.ask_for_permission(master, count, slave = nil) ⇒ Object



33
34
35
36
37
38
39
40
41
42
# File 'lib/lit/user_interface.rb', line 33

def self.ask_for_permission(master, count, slave = nil)
  log
  log 'Comparing Locales'
  log "Application: #{master[:app_name]}" if master[:app_name]
  log "Master Locale: #{master[:filename]}.yml" if master
  log "Slave Locale: #{slave[:filename]}.yml" if slave
  log "Difference: #{count} Entries"
  a = [(print "# Wanna do it? [Y/n]: "), Readline.readline()][1]
  a == 'y' || a == 'Y' || a == ''
end

.ask_for_sorting(file, app_name) ⇒ Object



67
68
69
70
71
72
73
74
# File 'lib/lit/user_interface.rb', line 67

def self.ask_for_sorting(file, app_name)
  log
  log "Application: #{app_name}" unless app_name.blank?
  log "Do you want the #{file}.yml to be sorted?"
  log 'Alphabetically & Recursive (ASC)'
  a = [(print "# [Y/n]: "), Readline.readline()][1]
  a == 'y' || a == 'Y' || a == ''
end

.ask_for_split(file, count) ⇒ Object



59
60
61
62
63
64
65
# File 'lib/lit/user_interface.rb', line 59

def self.ask_for_split(file, count)
  log
  log "Splitting File #{file}.yml"
  log "File-Count: #{count} new files will be create!"
  a = [(print "# Wanna do it? [Y/n]: "), Readline.readline()][1]
  a == 'y' || a == 'Y' || a == ''
end

.ask_for_task(tasks) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/lit/user_interface.rb', line 44

def self.ask_for_task(tasks)
  log
  log 'Welcome, stranger!'
  log 'Are you lost in translation, too?'
  log 'Then I will be glad to help you one of the following tasks!'
  tasks.each_with_index do |task, i|
    log "#{i + 1} => #{task[:text]}"
  end
  log 'Soo ... what can I do for you? (Type in the Number)'
  id = [(print 'Task No.: '), Readline.readline()][1]
  tasks[(id.to_i - 1)]
rescue
  puts "Cannot find task with id #{id}"
end

.ask_for_translation(value, new_structure, lang1, lang2, diff_count, diff_counter) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/lit/user_interface.rb', line 76

def self.ask_for_translation(value, new_structure, lang1, lang2, diff_count, diff_counter)
  system 'clear'
  log
  log "#{diff_counter} / #{diff_count}"
  new_s = new_structure.join('---')
  log "#{new_s} is missing"

  snippets = LostInTranslation.define_snippets.reverse
  snippets.each do |snippet|
    value = value.gsub(snippet.second, snippet.first)
  end

  puts "# In #{lang1.upcase}: #{value}"
  new_val = [(print "# In #{lang2.upcase}: "), Readline.readline()][1]
  new_val = (new_s + '---' + new_val) unless new_val.blank?
  new_val
end

.breakoutObject



43
44
45
# File 'lib/lost_in_translation.rb', line 43

def self.breakout
  raise "Well in that case, forget it!"
end

.compareObject



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/tasks/compare.rb', line 4

def self.compare
  @master, @slave, paths = init

  prepare_for_edit(master: @master[:path], slave: @slave[:path])
  prepare_paths([paths[:master], paths[:slave]])

  master_file = YAML.load_file(paths[:master])
  slave_file = YAML.load_file(paths[:slave])

  count = diff(master_file[@master[:lang]], slave_file[@slave[:lang]], @master[:lang],
               @slave[:lang], [@slave[:lang]], [], mode: 'count')

  breakout unless ask_for_permission(@master, count, @slave)

  new_strings_array = diff(master_file[@master[:lang]], slave_file[@slave[:lang]], @master[:lang],
                           @slave[:lang], [@slave[:lang]], [], diff_count: count, mode: 'replace')

  new_strings_array.each do |string|
    result = string_to_hash(string)
    merge_hash(result, slave_file)
  end

  File.open(paths[:slave], 'w') { |file| file.write(slave_file.to_yaml(line_width: -1)) }
  postpare_paths([paths[:slave]])
  FileUtils.cp(paths[:slave], @slave[:path])

  reset_tmp_files

  log 'Done'
  log
end

.countObject



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/tasks/count.rb', line 4

def self.count
  @master, @slave, paths = init

  prepare_for_edit(master: @master[:path], slave: @slave[:path])
  prepare_paths([paths[:master], paths[:slave]])

  master_file = YAML.load_file(paths[:master])
  slave_file = YAML.load_file(paths[:slave])

  count = diff(master_file[@master[:lang]], slave_file[@slave[:lang]], @master[:lang], @slave[:lang],
               [@slave[:lang]], [], mode: 'count')

  count2 = diff(slave_file[@slave[:lang]], master_file[@master[:lang]], @slave[:lang], @master[:lang],
                [@master[:lang]], [], mode: 'count')


  reset_tmp_files
  log
  log 'Differences between Locales'
  log "#{@master[:filename]}.yml => #{@slave[:filename]}.yml = #{count}"
  log "#{@slave[:filename]}.yml => #{@master[:filename]}.yml = #{count2}"
  log 'Done'
  log
end

.define_snippetsObject



23
24
25
26
27
28
29
30
31
# File 'lib/lit/file_functions.rb', line 23

def self.define_snippets
  snippets = []
  snippets << ['<<', 'a_greater_than_sign']
  snippets << ['*', 'an_asterik_sign']
  snippets << ['!', 'a_bang_sign']
  snippets << ['%', 'a_percentage_sign']
  snippets << ['a_bang_sign \'', '\'a_bang_sign']
  snippets
end

.delete_missingObject



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/tasks/delete_missing.rb', line 4

def self.delete_missing
  tbd
  @master, @slave, paths = init

  prepare_for_edit(master: @master[:path], slave: @slave[:path])
  prepare_paths([paths[:master], paths[:slave]])

  master_file = YAML.load_file(paths[:master])
  slave_file = YAML.load_file(paths[:slave])

  breakout unless ask_for_permission(@master, count, @slave)

  new_strings_array = diff(master_file[@master[:lang]], slave_file[@slave[:lang]], @master[:lang],
                           @slave[:lang], [@slave[:lang]], [], mode: 'clean')

  master_file = {}
  new_strings_array.each do |string|
    string = string.split('---').map { |x| x == @slave[:lang] ? @master[:lang] : x }.join('---')
    result = string_to_hash(string)
    merge_hash(result, master_file)
  end

  File.open(@master[:path], 'w') { |file| file.write(master_file.to_yaml) }
  postpare_paths([@master[:path], @slave[:path]])
  reset_tmp_files
  log 'Done'
  log
end

.diff(root, compared, lang1, lang2, structure = [], new_array = [], options = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/lit/difference.rb', line 5

def self.diff(root, compared, lang1, lang2, structure = [], new_array = [], options = {})
  @slave_file = options[:slave_file] || ''
  @mode = options[:mode] || 'count' # replace, clean, count
  @diff_count = options[:diff_count] || 0
  @diff_counter = options[:diff_counter] || 0
  root.each_pair do |key, value|
    next_root     = root[key]
    next_compared = compared.nil? ? nil : compared[key]
    new_structure = structure.dup << key
    if value.is_a?(String) && (compared.nil? || compared[key].nil?)
      if value_missing(@slave_file, new_structure)
        @diff_counter += 1
        if @mode == 'replace'
          new_val = ask_for_translation(value, new_structure, lang1, lang2, @diff_count, @diff_counter)
          new_array << new_val unless new_val.blank?
        elsif @mode == 'clean'
          new_array << "#{new_structure.join('---')}---#{value}"
        end
      end
    end
    if next_root.is_a? Hash
      diff(next_root, next_compared, lang1, lang2, new_structure, new_array,
           diff_counter: @diff_counter, diff_count: @diff_count, mode: @mode, slave_file: @slave_file)
    end
  end
  @mode == 'count' ? @diff_counter : new_array
end

.fully_automaticObject



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/tasks/fully_automatic.rb', line 4

def self.fully_automatic
  tbd
  @master, @slave, paths = init

  prepare_for_edit(master: @master[:path], slave: @slave[:path])
  prepare_paths([paths[:master], paths[:slave]])

  master_file = YAML.load_file(paths[:master])
  slave_file = YAML.load_file(paths[:slave])

  count = diff(master_file[@master[:lang]], slave_file[@slave[:lang]], @master[:lang],
               @slave[:lang], [@slave[:lang]], [], mode: 'count')

  breakout unless ask_for_permission(@master, count, @slave)

  new_strings_array = diff(master_file[@master[:lang]], slave_file[@slave[:lang]], @master[:lang],
                           @slave[:lang], [@slave[:lang]], [], diff_count: count, mode: 'replace')

  new_strings_array.each do |string|
    result = string_to_hash(string)
    merge_hash(result, slave_file)
  end

  File.open(paths[:slave], 'w') { |file| file.write(slave_file.to_yaml(line_width: -1)) }
  postpare_paths([paths[:slave]])
  FileUtils.cp(paths[:slave], @slave[:path])

  reset_tmp_files
end

.get_locale(path) ⇒ Object



38
39
40
# File 'lib/lit/difference.rb', line 38

def self.get_locale(path)
  path.split('/').last.split('.').first unless path.empty?
end

.half_automaticObject



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/tasks/half_automatic.rb', line 4

def self.half_automatic
  tbd
  @master, @slave, paths = init

  prepare_for_edit(master: @master[:path], slave: @slave[:path])
  prepare_paths([paths[:master], paths[:slave]])

  master_file = YAML.load_file(paths[:master])
  slave_file = YAML.load_file(paths[:slave])

  count = diff(master_file[@master[:lang]], slave_file[@slave[:lang]], @master[:lang],
               @slave[:lang], [@slave[:lang]], [], mode: 'count')

  breakout unless ask_for_permission(@master, count, @slave)

  new_strings_array = diff(master_file[@master[:lang]], slave_file[@slave[:lang]], @master[:lang],
                           @slave[:lang], [@slave[:lang]], [], diff_count: count, mode: 'replace')

  new_strings_array.each do |string|
    result = string_to_hash(string)
    merge_hash(result, slave_file)
  end

  File.open(paths[:slave], 'w') { |file| file.write(slave_file.to_yaml(line_width: -1)) }
  postpare_paths([paths[:slave]])
  FileUtils.cp(paths[:slave], @slave[:path])

  reset_tmp_files
end

.init(with_slave = true) ⇒ Object



32
33
34
35
36
37
38
39
40
41
# File 'lib/lost_in_translation.rb', line 32

def self.init(with_slave = true)
  system 'clear'
  log
  log 'What I18n-yaml files do you want to compare?'
  namespace = [(print "# Namespace? ('namespace' for 'namespace.en.yml'): "), Readline.readline()][1]
  master = ask_for_file(true, namespace) # lang path app_name
  slave = with_slave ? ask_for_file(false, namespace) : {}
  invalid_filepath if !File.exist?(master[:path]) && (!File.exist?(slave[:path]) && with_slave)
  [master, slave, tmp_paths]
end

.invalid_filepathObject



47
48
49
# File 'lib/lost_in_translation.rb', line 47

def self.invalid_filepath
  raise "One on the filepaths are invalid!"
end

.jokeObject



30
31
32
33
34
35
36
37
38
39
# File 'lib/tasks/start.rb', line 30

def self.joke
  system 'clear'
  log
  log 'A: Knock, Knock!'
  log 'B: Who is there?'
  log 'A: Ya.'
  log 'B: Ya who?'
  log 'A: Oh, I prefer google.'
  log
end

.list_filesObject



48
49
50
51
52
53
54
55
56
57
58
# File 'lib/tasks/start.rb', line 48

def self.list_files
  system 'clear'

  path = ask_for_locales_path
  files = Dir["#{path}/**/*.yml"]
  puts "No Files found in #{path}" if files.empty?
  files&.sort&.each do |file|
    puts file.split('/').last
  end
  start
end

.log(text = '') ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
# File 'lib/lit/user_interface.rb', line 94

def self.log(text = '')
  max_length = 80
  outside = 4
  puts '#' * max_length if text.blank?
  arr = text.scan(/.{1,#{max_length - outside}}/)
  arr.each do |str|
    fill_length = max_length - str.length - outside
    fill = ' ' * fill_length
    puts '# ' + str + fill + ' #'
  end
end

.merge_hash(merge_from, merge_to) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
# File 'lib/lit/hash.rb', line 12

def self.merge_hash(merge_from, merge_to)
  return if merge_from.is_a?(String) || merge_to.is_a?(String)
  merged_hash = merge_to
  first_key = merge_from.keys.first
  merged_hash[first_key] = if merge_to.key?(first_key)
                             merge_hash(merge_from[first_key], merge_to[first_key])
                           else
                             merge_from[first_key]
                           end
  merged_hash
end

.postpare_paths(paths = []) ⇒ Object



17
18
19
20
21
# File 'lib/lit/file_functions.rb', line 17

def self.postpare_paths(paths = [])
  paths.each do |p|
    prepare_yaml(p, true)
  end
end

.prepare_for_edit(options = {}) ⇒ Object



5
6
7
8
9
# File 'lib/lit/file_functions.rb', line 5

def self.prepare_for_edit(options = {})
  paths = tmp_paths
  FileUtils.cp(options[:master], paths[:master]) if options[:master]
  FileUtils.cp(options[:slave], paths[:slave]) if options[:slave]
end

.prepare_paths(paths = []) ⇒ Object



11
12
13
14
15
# File 'lib/lit/file_functions.rb', line 11

def self.prepare_paths(paths = [])
  paths.each do |p|
    prepare_yaml(p, false)
  end
end

.quitObject



41
42
43
44
45
46
# File 'lib/tasks/start.rb', line 41

def self.quit
  system 'clear'
  log
  log 'Thank you and goodbye!'
  log
end

.recentObject



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/tasks/recent.rb', line 4

def self.recent
  @master, @slave, paths = init

  FileUtils.cp(@master[:path], paths[:copy])
  `git checkout "#{@master[:path]}"`

  prepare_for_edit(master: @master[:path], slave: @slave[:path])
  FileUtils.cp(paths[:copy], @master[:path])

  prepare_paths([paths[:master], paths[:slave], paths[:copy]])

  master_file = YAML.load_file(paths[:master])
  master_copy_file = YAML.load_file(paths[:copy])
  slave_file = YAML.load_file(paths[:slave])

  count = diff(master_copy_file[@master[:lang]], master_file[@master[:lang]], @master[:lang],
               @slave[:lang], [@slave[:lang]], [], mode: 'count', slave_file: slave_file)

  breakout unless ask_for_permission(@master, count, @slave)

  new_strings_array = diff(master_copy_file[@master[:lang]], master_file[@master[:lang]], @master[:lang],
                           @slave[:lang], [@slave[:lang]], [], mode: 'replace', diff_counter: 0, diff_count: count,
                           slave_file: slave_file)

  new_strings_array.each do |string|
    result = string_to_hash(string)
    merge_hash(result, slave_file)
  end

  File.open(paths[:slave], 'w') { |file| file.write(slave_file.to_yaml(line_width: -1)) }
  postpare_paths([paths[:slave]])
  FileUtils.cp(paths[:slave], @slave[:path])

  reset_tmp_files
  log 'Done'
  log
end

.reset_tmp_filesObject



33
34
35
36
37
38
# File 'lib/lit/file_functions.rb', line 33

def self.reset_tmp_files
  paths = tmp_paths
  paths.each_value do |path|
    File.open(path, 'w') { |file| file.write('') }
  end
end

.rootObject



20
21
22
# File 'lib/lost_in_translation.rb', line 20

def self.root
  File.dirname __dir__
end

.sort_fileObject



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/tasks/sort_file.rb', line 4

def self.sort_file
  @master, @slave, paths = init(false)

  prepare_for_edit(master: @master[:path], slave: @slave[:path])
  prepare_paths([paths[:master]])

  master_file = YAML.load_file(paths[:master])

  if ask_for_sorting(@master[:lang], @master[:app_name])
    master_file = sort_hash(master_file)
    File.open(paths[:master], 'w') { |file| file.write(master_file.to_yaml(line_width: -1)) }
  end

  postpare_paths([paths[:master]])

  FileUtils.cp(paths[:master], @master[:path])

  reset_tmp_files
  log 'Done'
  log
end

.sort_hash(object) ⇒ Object



24
25
26
27
28
29
30
# File 'lib/lit/hash.rb', line 24

def self.sort_hash(object)
  return object unless object.is_a?(Hash)
  hash = {}
  object.each { |k, v| hash[k] = sort_hash(v) }
  sorted = hash.sort { |a, b| a[0].to_s <=> b[0].to_s }
  hash.class[sorted]
end

.split_fileObject



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/tasks/split_file.rb', line 4

def self.split_file
  @master, @slave, paths = init(false)

  prepare_for_edit(master: @master[:path])
  prepare_paths([paths[:master]])

  master_file = YAML.load_file(paths[:master])[@master[:lang]]

  count = master_file.select { |_k, v| v.is_a?(Hash) }.size
  new_hash = {}

  if ask_for_split(@master[:lang], count)
    master_file.each_pair do |key, value|
      next unless value.is_a?(Hash)
      new_hash[@master[:lang]] = { key => value }
      File.open(paths[:slave], 'w') { |file| file.write(new_hash.to_yaml(line_width: -1)) }
      postpare_paths([paths[:slave]])
      root_path = @master[:path].split('/').reverse.drop(1).reverse.join('/')
      filename = @master[:path].split('/').last
      FileUtils.cp(paths[:slave], "#{root_path}/#{key}.#{filename}")
      master_file.delete(key)
    end

    new_hash[@master[:lang]] = master_file
    File.open(paths[:master], 'w') { |file| file.write(new_hash.to_yaml(line_width: -1)) }
    postpare_paths([paths[:master]])
    FileUtils.cp(paths[:master], @master[:path])
  end

  reset_tmp_files
  log 'Done'
  log
end

.startObject



4
5
6
7
8
9
10
11
12
13
14
15
16
# File 'lib/tasks/start.rb', line 4

def self.start
  tasks = [
    { text: 'Compare & Translate two I18n-Locale-Files', method: :start_compare },
    { text: 'Count Differences of 2 I18n-Locale-Files', method: :count },
    { text: 'Sort an I18n-Locale-File Alphabetically & Recursive (ASC)', method: :sort_file },
    { text: 'Split an I18n-Locale-File into multiple namespaced Files (1. Level)', method: :split_file },
    { text: 'Show a list of available I18n-Locale-Files', method: :list_files },
    { text: 'Tell me joke', method: :joke },
    { text: 'Quit', method: :quit }
  ]
  task = ask_for_task(tasks)
  LostInTranslation.send(task[:method])
end

.start_compareObject



18
19
20
21
22
23
24
25
26
27
28
# File 'lib/tasks/start.rb', line 18

def self.start_compare
  tasks = [
    { text: 'Compare everything', method: :compare },
    { text: 'Just compare the recent changes (since last git commit)', method: :recent },
    { text: 'Automatic translation via API', method: :fully_automatic },
    { text: 'Translation suggentions from API', method: :half_automatic },
    { text: 'Compare and delete the differences', method: :delete_missing },
  ]
  task = ask_for_task(tasks)
  LostInTranslation.send(task[:method])
end

.string_to_hash(string) ⇒ Object



5
6
7
8
9
10
# File 'lib/lit/hash.rb', line 5

def self.string_to_hash(string)
  array = string.split('---')
  value = array.pop
  arr = array.reverse
  arr[1..-1].inject(arr[0] => value) { |memo, i| { i => memo } }
end

.tbdObject



51
52
53
# File 'lib/lost_in_translation.rb', line 51

def self.tbd
  raise "This feature is not yet implemented! Please take another!"
end

.tmp_pathsObject



24
25
26
27
28
29
30
# File 'lib/lost_in_translation.rb', line 24

def self.tmp_paths
  tmp_paths = {}
  tmp_paths[:copy] = "#{root}/tmp/tmp_master_copy.yml"
  tmp_paths[:master] = "#{root}/tmp/tmp_master.yml"
  tmp_paths[:slave] = "#{root}/tmp/tmp_slave.yml"
  tmp_paths
end

.value_missing(slave_file, structure) ⇒ Object



33
34
35
36
# File 'lib/lit/difference.rb', line 33

def self.value_missing(slave_file, structure)
  return true if slave_file.blank?
  slave_file.dig(*structure).blank?
end