rubustrings_fr24 0.0.6

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 90eedc49c30c5bb68b98ac738d378a9f94713fba4983049a313a88007de94c9a
4
+ data.tar.gz: fb26568937c26bd2e88d49f4c475f59a8d6ef1505ab993bbc48cf1347f3f077a
5
+ SHA512:
6
+ metadata.gz: 003263da105280fd00c15cebceb9278631db61843277e755554d588712e790b272b0ab870865313e15d438f1af161dd7c3559848285eaa0bb8ae1feaf84154f4
7
+ data.tar.gz: 234ea4fff83ebedfbea53fa740e84187ef0572456e9bff75cd3380e14d63499d743959b2fb017d50f85ea81fb6fec9da526e4cb70a50b6a3dc0a287fead1d887
data/bin/rubustrings ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubustrings'
4
+
5
+ filename = ARGV[0]
6
+ parameter = ARGV.last
7
+
8
+ if Rubustrings.validate([filename], parameter == "--onlyformat")
9
+ exit 0
10
+ else
11
+ exit 1
12
+ end
@@ -0,0 +1,185 @@
1
+
2
+ require 'colored'
3
+
4
+ module Rubustrings
5
+ class Action
6
+
7
+ def validate(filenames, only_format)
8
+ abort 'No strings file provided' unless filenames
9
+ filenames.each do |file_name|
10
+ log_output(:info, '', 0, "Processing file: \"#{file_name}\"\n")
11
+ result = validate_localizable_string_file file_name, only_format
12
+
13
+ if result
14
+ log_output(:result_success, file_name, 0, 'Strings file validated succesfully')
15
+ return true
16
+ else
17
+ log_output(:result_error, file_name, 0, 'Some errors detected')
18
+ return false
19
+ end
20
+ end
21
+ end
22
+
23
+ # Possible levels are :error, :result_error, :warning, :result_success, :info
24
+ def log_output(level, file_name, line_number, message)
25
+ message = message.chomp
26
+ case level
27
+ when :error
28
+ puts "#{file_name}:#{line_number}: error: #{message}"
29
+ when :warning
30
+ puts "#{file_name}:#{line_number}: warning: #{message}"
31
+ when :result_success
32
+ puts "\nResult: ✓ #{message}".bold.green
33
+ when :result_error
34
+ puts "\nResult: ✘ #{message}".bold.red
35
+ when :info
36
+ puts message.to_s.blue
37
+ end
38
+ end
39
+
40
+ def validate_localizable_string_file(file_name, only_format)
41
+ file_data = open_and_read_file file_name
42
+ cleaned_strings = remove_comments_and_empty_lines file_data
43
+
44
+ return log_output(:error, file_name, 0, "no translations found in file: #{file_name}") if cleaned_strings.empty?
45
+
46
+ validation_result = true
47
+ cleaned_strings.each_line do |line|
48
+ validation_result &= validate_translation_line file_name, line, only_format
49
+ end
50
+ validation_result
51
+ end
52
+
53
+ def add_line_numbers(file_data)
54
+ line_num = 0
55
+ result = ''
56
+ file_data.each_line do |line|
57
+ line_num += 1
58
+ result += "#{line_num} #{line}"
59
+ end
60
+ result
61
+ end
62
+
63
+ def open_and_read_file(file_name)
64
+ return nil unless File.exist?(file_name)
65
+
66
+ begin
67
+ File.open(file_name, 'rb:utf-16:utf-8').read
68
+ rescue
69
+ File.open(file_name, 'rb:utf-8:utf-8').read
70
+ end
71
+ end
72
+
73
+ def remove_comments_and_empty_lines(file_data)
74
+ multiline_comments_regex = %r{/\*.*?\*/}m
75
+ empty_lines_regex = /^[1-9]\d* $\n/
76
+
77
+ file_data_with_lines = add_line_numbers file_data
78
+ file_data_with_lines.gsub(multiline_comments_regex, '').gsub(empty_lines_regex, '') if file_data
79
+ end
80
+
81
+ def validate_format(line)
82
+ localizable_strings_format_regex = /^\"((?:\\.|[^\\"])*?)\"\s=\s\"((?:\\.|[^\\"])*?)\";/
83
+ localizable_strings_format_regex.match line
84
+ end
85
+
86
+ def validate_special_characters(translation_key, translation_value)
87
+ # Remove %% to avoid ambiguous scenarios with adjacent formats like "%s%%s"
88
+ translation_key = translation_key.gsub("%%", " ")
89
+ translation_value = translation_value.gsub("%%", " ")
90
+
91
+ variables_regex = /\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?(hh|ll|[hlLzjt])?([b-fiosuxX@])/
92
+ position_index = 0
93
+ length_index = 7
94
+ format_index = 8
95
+
96
+ # sort by according to parameter field, if specified
97
+ key_variables = translation_key.scan(variables_regex).stable_sort_by{ |r| r[position_index].to_i }
98
+ value_variables = translation_value.scan(variables_regex).stable_sort_by{ |r| r[position_index].to_i }
99
+
100
+ return true unless key_variables.any? || value_variables.any?
101
+ return false unless key_variables.count == value_variables.count
102
+
103
+ # we should not have any parameter fields in the keys
104
+ return false unless key_variables.last[position_index] == nil
105
+
106
+ # if we do have parameter fields, we need to include all of them
107
+ if value_variables[0][position_index] != nil
108
+ return false unless value_variables.last[position_index] != nil
109
+ validation_result = true
110
+ value_variables.each_with_index { |v, idx|
111
+ if v[position_index].to_i != idx + 1
112
+ validation_result = false
113
+ end
114
+ }
115
+ return false unless validation_result
116
+ else
117
+ return false unless value_variables.last[position_index] == nil
118
+ end
119
+
120
+ # remove parameter field
121
+ key_variables = key_variables.map{ |v| [v[length_index], v[format_index]] }
122
+ value_variables = value_variables.map{ |v| [v[length_index], v[format_index]] }
123
+ key_variables == value_variables
124
+ end
125
+
126
+ def validate_special_beginning(translation_key, translation_value)
127
+ beginning_regex = /^(?:\s|\n|\r)/
128
+
129
+ return true unless translation_key =~ beginning_regex || translation_value =~ beginning_regex
130
+ translation_key.chars.first == translation_value.chars.first
131
+ end
132
+
133
+ def validate_special_ending(translation_key, translation_value)
134
+ ending_regex = /(?:\s|\n|\r)$/
135
+
136
+ return true unless translation_key =~ ending_regex || translation_value =~ ending_regex
137
+ translation_key.chars.last == translation_value.chars.last
138
+ end
139
+
140
+ def validate_translation_line(file_name, line, only_format)
141
+ line_number = 0
142
+
143
+ empty_regex = /^\d+\s*\n?$/
144
+ return true if empty_regex.match line
145
+
146
+ numbered_line_regex = /^(\d+) (.*)/
147
+ numbered_line_match = numbered_line_regex.match line
148
+
149
+ return log_output(:error, file_name, line_number, 'internal error') unless numbered_line_match
150
+ line_number = numbered_line_match[1]
151
+ line = numbered_line_match[2]
152
+
153
+ match = validate_format line
154
+ return log_output(:error, file_name, line_number, "invalid format: #{line}") unless match
155
+
156
+ return true if only_format
157
+
158
+ match_key = match[1]
159
+ match_value = match[2]
160
+
161
+ log_output(:warning, file_name, line_number, "no translated string: #{line}") if match_value.empty?
162
+
163
+ validation_special_characters = validate_special_characters match_key, match_value
164
+ log_output(:error, file_name, line_number, "variables mismatch: #{line}") unless validation_special_characters
165
+
166
+ validation_special_beginning = validate_special_beginning match_key, match_value
167
+ log_output(:error, file_name, line_number, "beginning mismatch: #{line}") unless validation_special_beginning
168
+
169
+ validation_special_ending = validate_special_ending match_key, match_value
170
+ log_output(:error, file_name, line_number, "ending mismatch: #{line}") unless validation_special_ending
171
+
172
+ validation_special_characters && validation_special_beginning && validation_special_ending
173
+ end
174
+ end
175
+ end
176
+
177
+ module Enumerable
178
+ def stable_sort
179
+ sort_by.with_index { |x, idx| [x, idx] }
180
+ end
181
+
182
+ def stable_sort_by
183
+ sort_by.with_index { |x, idx| [yield(x), idx] }
184
+ end
185
+ end
@@ -0,0 +1,11 @@
1
+
2
+ require 'rubustrings/action'
3
+
4
+ # The main Rubustrings driver
5
+ module Rubustrings
6
+ class << self
7
+ def validate(filenames, only_format = false)
8
+ Action.new.validate(filenames, only_format)
9
+ end
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubustrings_fr24
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.6
5
+ platform: ruby
6
+ authors:
7
+ - David Cordero
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-10-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: colored
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Check the format and consistency of the Localizable.strings files of
28
+ iOS Apps with multi-language support
29
+ email: dcorderoramirez@gmail.com
30
+ executables:
31
+ - rubustrings
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - bin/rubustrings
36
+ - lib/rubustrings.rb
37
+ - lib/rubustrings/action.rb
38
+ homepage: https://github.com/AndreyAnt/Rubustrings
39
+ licenses:
40
+ - MIT
41
+ metadata: {}
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubygems_version: 3.0.3.1
58
+ signing_key:
59
+ specification_version: 4
60
+ summary: Check Localizable.strings files of iOS Apps
61
+ test_files: []