aigu 0.3.1 → 0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +52 -0
- data/README.md +89 -5
- data/Rakefile +1 -1
- data/aigu.gemspec +7 -4
- data/bin/aigu +1 -1
- data/bin/phare +16 -0
- data/lib/aigu.rb +11 -0
- data/lib/aigu/android_exporter.rb +165 -0
- data/lib/aigu/android_importer.rb +130 -0
- data/lib/aigu/cli.rb +14 -9
- data/lib/aigu/core_exporter.rb +82 -0
- data/lib/aigu/core_importer.rb +82 -0
- data/lib/aigu/exporter.rb +1 -5
- data/lib/aigu/extensions/hash.rb +6 -0
- data/lib/aigu/importer.rb +1 -3
- data/lib/aigu/ios_exporter.rb +165 -0
- data/lib/aigu/ios_importer.rb +181 -0
- data/lib/aigu/mergeer.rb +51 -0
- data/lib/aigu/puller.rb +44 -0
- data/lib/aigu/pusher.rb +44 -0
- data/lib/aigu/unmergeer.rb +55 -0
- data/lib/aigu/version.rb +1 -1
- data/spec/aigu/android_exporter_spec.rb +40 -0
- data/spec/aigu/android_importer_spec.rb +131 -0
- data/spec/aigu/core_exporter_spec.rb +53 -0
- data/spec/aigu/core_importer_spec.rb +102 -0
- data/spec/aigu/exporter_spec.rb +2 -2
- data/spec/aigu/importer_spec.rb +2 -2
- data/spec/aigu/ios_exporter_spec.rb +115 -0
- data/spec/aigu/ios_importer_spec.rb +175 -0
- data/spec/spec_helper.rb +7 -1
- metadata +72 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1891efbb20cc81f439f20f30fb4d74586e09c2c9
|
4
|
+
data.tar.gz: 2715fb01c3d8f203c791ffc55357469b077ad793
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83421bf2129630b61d54543cfa484963415151301c345fd624febb67d65de937a45634173c54fb3017c5a3c3a3f95f3ab92ce1f814b147c99a560336f675f390
|
7
|
+
data.tar.gz: 3a60ed45b7ee4764a8b809cb297e8a9b9a7bfa395ae683cd335009308b189a8bb56039e39e099abee88c5a637a3e1f9ac635b10bf575b5c40bdfc32b33b562ab
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
AllCops:
|
2
|
+
Include:
|
3
|
+
- Rakefile
|
4
|
+
Exclude:
|
5
|
+
- bin/phare
|
6
|
+
|
7
|
+
Documentation:
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
Encoding:
|
11
|
+
Enabled: false
|
12
|
+
|
13
|
+
LineLength:
|
14
|
+
Max: 200
|
15
|
+
|
16
|
+
AccessModifierIndentation:
|
17
|
+
EnforcedStyle: outdent
|
18
|
+
|
19
|
+
IfUnlessModifier:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
CaseIndentation:
|
23
|
+
IndentWhenRelativeTo: case
|
24
|
+
IndentOneStep: true
|
25
|
+
|
26
|
+
MethodLength:
|
27
|
+
CountComments: false
|
28
|
+
Max: 20
|
29
|
+
|
30
|
+
SignalException:
|
31
|
+
Enabled: false
|
32
|
+
|
33
|
+
ColonMethodCall:
|
34
|
+
Enabled: false
|
35
|
+
|
36
|
+
AsciiComments:
|
37
|
+
Enabled: false
|
38
|
+
|
39
|
+
Lambda:
|
40
|
+
Enabled: false
|
41
|
+
|
42
|
+
RegexpLiteral:
|
43
|
+
Enabled: false
|
44
|
+
|
45
|
+
AssignmentInCondition:
|
46
|
+
Enabled: false
|
47
|
+
|
48
|
+
Metrics/AbcSize:
|
49
|
+
Enabled: false
|
50
|
+
|
51
|
+
ClassLength:
|
52
|
+
Enabled: false
|
data/README.md
CHANGED
@@ -1,8 +1,16 @@
|
|
1
1
|
## Introduction
|
2
2
|
|
3
|
-
Aigu
|
4
|
-
|
5
|
-
|
3
|
+
Aigu is a set of utility to process localization files to genarate JSON files
|
4
|
+
to push to Accent service. Pulling from Accent to update localization files
|
5
|
+
is also supported.
|
6
|
+
|
7
|
+
The following localization file formats are supported: Rails YAML, Android
|
8
|
+
XML, Java Enum Core, iOS strings and stringsdict.
|
9
|
+
|
10
|
+
Merge and unmerge commands allows to merge different source files into a
|
11
|
+
single JSON file to send as a single Accent project.
|
12
|
+
|
13
|
+
Push and pull can be used to interact directly with Accent.
|
6
14
|
|
7
15
|
## Installation
|
8
16
|
|
@@ -36,6 +44,13 @@ $ aigu export --locale=fr --input-directory=config/locales --output-file=my-proj
|
|
36
44
|
| `output-file` | The path to the JSON file that will be written by `aigu` |
|
37
45
|
| `ignore` | The patterns `aigu` will use to skip ignored files (eg. `routes.yml`)
|
38
46
|
|
47
|
+
| Command | File format |
|
48
|
+
|-------------------|-------------------------------------------------------|
|
49
|
+
| `export` | Rails YAML |
|
50
|
+
| `andoird_export` | Android XML |
|
51
|
+
| `core_export` | Java Enum Core |
|
52
|
+
| `ios_export` | iOS strings & stringsdict |
|
53
|
+
|
39
54
|
### Importing the JSON file from Accent
|
40
55
|
|
41
56
|
The `import` command takes a generated JSON file from Accent and generates
|
@@ -53,10 +68,67 @@ $ aigu import --locale=fr --input-file=file-from-accent.json --output-directory=
|
|
53
68
|
| `input-file` | The path to the Accent-generated JSON file |
|
54
69
|
| `output-directory` | The directory where the localization YAML files will be generated |
|
55
70
|
|
56
|
-
|
71
|
+
| Command | File format |
|
72
|
+
|-------------------|-------------------------------------------------------|
|
73
|
+
| `import` | Rails YAML |
|
74
|
+
| `andoird_import` | Android XML |
|
75
|
+
| `core_import` | Java Enum Core |
|
76
|
+
| `ios_import` | iOS strings & stringsdict |
|
77
|
+
|
78
|
+
### Merge
|
79
|
+
|
80
|
+
The `merge` command will combine several JSON file into a single one to send into a single Accent project. It will prefix keys with
|
81
|
+
a pattern embedding the filename to allow later unmerging. It works from an input directory, mergin all json files in it.
|
82
|
+
A file can be named `default.json` to avoid prefixes in the resulting json.
|
83
|
+
|
84
|
+
#### Options
|
85
|
+
|
86
|
+
| Option | Description |
|
87
|
+
|--------------------|---------------------------------------------------------------------------------------------------|
|
88
|
+
| `input-directory` | The directory containing json files to merge |
|
89
|
+
| `output-file` | The path to the JSON file that will be written to |
|
90
|
+
|
91
|
+
|
92
|
+
### Unmerge
|
93
|
+
|
94
|
+
The `unmerge` will split the Accent JSON file into several json files, for further processing. It will look for the prefix pattern
|
95
|
+
of the merge command and will extract the filename or use default.json if pattern is not found.
|
96
|
+
|
97
|
+
#### Options
|
98
|
+
|
99
|
+
| Option | Description |
|
100
|
+
|--------------------|---------------------------------------------------------------------------------------------------|
|
101
|
+
| `input-file` | The path to the Accent-generated JSON file |
|
102
|
+
| `output-directory` | The directory where the unmerged files will be written |
|
103
|
+
|
104
|
+
### Sending to Accent
|
105
|
+
|
106
|
+
The `push` command takes a JSON file exported by Aigu and send it to Accent
|
107
|
+
|
108
|
+
#### Options
|
109
|
+
|
110
|
+
| Option | Description |
|
111
|
+
|--------------------|---------------------------------------------------------------------------------------------------|
|
112
|
+
| `input-file` | The path to the Aigu-generated JSON file |
|
113
|
+
| `accent-api-key` | The API key of the Accent project. (See project config in Accent) |
|
114
|
+
| `accent-url` | The URL to the instance of Accent to use (Prod: http://accent.mirego.com, QA: https://mirego-accent-qa.herokuapp.com ) |
|
115
|
+
|
116
|
+
### Pulling from Accent
|
117
|
+
|
118
|
+
The `pull` command GET the Accent generated JSON file
|
119
|
+
|
120
|
+
#### Options
|
121
|
+
|
122
|
+
| Option | Description |
|
123
|
+
|--------------------|---------------------------------------------------------------------------------------------------|
|
124
|
+
| `output-file` | The path to write the Accent JSON file to |
|
125
|
+
| `accent-api-key` | The API key of the Accent project. (See project config in Accent) |
|
126
|
+
| `accent-url` | The URL to the instance of Accent to use (Prod: http://accent.mirego.com, QA: https://mirego-accent-qa.herokuapp.com ) |
|
127
|
+
|
128
|
+
### Using `.aigu.yml`
|
57
129
|
|
58
130
|
Instead of using command-line arguments when running the `aigu` command, you
|
59
|
-
can create a
|
131
|
+
can create a `.aigu.yml` file at the root of your project and hard-code options
|
60
132
|
in that file.
|
61
133
|
|
62
134
|
```yaml
|
@@ -67,6 +139,18 @@ output-directory: config/locales
|
|
67
139
|
input-directory: config/locales
|
68
140
|
```
|
69
141
|
|
142
|
+
## Contributing
|
143
|
+
|
144
|
+
We’re using `phare` to make sure all Ruby code adheres to our coding style
|
145
|
+
guide. The best way to use `phare` is as a pre-commit hook:
|
146
|
+
|
147
|
+
```bash
|
148
|
+
$ ln -s "`pwd`/bin/phare" .git/hooks/pre-commit
|
149
|
+
```
|
150
|
+
|
151
|
+
That way, whenever `git commit` is ran, `phare` will be executed and will abort
|
152
|
+
the commit if there are errors.
|
153
|
+
|
70
154
|
## License
|
71
155
|
|
72
156
|
`Aigu` is © 2014 [Mirego](http://www.mirego.com) and may be freely distributed under the [New BSD license](http://opensource.org/licenses/BSD-3-Clause). See the [`LICENSE.md`](https://github.com/mirego/aigu/blob/master/LICENSE.md) file.
|
data/Rakefile
CHANGED
data/aigu.gemspec
CHANGED
@@ -6,19 +6,22 @@ require 'aigu/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = 'aigu'
|
8
8
|
spec.version = Aigu::VERSION
|
9
|
-
spec.authors = ['Rémi Prévost']
|
10
|
-
spec.email = ['rprevost@mirego.com']
|
9
|
+
spec.authors = ['Rémi Prévost', 'William Jobin']
|
10
|
+
spec.email = ['rprevost@mirego.com', 'wjobin@mirego.com']
|
11
11
|
spec.description = 'Aigu converts a directory of Rails localization files into a single JSON file to import in Accent.'
|
12
12
|
spec.summary = spec.description
|
13
13
|
spec.homepage = 'https://github.com/mirego/aigu'
|
14
14
|
spec.license = 'BSD 3-Clause'
|
15
15
|
|
16
16
|
spec.files = `git ls-files`.split($/)
|
17
|
-
spec.executables =
|
17
|
+
spec.executables = 'aigu'
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
21
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
22
22
|
spec.add_development_dependency 'rake'
|
23
|
-
spec.add_development_dependency 'rspec', '~> 3.0
|
23
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
24
|
+
spec.add_development_dependency 'phare', '~> 0.6'
|
25
|
+
spec.add_development_dependency 'rubocop', '~> 0.27.0'
|
26
|
+
spec.add_development_dependency 'nokogiri', '~> 1.6.3'
|
24
27
|
end
|
data/bin/aigu
CHANGED
data/bin/phare
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by Bundler.
|
4
|
+
#
|
5
|
+
# The application 'phare' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
+
Pathname.new(__FILE__).realpath)
|
12
|
+
|
13
|
+
require 'rubygems'
|
14
|
+
require 'bundler/setup'
|
15
|
+
|
16
|
+
load Gem.bin_path('phare', 'phare')
|
data/lib/aigu.rb
CHANGED
@@ -4,11 +4,22 @@ require 'optparse'
|
|
4
4
|
require 'fileutils'
|
5
5
|
require 'json'
|
6
6
|
require 'yaml'
|
7
|
+
require 'nokogiri'
|
7
8
|
|
8
9
|
require 'aigu/extensions/hash'
|
9
10
|
require 'aigu/cli'
|
10
11
|
require 'aigu/importer'
|
11
12
|
require 'aigu/exporter'
|
13
|
+
require 'aigu/android_exporter'
|
14
|
+
require 'aigu/android_importer'
|
15
|
+
require 'aigu/core_exporter'
|
16
|
+
require 'aigu/core_importer'
|
17
|
+
require 'aigu/ios_exporter'
|
18
|
+
require 'aigu/ios_importer'
|
19
|
+
require 'aigu/unmergeer'
|
20
|
+
require 'aigu/mergeer'
|
21
|
+
require 'aigu/puller'
|
22
|
+
require 'aigu/pusher'
|
12
23
|
|
13
24
|
module Aigu
|
14
25
|
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
module Aigu
|
2
|
+
class AndroidExporter
|
3
|
+
def initialize(opts = {})
|
4
|
+
@output_file = opts[:'output-file']
|
5
|
+
@input_directory = opts[:'input-directory']
|
6
|
+
@locale = opts[:locale]
|
7
|
+
@ignore = opts[:ignore]
|
8
|
+
end
|
9
|
+
|
10
|
+
def process!
|
11
|
+
puts "Generating Accent JSON file `#{@output_file}` based on Android resources files in `#{@input_directory}` directory"
|
12
|
+
|
13
|
+
if @ignore
|
14
|
+
print 'Ignoring '
|
15
|
+
puts @ignore.join(', ')
|
16
|
+
end
|
17
|
+
|
18
|
+
puts '---'
|
19
|
+
|
20
|
+
build_output
|
21
|
+
write_json_file
|
22
|
+
|
23
|
+
puts '---'
|
24
|
+
puts 'Done'
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def build_output
|
30
|
+
@output = {}
|
31
|
+
|
32
|
+
pattern = File.join(@input_directory, '*', 'strings.xml')
|
33
|
+
Dir[pattern].each do |filepath|
|
34
|
+
next unless supported_resource_for_language?(filepath, @locale)
|
35
|
+
|
36
|
+
if ignored_filepath?(filepath)
|
37
|
+
puts "Ignoring #{filepath}"
|
38
|
+
else
|
39
|
+
puts "Processing #{filepath}"
|
40
|
+
|
41
|
+
_, _, qualifiers = get_resource_type(filepath)
|
42
|
+
puts "Qualifiers: #{qualifiers}"
|
43
|
+
|
44
|
+
content = File.open(filepath, 'r:bom|utf-8').read
|
45
|
+
base_key = qualifiers
|
46
|
+
|
47
|
+
content = parse_xml(content, base_key)
|
48
|
+
@output.merge! content
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
@output
|
53
|
+
end
|
54
|
+
|
55
|
+
def write_json_file
|
56
|
+
file_path = @output_file
|
57
|
+
puts "Generating #{file_path}"
|
58
|
+
FileUtils.mkdir_p(File.dirname(file_path))
|
59
|
+
|
60
|
+
File.open(file_path, 'w+') do |file|
|
61
|
+
file << JSON.pretty_generate(JSON.parse(@output.to_json))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def sanitize_value_to_string(value)
|
66
|
+
case value
|
67
|
+
when true
|
68
|
+
'___TRUE___'
|
69
|
+
when false
|
70
|
+
'___FALSE___'
|
71
|
+
when nil
|
72
|
+
'___NULL___'
|
73
|
+
else
|
74
|
+
value
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def parse_xml(xml, base_key = '')
|
79
|
+
xml = cleanup_input_xml(xml)
|
80
|
+
doc = Nokogiri::XML(xml) { |config| config.options = Nokogiri::XML::ParseOptions::RECOVER }
|
81
|
+
resources = doc.root.children
|
82
|
+
string_hash = {}
|
83
|
+
|
84
|
+
resources.each do |node|
|
85
|
+
if node.name == 'string'
|
86
|
+
string_hash.merge!(hash_for_key_value(node['name'], node.content, base_key))
|
87
|
+
elsif node.name == 'string-array'
|
88
|
+
resource_string_prefix = node['name'] + '__ARRAY_ITEM__#'
|
89
|
+
|
90
|
+
item_index = 0
|
91
|
+
node.children.each do |array_item|
|
92
|
+
next unless array_item.name == 'item'
|
93
|
+
|
94
|
+
hash = hash_for_key_value("#{resource_string_prefix}#{item_index}", array_item.content, base_key)
|
95
|
+
string_hash.merge! hash
|
96
|
+
|
97
|
+
item_index += 1
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
string_hash
|
103
|
+
end
|
104
|
+
|
105
|
+
def build_key_name(key_name, base_key)
|
106
|
+
base_key.empty? ? key_name : "#{key_name}__@TYPE_#{base_key}"
|
107
|
+
end
|
108
|
+
|
109
|
+
def hash_for_key_value(key, value, base_key)
|
110
|
+
{ build_key_name(key, base_key) => value }
|
111
|
+
end
|
112
|
+
|
113
|
+
# Try to fix issue
|
114
|
+
def cleanup_input_xml(xml)
|
115
|
+
replace_html_name(xml, 'quot', '"')
|
116
|
+
replace_html_name(xml, 'amp', '&')
|
117
|
+
replace_html_name(xml, 'apos', "'")
|
118
|
+
replace_html_name(xml, 'lt', '<')
|
119
|
+
replace_html_name(xml, 'gt', '>')
|
120
|
+
xml
|
121
|
+
end
|
122
|
+
|
123
|
+
def replace_html_name(xml, html_name, character)
|
124
|
+
replace_string = "&##{character.ord};"
|
125
|
+
xml.gsub!(/&#{html_name};/, replace_string)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Parse out resource meta from filename
|
129
|
+
# Assumes first qualifer is locale if 2 chars
|
130
|
+
def get_resource_type(filepath)
|
131
|
+
filepath_parts = filepath.split(File::SEPARATOR)
|
132
|
+
filepath = filepath_parts[-2]
|
133
|
+
|
134
|
+
resource_qualifiers = filepath.split('-')
|
135
|
+
|
136
|
+
resource_type, first_qualifier = resource_qualifiers
|
137
|
+
|
138
|
+
first_qualifier_is_locale = !first_qualifier || (first_qualifier.length == 2)
|
139
|
+
|
140
|
+
if first_qualifier_is_locale
|
141
|
+
resource_qualifiers.shift(2)
|
142
|
+
locale = first_qualifier
|
143
|
+
else
|
144
|
+
resource_qualifiers.shift(1)
|
145
|
+
locale = nil
|
146
|
+
end
|
147
|
+
|
148
|
+
[resource_type, locale, resource_qualifiers.join(' ')]
|
149
|
+
end
|
150
|
+
|
151
|
+
def supported_resource_for_language?(filepath, expected_locale)
|
152
|
+
_, locale = get_resource_type(filepath)
|
153
|
+
expected_locale == locale
|
154
|
+
end
|
155
|
+
|
156
|
+
def ignored_filepath?(filepath)
|
157
|
+
@ignore && @ignore.any? do |pattern|
|
158
|
+
File.fnmatch(pattern, filepath, File::FNM_PATHNAME | File::FNM_DOTMATCH)
|
159
|
+
end
|
160
|
+
|
161
|
+
_, locale = get_resource_type(filepath)
|
162
|
+
!(@locale == locale)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module Aigu
|
2
|
+
class AndroidImporter
|
3
|
+
ARRAY_REGEX = /__ARRAY_ITEM__#(?<index>\d+)$/
|
4
|
+
TYPE_REGEX = /__@TYPE_(?<type_key>.+)$/
|
5
|
+
|
6
|
+
def initialize(opts = {})
|
7
|
+
@input_file = opts[:'input-file']
|
8
|
+
@output_directory = opts[:'output-directory']
|
9
|
+
@locale = opts[:locale]
|
10
|
+
end
|
11
|
+
|
12
|
+
def process!
|
13
|
+
puts "Generating Android XML files in `#{@output_directory}` based on Accent-generated `#{@input_file}` file"
|
14
|
+
puts '---'
|
15
|
+
|
16
|
+
parse_json
|
17
|
+
@blob = split_res_types(@object)
|
18
|
+
write_xml_files
|
19
|
+
|
20
|
+
puts '---'
|
21
|
+
puts 'Done'
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def parse_json
|
27
|
+
json = File.read(@input_file)
|
28
|
+
@object = JSON.parse(json)
|
29
|
+
@object = expand_content_values(@object)
|
30
|
+
end
|
31
|
+
|
32
|
+
def write_xml_files
|
33
|
+
@blob.each_pair do |type, hash|
|
34
|
+
# TODO: add locale to filename
|
35
|
+
qualifier = type.gsub(/_/, '-')
|
36
|
+
if qualifier != ''
|
37
|
+
qualifier.prepend('-')
|
38
|
+
end
|
39
|
+
if @locale
|
40
|
+
language = '-' + @locale
|
41
|
+
else
|
42
|
+
language = ''
|
43
|
+
end
|
44
|
+
|
45
|
+
file_path = File.join(@output_directory, "values#{language}#{qualifier}", 'strings.xml')
|
46
|
+
puts "Generating #{file_path}"
|
47
|
+
FileUtils.mkdir_p(File.dirname(file_path))
|
48
|
+
|
49
|
+
File.open(file_path, 'w+:bom|utf-8') do |file|
|
50
|
+
file << res_to_xml(hash)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# TODO: Use XML tooling
|
56
|
+
def res_to_xml(content)
|
57
|
+
xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
58
|
+
xml << "<resources>\n"
|
59
|
+
|
60
|
+
content.each_pair do |key, value|
|
61
|
+
if value.is_a?(Array)
|
62
|
+
xml << ' <string-array name=' << key.encode(xml: :attr) << ">\n"
|
63
|
+
value.each do |item|
|
64
|
+
xml << ' <item>' << item.encode(xml: :text) << "</item>\n"
|
65
|
+
end
|
66
|
+
xml << " </string-array>\n"
|
67
|
+
elsif value.is_a?(String)
|
68
|
+
xml << ' <string name=' << key.encode(xml: :attr) << '>' << value.encode(xml: :text) << "</string>\n"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
xml << "</resources>\n"
|
73
|
+
xml
|
74
|
+
end
|
75
|
+
|
76
|
+
def localize_content_keys(content)
|
77
|
+
content.reduce({}) do |memo, (key, value)|
|
78
|
+
localized_key = key.gsub(/^([^|]+)\|/, "\\1.#{@locale}|#{@locale}.")
|
79
|
+
memo.merge localized_key => value
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def expand_content_values(content)
|
84
|
+
content.each_with_object({}) do |(key, value), memo|
|
85
|
+
match_data = key.match(ARRAY_REGEX)
|
86
|
+
|
87
|
+
if match_data
|
88
|
+
canonical_key = key.gsub(ARRAY_REGEX, '')
|
89
|
+
value_index = match_data[:index].to_i
|
90
|
+
memo[canonical_key] ||= []
|
91
|
+
memo[canonical_key][value_index] = sanitize_string_to_value(value)
|
92
|
+
else
|
93
|
+
memo[key] = sanitize_string_to_value(value)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def split_res_types(content)
|
99
|
+
res_types = {}
|
100
|
+
|
101
|
+
content.each_pair do |key, value|
|
102
|
+
match_data = key.match(TYPE_REGEX)
|
103
|
+
if match_data
|
104
|
+
canonical_key = key.gsub(TYPE_REGEX, '')
|
105
|
+
res_type = match_data[:type_key]
|
106
|
+
else
|
107
|
+
canonical_key = key
|
108
|
+
res_type = ''
|
109
|
+
end
|
110
|
+
res_types[res_type] ||= {}
|
111
|
+
res_types[res_type][canonical_key] = value
|
112
|
+
end
|
113
|
+
|
114
|
+
res_types
|
115
|
+
end
|
116
|
+
|
117
|
+
def sanitize_string_to_value(string)
|
118
|
+
case string
|
119
|
+
when '___TRUE___'
|
120
|
+
true
|
121
|
+
when '___FALSE___'
|
122
|
+
false
|
123
|
+
when '___NULL___'
|
124
|
+
nil
|
125
|
+
else
|
126
|
+
string
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|