vocab 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/CHANGELOG.md +4 -0
- data/MIT-LICENSE +7 -0
- data/README.md +66 -14
- data/bin/vocab +1 -1
- data/lib/vocab/application.rb +7 -5
- data/lib/vocab/extractor/android.rb +31 -14
- data/lib/vocab/extractor/base.rb +27 -11
- data/lib/vocab/extractor/rails.rb +16 -6
- data/lib/vocab/merger/android.rb +48 -15
- data/lib/vocab/merger/base.rb +0 -6
- data/lib/vocab/translator/android.rb +67 -9
- data/lib/vocab/validator/android.rb +2 -2
- data/lib/vocab/validator/base.rb +7 -1
- data/lib/vocab/validator/rails.rb +1 -1
- data/lib/vocab/version.rb +1 -1
- data/spec/data/android/locales/values/strings.xml +11 -0
- data/spec/data/android/locales/values-es/strings.xml +5 -0
- data/spec/data/android/translations/values-es/es-string-file.xml +11 -0
- data/spec/data/android/write.xml +1 -0
- data/spec/data/android/write_plurals.xml +14 -0
- data/spec/data/rails/locales/en.yml +4 -0
- data/spec/extractor/android_spec.rb +47 -26
- data/spec/extractor/base_spec.rb +25 -8
- data/spec/extractor/rails_spec.rb +23 -20
- data/spec/merger/android_spec.rb +78 -25
- data/spec/merger/base_spec.rb +0 -1
- data/spec/merger/rails_spec.rb +1 -2
- data/spec/spec_helper.rb +8 -5
- data/spec/support/matchers.rb +25 -0
- data/spec/translator/android_spec.rb +45 -2
- data/spec/translator/rails_spec.rb +28 -24
- data/spec/validator/android_spec.rb +2 -2
- data/spec/validator/base_spec.rb +23 -0
- data/spec/validator/rails_spec.rb +6 -6
- data/vocab.gemspec +1 -0
- metadata +23 -8
data/.gitignore
CHANGED
data/CHANGELOG.md
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2012 Inquisitive Minds, Inc
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Command line tool to automate the manipulation of i18n string files in Rails and Android.
|
4
4
|
|
5
|
-
Features include:
|
5
|
+
## Features include:
|
6
6
|
|
7
7
|
* Generate a list all English translations that have been updated or added since the last translation
|
8
8
|
* Integrate a list of newly translated strings into the right place in the project translation file(s)
|
@@ -11,7 +11,7 @@ Features include:
|
|
11
11
|
# Requirements
|
12
12
|
|
13
13
|
* Must be used in context of git controlled project
|
14
|
-
* Assumes that android string files are called strings.xml
|
14
|
+
* Assumes that android string files are called strings.xml under res/values-xx
|
15
15
|
|
16
16
|
# Installation
|
17
17
|
|
@@ -23,36 +23,88 @@ Set the current git commit to be the starting point for the next translation dif
|
|
23
23
|
|
24
24
|
vocab init
|
25
25
|
|
26
|
+
You may need to change the SHA hash in .vocab to match the commit of the last translation
|
27
|
+
|
26
28
|
# Usage
|
27
29
|
|
28
|
-
##
|
30
|
+
## Android
|
31
|
+
|
32
|
+
### Extract Changed and Updated Strings For Translation
|
29
33
|
|
34
|
+
cd APP_ROOT
|
30
35
|
vocab extract android
|
31
36
|
|
32
|
-
|
37
|
+
This will create two files in the current directory:
|
33
38
|
|
34
|
-
|
39
|
+
`strings.diff.xml` Contains all the keys that need to be updated for existing languages
|
40
|
+
`strings.full.xml` Contains all keys for a full translation
|
35
41
|
|
36
|
-
|
37
|
-
|
42
|
+
Send these files off to the appropriate translator. When they files come back,
|
43
|
+
put the partial language translations in `tmp/translations`. For example:
|
38
44
|
|
39
|
-
|
45
|
+
tmp/translations/values-zn/strings.xml
|
46
|
+
tmp/translations/values-es/es-strings-7.xml
|
40
47
|
|
41
|
-
|
48
|
+
The file must be in the properly named folder and end with xml.
|
42
49
|
|
43
|
-
|
50
|
+
For new language files, just put them directly under the `res` directory.
|
44
51
|
|
45
|
-
|
52
|
+
### Merging new translations into project string files
|
46
53
|
|
47
|
-
|
54
|
+
Integrate the translations with the following command:
|
48
55
|
|
56
|
+
cd APP_ROOT
|
57
|
+
vocab merge android
|
58
|
+
|
59
|
+
### Validating that all translations have the same keys
|
60
|
+
|
61
|
+
cd APP_ROOT
|
49
62
|
vocab validate android
|
50
63
|
|
51
|
-
|
64
|
+
## Rails
|
65
|
+
|
66
|
+
### Extract Changed and Updated Strings For Translation
|
67
|
+
|
68
|
+
cd RAILS_ROOT
|
69
|
+
vocab extract rails
|
70
|
+
|
71
|
+
This will create two files in the current directory:
|
52
72
|
|
73
|
+
`en.diff.yml` Contains all the keys that need to be updated for existing languages
|
74
|
+
`en.full.yml` Contains all keys for a full translation
|
75
|
+
|
76
|
+
Send these files off to the appropriate translator. When they files come back,
|
77
|
+
put them in `tmp/translations`. For example:
|
78
|
+
|
79
|
+
tmp/translations/zn.yml
|
80
|
+
tmp/translations/es.yml
|
81
|
+
|
82
|
+
### Merging new translations into project string files
|
83
|
+
|
84
|
+
Integrate the translations with the following command:
|
85
|
+
|
86
|
+
cd RAILS_ROOT
|
87
|
+
vocab merge rails
|
88
|
+
|
89
|
+
Keys will be put in the correct nested yml file. You can put whole or partial translations
|
90
|
+
in tmp/translations.
|
91
|
+
|
92
|
+
### Validating that all translations have the same keys
|
93
|
+
|
94
|
+
cd RAILS_ROOT
|
53
95
|
vocab validate rails
|
54
96
|
|
97
|
+
# Other details
|
98
|
+
|
99
|
+
Keys starting with 'debug_' are ignored for both Rails and Android string files. Prepend development-only strings
|
100
|
+
with 'debug_' to avoid these keys being sent to translators.
|
101
|
+
|
55
102
|
# TODO
|
56
103
|
|
57
104
|
* Add .processed to each tmp/translation after success
|
58
|
-
*
|
105
|
+
* Handle full translations under tmp/translations when no existing translation exists in android
|
106
|
+
* Add iOS support
|
107
|
+
* Add AIR support
|
108
|
+
* Add Chrome support
|
109
|
+
* Add Firefox support
|
110
|
+
|
data/bin/vocab
CHANGED
data/lib/vocab/application.rb
CHANGED
@@ -3,10 +3,10 @@ require 'ostruct'
|
|
3
3
|
|
4
4
|
module Vocab
|
5
5
|
class Application
|
6
|
-
|
6
|
+
|
7
7
|
class << self
|
8
8
|
def run
|
9
|
-
handle_command
|
9
|
+
return handle_command
|
10
10
|
end
|
11
11
|
|
12
12
|
##############################
|
@@ -14,6 +14,7 @@ module Vocab
|
|
14
14
|
##############################
|
15
15
|
|
16
16
|
def handle_command
|
17
|
+
success = true
|
17
18
|
options = OpenStruct.new
|
18
19
|
parser = OptionParser.new
|
19
20
|
|
@@ -45,14 +46,15 @@ module Vocab
|
|
45
46
|
elsif( options.command == 'merge' && options.platform == 'android' )
|
46
47
|
Merger::Android.new.merge
|
47
48
|
elsif( options.command == 'validate' && options.platform == 'android' )
|
48
|
-
Validator::Android.new.validate
|
49
|
+
success = Validator::Android.new.validate
|
49
50
|
elsif( options.command == 'validate' && options.platform == 'rails' )
|
50
|
-
Validator::Rails.new.validate
|
51
|
+
success = Validator::Rails.new.validate
|
51
52
|
else
|
52
53
|
puts parser.help
|
53
54
|
end
|
55
|
+
|
56
|
+
return success
|
54
57
|
end
|
55
|
-
|
56
58
|
end
|
57
59
|
end
|
58
60
|
end
|
@@ -6,30 +6,38 @@ module Vocab
|
|
6
6
|
DIFF = 'strings.diff.xml'
|
7
7
|
FULL = 'strings.full.xml'
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
STRINGS_XML = 'res/values/strings.xml'
|
10
|
+
|
11
|
+
def current_strings( path = nil )
|
12
|
+
path ||= "#{Vocab.root}/#{STRINGS_XML}"
|
11
13
|
return Vocab::Translator::Android.hash_from_xml( path )
|
12
14
|
end
|
13
15
|
|
14
|
-
def
|
15
|
-
path ||=
|
16
|
-
|
17
|
-
xml = previous_file( path, sha )
|
18
|
-
|
19
|
-
tmpfile = "#{Vocab.root}/tmp/last_translation/#{File.basename(path)}"
|
20
|
-
FileUtils.mkdir_p( File.dirname( tmpfile ) )
|
21
|
-
File.open( tmpfile, 'w' ) { |f| f.write( xml ) }
|
16
|
+
def previous_strings( path = nil )
|
17
|
+
path ||= STRINGS_XML
|
18
|
+
tmpfile = tmp_file( path )
|
22
19
|
return Vocab::Translator::Android.hash_from_xml( tmpfile )
|
23
20
|
end
|
24
21
|
|
25
|
-
def
|
22
|
+
def current_plurals( path = nil )
|
23
|
+
path ||= "#{Vocab.root}/#{STRINGS_XML}"
|
24
|
+
return Vocab::Translator::Android.plurals_from_xml( path )
|
25
|
+
end
|
26
|
+
|
27
|
+
def previous_plurals( path = nil )
|
28
|
+
path ||= STRINGS_XML
|
29
|
+
tmpfile = tmp_file( path )
|
30
|
+
return Vocab::Translator::Android.plurals_from_xml( tmpfile )
|
31
|
+
end
|
32
|
+
|
33
|
+
def write_diff( strings, plurals, path = nil )
|
26
34
|
path ||= "#{Vocab.root}/#{DIFF}"
|
27
|
-
Vocab::Translator::Android.write(
|
35
|
+
Vocab::Translator::Android.write( strings, plurals, path )
|
28
36
|
end
|
29
37
|
|
30
|
-
def write_full(
|
38
|
+
def write_full( strings, plurals, path = nil )
|
31
39
|
path ||= "#{Vocab.root}/#{FULL}"
|
32
|
-
Vocab::Translator::Android.write(
|
40
|
+
Vocab::Translator::Android.write( strings, plurals, path )
|
33
41
|
end
|
34
42
|
|
35
43
|
def examples( locales_dir = nil )
|
@@ -50,6 +58,15 @@ tmp/translations/values-zh-rCN/strings.xml
|
|
50
58
|
super( values )
|
51
59
|
end
|
52
60
|
|
61
|
+
def tmp_file( path )
|
62
|
+
sha = Vocab.settings.last_translation
|
63
|
+
xml = previous_file( path, sha )
|
64
|
+
tmpfile = "#{Vocab.root}/tmp/last_translation/#{File.basename(path)}"
|
65
|
+
FileUtils.mkdir_p( File.dirname( tmpfile ) )
|
66
|
+
File.open( tmpfile, 'w' ) { |f| f.write( xml ) }
|
67
|
+
return tmpfile
|
68
|
+
end
|
69
|
+
|
53
70
|
end
|
54
71
|
end
|
55
72
|
end
|
data/lib/vocab/extractor/base.rb
CHANGED
@@ -3,11 +3,14 @@ module Vocab
|
|
3
3
|
class Base
|
4
4
|
class << self
|
5
5
|
def extract( diff_path = nil, full_path = nil )
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
all_strings = current_strings
|
7
|
+
all_plurals = current_plurals
|
8
|
+
|
9
|
+
updated_strings = diff( previous_strings, all_strings )
|
10
|
+
updated_plurals = diff( previous_plurals, all_plurals )
|
11
|
+
write_diff( updated_strings, updated_plurals, diff_path )
|
12
|
+
write_full( all_strings, all_plurals, full_path )
|
13
|
+
update_settings
|
11
14
|
mkdir_examples
|
12
15
|
print_instructions
|
13
16
|
end
|
@@ -26,19 +29,32 @@ module Vocab
|
|
26
29
|
return diff
|
27
30
|
end
|
28
31
|
|
29
|
-
def
|
30
|
-
|
32
|
+
def update_settings
|
33
|
+
sha = Vocab.settings.update_translation
|
34
|
+
Vocab.ui.say( "Updated current translation to #{sha}" )
|
31
35
|
end
|
32
36
|
|
33
|
-
def
|
34
|
-
raise "
|
37
|
+
def previous_strings
|
38
|
+
raise "previous_strings not implemented"
|
35
39
|
end
|
36
40
|
|
37
|
-
def
|
41
|
+
def current_strings
|
42
|
+
raise "current_strings not implemented"
|
43
|
+
end
|
44
|
+
|
45
|
+
def current_plurals
|
46
|
+
raise "current_plurals not implemented"
|
47
|
+
end
|
48
|
+
|
49
|
+
def previous_plurals
|
50
|
+
raise "previous_plurals not implemented"
|
51
|
+
end
|
52
|
+
|
53
|
+
def write_diff( diff, plurals, path )
|
38
54
|
raise "write_diff not implemented"
|
39
55
|
end
|
40
56
|
|
41
|
-
def write_full( diff, path )
|
57
|
+
def write_full( diff, plurals, path )
|
42
58
|
raise "write_full not implemented"
|
43
59
|
end
|
44
60
|
|
@@ -5,14 +5,14 @@ module Vocab
|
|
5
5
|
FULL = 'en.full.yml'
|
6
6
|
|
7
7
|
class << self
|
8
|
-
def write_diff(
|
8
|
+
def write_diff( strings, plurals, path )
|
9
9
|
path ||= "#{Vocab.root}/#{DIFF}"
|
10
|
-
write(
|
10
|
+
write( strings, path )
|
11
11
|
end
|
12
12
|
|
13
|
-
def write_full(
|
13
|
+
def write_full( strings, plurals, path )
|
14
14
|
path ||= "#{Vocab.root}/#{FULL}"
|
15
|
-
write(
|
15
|
+
write( strings, path )
|
16
16
|
end
|
17
17
|
|
18
18
|
def write( translations, path )
|
@@ -21,7 +21,7 @@ module Vocab
|
|
21
21
|
Vocab.ui.say( "Extracted to #{path}" )
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
24
|
+
def previous_strings( locales_root = nil )
|
25
25
|
locales_root ||= "config/locales"
|
26
26
|
tmpdir = "#{Vocab.root}/tmp/last_translation"
|
27
27
|
FileUtils.rm_rf( "#{tmpdir}/*" )
|
@@ -41,11 +41,21 @@ module Vocab
|
|
41
41
|
return translations( tmpdir )
|
42
42
|
end
|
43
43
|
|
44
|
-
def
|
44
|
+
def current_strings( locales_root = nil )
|
45
45
|
locales_root ||= "#{Vocab.root}/config/locales"
|
46
46
|
return translations( locales_root )
|
47
47
|
end
|
48
48
|
|
49
|
+
# Treat this as a no-op because plurals handled like normal strings
|
50
|
+
def previous_plurals
|
51
|
+
return {}
|
52
|
+
end
|
53
|
+
|
54
|
+
# Treat this as a no-op because plurals handled like normal strings
|
55
|
+
def current_plurals
|
56
|
+
return {}
|
57
|
+
end
|
58
|
+
|
49
59
|
def translations( dir )
|
50
60
|
translator = Vocab::Translator::Rails.new
|
51
61
|
translator.load_dir( dir )
|
data/lib/vocab/merger/android.rb
CHANGED
@@ -8,10 +8,26 @@ module Vocab
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def merge_file( path )
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
strings = strings( path )
|
12
|
+
plurals = plurals( path )
|
13
|
+
Vocab::Translator::Android.write( strings, plurals, path )
|
14
|
+
end
|
15
|
+
|
16
|
+
def strings( path )
|
17
|
+
keys = string_keys
|
18
|
+
current = current_strings_for_locale( path )
|
19
|
+
updates = update_strings_for_locale( path )
|
20
|
+
return translation_hash( keys, current, updates, path )
|
21
|
+
end
|
14
22
|
|
23
|
+
def plurals( path )
|
24
|
+
keys = plural_keys
|
25
|
+
current = current_plurals_for_locale( path )
|
26
|
+
updates = update_plurals_for_locale( path )
|
27
|
+
return translation_hash( keys, current, updates, path )
|
28
|
+
end
|
29
|
+
|
30
|
+
def translation_hash( keys, current, updates, path )
|
15
31
|
translation = {}
|
16
32
|
keys.each do |key|
|
17
33
|
next if Vocab::Translator::Base.ignore_key?( key )
|
@@ -24,24 +40,33 @@ module Vocab
|
|
24
40
|
end
|
25
41
|
end
|
26
42
|
|
27
|
-
|
43
|
+
return translation
|
28
44
|
end
|
29
45
|
|
30
|
-
def
|
31
|
-
return Vocab::Translator::Android.
|
46
|
+
def string_keys
|
47
|
+
return Vocab::Translator::Android.string_keys( @locales_dir )
|
32
48
|
end
|
33
49
|
|
34
|
-
def
|
35
|
-
Vocab::Translator::Android.
|
50
|
+
def plural_keys
|
51
|
+
return Vocab::Translator::Android.plural_keys( @locales_dir )
|
36
52
|
end
|
37
53
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
update =
|
44
|
-
Vocab::Translator::Android.hash_from_xml( update )
|
54
|
+
def current_strings_for_locale( path )
|
55
|
+
return Vocab::Translator::Android.hash_from_xml( path )
|
56
|
+
end
|
57
|
+
|
58
|
+
def update_strings_for_locale( path )
|
59
|
+
update = update_file_path( path )
|
60
|
+
return Vocab::Translator::Android.hash_from_xml( update )
|
61
|
+
end
|
62
|
+
|
63
|
+
def current_plurals_for_locale( path )
|
64
|
+
return Vocab::Translator::Android.plurals_from_xml( path )
|
65
|
+
end
|
66
|
+
|
67
|
+
def update_plurals_for_locale( path )
|
68
|
+
update = update_file_path( path )
|
69
|
+
return Vocab::Translator::Android.plurals_from_xml( update )
|
45
70
|
end
|
46
71
|
|
47
72
|
def translation_locales
|
@@ -54,6 +79,14 @@ module Vocab
|
|
54
79
|
end
|
55
80
|
end
|
56
81
|
|
82
|
+
def update_file_path( path )
|
83
|
+
name = path.gsub( "#{@locales_dir}/", '' )
|
84
|
+
dirname = File.dirname( name )
|
85
|
+
entries = Dir.glob( "#{updates_dir}/#{dirname}/*.xml" )
|
86
|
+
Vocab.ui.warn( "Multiple update files for #{path}: #{entries.join( ',' )}" ) if entries.size > 1
|
87
|
+
return entries.first
|
88
|
+
end
|
89
|
+
|
57
90
|
end
|
58
91
|
end
|
59
92
|
end
|
data/lib/vocab/merger/base.rb
CHANGED
@@ -4,17 +4,11 @@ module Vocab
|
|
4
4
|
|
5
5
|
attr_accessor :locales_dir, :updates_dir
|
6
6
|
|
7
|
-
def update_settings
|
8
|
-
sha = Vocab.settings.update_translation
|
9
|
-
Vocab.ui.say( "Updated current translation to #{sha}" )
|
10
|
-
end
|
11
|
-
|
12
7
|
def merge
|
13
8
|
files_to_merge.each do |file|
|
14
9
|
Vocab.ui.say( "Merging file: #{file}" )
|
15
10
|
merge_file( file )
|
16
11
|
end
|
17
|
-
update_settings
|
18
12
|
end
|
19
13
|
end
|
20
14
|
end
|
@@ -3,29 +3,77 @@ module Vocab
|
|
3
3
|
class Android < Base
|
4
4
|
|
5
5
|
def self.hash_from_xml( path )
|
6
|
-
|
7
|
-
doc = Nokogiri::HTML.fragment( xml ) { |config| config.noblanks }
|
6
|
+
doc = doc_from_xml( path )
|
8
7
|
children = doc.search( 'resources/string' )
|
9
8
|
hash = {}
|
10
|
-
children.each
|
9
|
+
children.each do |child|
|
10
|
+
text = child.text
|
11
|
+
# escape apostrophes for android resource loader
|
12
|
+
text = text.gsub( /([^\\])'/, %q[\1\\\'] )
|
13
|
+
hash[ child['name'] ] = text
|
14
|
+
end
|
11
15
|
return hash
|
12
16
|
end
|
13
17
|
|
14
|
-
|
18
|
+
# Extracts plural definitions from xml to a hash
|
19
|
+
#
|
20
|
+
# For example:
|
21
|
+
#
|
22
|
+
# <plurals name="user_count">
|
23
|
+
# <item quantity="one">1 user</item>
|
24
|
+
# <item quantity="many">%d users</item>
|
25
|
+
# </plurals>
|
26
|
+
#
|
27
|
+
# Is returned as:
|
28
|
+
#
|
29
|
+
# { "user_count" => { "one" => "1 user",
|
30
|
+
# "many" => "%d users" } }
|
31
|
+
def self.plurals_from_xml( path )
|
32
|
+
doc = doc_from_xml( path )
|
33
|
+
|
34
|
+
plurals = {}
|
35
|
+
doc.search( 'resources/plurals' ).each do |plural|
|
36
|
+
items = {}
|
37
|
+
plural.search( 'item' ).each do |item|
|
38
|
+
items[ item['quantity' ] ] = item.text
|
39
|
+
end
|
40
|
+
|
41
|
+
plurals[ plural['name'] ] = items
|
42
|
+
end
|
43
|
+
return plurals
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.write( strings, plurals, path )
|
15
47
|
builder = Nokogiri::XML::Builder.new do |xml|
|
16
|
-
xml.resources
|
17
|
-
|
48
|
+
xml.resources do
|
49
|
+
strings.sort.each do |key, value|
|
18
50
|
xml.string( value, :name => key )
|
19
51
|
end
|
20
|
-
|
52
|
+
|
53
|
+
plurals.keys.sort.each do |key|
|
54
|
+
xml.plurals( :name => key ) do
|
55
|
+
plurals[ key ].each do |quantity, value|
|
56
|
+
xml.item( value, :quantity => quantity )
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
21
61
|
end
|
22
62
|
File.open( path, 'w' ) { |f| f.write( builder.to_xml( :encoding => 'UTF-8' ) ) }
|
23
63
|
end
|
24
64
|
|
25
|
-
def self.
|
65
|
+
def self.string_keys( locales_dir )
|
26
66
|
path = "#{locales_dir}/values/strings.xml"
|
27
67
|
translations = Vocab::Translator::Android.hash_from_xml( path )
|
28
|
-
|
68
|
+
keys = translations.keys.map { |key| Vocab::Translator::Base.ignore_key?( key ) ? nil : key }.compact
|
69
|
+
return keys
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.plural_keys( locales_dir )
|
73
|
+
path = "#{locales_dir}/values/strings.xml"
|
74
|
+
translations = Vocab::Translator::Android.plurals_from_xml( path )
|
75
|
+
keys = translations.keys.map { |key| Vocab::Translator::Base.ignore_key?( key ) ? nil : key }.compact
|
76
|
+
return keys
|
29
77
|
end
|
30
78
|
|
31
79
|
def self.locales( dir, strict = true )
|
@@ -38,6 +86,16 @@ module Vocab
|
|
38
86
|
return locales
|
39
87
|
end
|
40
88
|
|
89
|
+
#########################################################################
|
90
|
+
# Helper methods
|
91
|
+
#########################################################################
|
92
|
+
|
93
|
+
def self.doc_from_xml( path )
|
94
|
+
xml = File.open( path ) { |f| f.read }
|
95
|
+
doc = Nokogiri::HTML.fragment( xml ) { |config| config.noblanks }
|
96
|
+
return doc
|
97
|
+
end
|
98
|
+
|
41
99
|
end
|
42
100
|
end
|
43
101
|
end
|
@@ -10,8 +10,8 @@ module Vocab
|
|
10
10
|
return Vocab::Translator::Android.hash_from_xml( path ).keys
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
14
|
-
return Vocab::Translator::Android.
|
13
|
+
def string_keys( path = nil )
|
14
|
+
return Vocab::Translator::Android.string_keys( @locales_dir )
|
15
15
|
end
|
16
16
|
|
17
17
|
def files_to_validate
|
data/lib/vocab/validator/base.rb
CHANGED
@@ -2,13 +2,19 @@ module Vocab
|
|
2
2
|
module Validator
|
3
3
|
class Base
|
4
4
|
|
5
|
+
# Returns false if validation fails
|
5
6
|
def validate
|
7
|
+
ok = true
|
8
|
+
|
6
9
|
files = files_to_validate
|
7
10
|
Vocab.ui.say( "#{files.size} file(s) to validate in #{@locales_dir}" )
|
8
11
|
files.each do |path|
|
9
12
|
validation = validate_file( path )
|
10
13
|
print( path, validation )
|
14
|
+
ok &&= validation[ :missing ] && validation[ :missing ].empty?
|
11
15
|
end
|
16
|
+
|
17
|
+
return ok
|
12
18
|
end
|
13
19
|
|
14
20
|
def print( path, validation )
|
@@ -27,7 +33,7 @@ module Vocab
|
|
27
33
|
|
28
34
|
def validate_file( path )
|
29
35
|
other = other_keys( path )
|
30
|
-
english =
|
36
|
+
english = string_keys( path )
|
31
37
|
|
32
38
|
result = {}
|
33
39
|
result[ :missing ] = ( english - other ).sort
|
data/lib/vocab/version.rb
CHANGED
@@ -7,4 +7,15 @@
|
|
7
7
|
<string name="cancel">Cancel</string>
|
8
8
|
<string name="delete">Delete</string>
|
9
9
|
<string name="not_in_es">This key not in spanish</string>
|
10
|
+
<string name="debug_key">Should be ignored</string>
|
11
|
+
|
12
|
+
<plurals name="user_count">
|
13
|
+
<item quantity="one">1 user</item>
|
14
|
+
<item quantity="many">%d users</item>
|
15
|
+
</plurals>
|
16
|
+
|
17
|
+
<plurals name="fish_count">
|
18
|
+
<item quantity="one">1 fish</item>
|
19
|
+
<item quantity="many">%d fish</item>
|
20
|
+
</plurals>
|
10
21
|
</resources>
|
@@ -3,4 +3,9 @@
|
|
3
3
|
<string name="app_name">Modo Niños</string>
|
4
4
|
<string name="pd_app_name">el Panel para padres</string>
|
5
5
|
<string name="app_current">actual</string>
|
6
|
+
|
7
|
+
<plurals name="fish_count">
|
8
|
+
<item quantity="one">1 pescado</item>
|
9
|
+
<item quantity="many">%d peces</item>
|
10
|
+
</plurals>
|
6
11
|
</resources>
|