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 +7 -0
- data/bin/rubustrings +12 -0
- data/lib/rubustrings/action.rb +185 -0
- data/lib/rubustrings.rb +11 -0
- metadata +61 -0
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,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
|
data/lib/rubustrings.rb
ADDED
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: []
|