phraseapp_updater 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.markdown +7 -5
- data/bin/phraseapp_updater +19 -8
- data/lib/phraseapp_updater.rb +8 -6
- data/lib/phraseapp_updater/locale_file.rb +20 -13
- data/lib/phraseapp_updater/locale_file/json_file.rb +29 -0
- data/lib/phraseapp_updater/locale_file/loader.rb +24 -0
- data/lib/phraseapp_updater/locale_file/yaml_file.rb +20 -0
- data/lib/phraseapp_updater/phraseapp_api.rb +5 -4
- data/lib/phraseapp_updater/version.rb +1 -1
- data/lib/phraseapp_updater/yml_config_loader.rb +28 -3
- metadata +6 -4
- data/lib/phraseapp_updater/locale_file_loader.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0c061126d02d4f01d387770c2c9340336be6e5f
|
4
|
+
data.tar.gz: 31e72d551e6852fa680e477c2e0a9ba185bd5160
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b64d248d78459245df8f5f17121b85268f11cf35273addb88d8d8f876e3d24325644d6ba7696f112bca6003aefc5c8e3ac752c3a4a64e6959246bfe89d93203
|
7
|
+
data.tar.gz: 4ada8a07261f8e5966a6a72ed5f8223bf18999704fccfaa1f1f7c6dc4d98506b8195ed8a179b1287aef6fe88e4031ba431bffbe71e76dd5d7cc5a651a2fae848
|
data/README.markdown
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[![Build Status](https://travis-ci.org/iknow/phraseapp_updater.svg?branch=master)](https://travis-ci.org/iknow/phraseapp_updater)
|
4
4
|
|
5
|
-
**Version** 0.1.
|
5
|
+
**Version** 0.1.5
|
6
6
|
|
7
7
|
This is a tool for merging PhraseApp locale data with locale data
|
8
8
|
committed in your project.
|
@@ -89,7 +89,7 @@ committed to your application's respository. These will be used in the
|
|
89
89
|
merge with the files on PhraseApp.
|
90
90
|
|
91
91
|
```
|
92
|
-
phraseapp_updater push --new_locales_path="/data/previous", --previous_locales_path="/data/new" --phraseapp_api_key="yourkey" --phraseapp_project_id="projectid"
|
92
|
+
phraseapp_updater push --new_locales_path="/data/previous", --previous_locales_path="/data/new" --phraseapp_api_key="yourkey" --phraseapp_project_id="projectid --file_format=json"
|
93
93
|
```
|
94
94
|
|
95
95
|
The arguments provided to the command can also be specified as shell
|
@@ -100,6 +100,7 @@ PA_NEW_LOCALES_PATH
|
|
100
100
|
PA_PREVIOUS_LOCALES_PATH
|
101
101
|
PA_API_KEY
|
102
102
|
PA_PROJECT_ID
|
103
|
+
PA_FILE_FORMAT
|
103
104
|
```
|
104
105
|
|
105
106
|
Additionally, PhraseApp credentials can be loaded from a
|
@@ -118,7 +119,7 @@ If you want to pull without this fallback behavior, PhraseApp's [client](https:/
|
|
118
119
|
is the best tool to use.
|
119
120
|
|
120
121
|
```
|
121
|
-
phraseapp_updater pull --fallback_path="/data/app/locales" --phraseapp_api_key="yourkey" --phraseapp_project_id="projectid"
|
122
|
+
phraseapp_updater pull --fallback_path="/data/app/locales" --phraseapp_api_key="yourkey" --phraseapp_project_id="projectid --file_format=json""
|
122
123
|
```
|
123
124
|
|
124
125
|
The PhraseApp data passed to the command can also be specified as shell
|
@@ -127,6 +128,7 @@ variables:
|
|
127
128
|
```
|
128
129
|
PA_API_KEY
|
129
130
|
PA_PROJECT_ID
|
131
|
+
PA_FILE_FORMAT
|
130
132
|
```
|
131
133
|
|
132
134
|
Additionally, PhraseApp credentials can be loaded from a
|
@@ -138,8 +140,8 @@ Ruby
|
|
138
140
|
`PhraseAppUpdater.push` and `PhraseAppUpdater.pull` are analogous to the command line versions:
|
139
141
|
|
140
142
|
```ruby
|
141
|
-
PhraseAppUpdater.
|
142
|
-
PhraseAppUpdater.
|
143
|
+
PhraseAppUpdater.new("api_key", "project_id", "file_format").push("previous/path", "current/path")
|
144
|
+
PhraseAppUpdater.new("api_key", "project_id", "file_format").pull("fallback/path")
|
143
145
|
```
|
144
146
|
|
145
147
|
|
data/bin/phraseapp_updater
CHANGED
@@ -11,9 +11,10 @@ class PhraseAppUpdaterCLI < Thor
|
|
11
11
|
option :config_file_path, type: :string, desc: "Path to .phraseapp.yml config file to read API key and project ID."
|
12
12
|
option :store_results_path, type: :string, desc: "Path to write the resolved files. Shell variable: PA_STORE_RESULTS_PATH"
|
13
13
|
option :store_phraseapp_originals_path, type: :string, desc: "Path to write the files downloaded from PhraseApp before the merge. Shell variable: PA_STORE_PHRASEAPP_ORIGINALS_PATH"
|
14
|
+
option :file_format, type: :string, desc: "Filetype of localization files."
|
14
15
|
|
15
16
|
def push
|
16
|
-
phraseapp_api_key, phraseapp_project_id =
|
17
|
+
phraseapp_api_key, phraseapp_project_id, file_format = load_phraseapp_configuration(options)
|
17
18
|
|
18
19
|
new_locales_path = options.fetch(:new_locales_path, ENV["PA_NEW_LOCALES_PATH"]).to_s
|
19
20
|
validate_readable_path!('new_locales_path', new_locales_path)
|
@@ -28,7 +29,7 @@ class PhraseAppUpdaterCLI < Thor
|
|
28
29
|
validate_writable_path!('store_phraseapp_originals_path', store_phraseapp_originals_path)
|
29
30
|
|
30
31
|
begin
|
31
|
-
result = PhraseAppUpdater.new(phraseapp_api_key, phraseapp_project_id).push(previous_locales_path, new_locales_path)
|
32
|
+
result = PhraseAppUpdater.new(phraseapp_api_key, phraseapp_project_id, file_format).push(previous_locales_path, new_locales_path)
|
32
33
|
|
33
34
|
unless store_results_path.empty?
|
34
35
|
write_locale_files(store_results_path, result.resolved_files)
|
@@ -41,8 +42,10 @@ class PhraseAppUpdaterCLI < Thor
|
|
41
42
|
puts "Bad PhraseApp API key."
|
42
43
|
rescue PhraseAppUpdater::PhraseAppAPI::BadProjectIDError => e
|
43
44
|
puts "Bad PhraseApp project ID: #{phraseapp_project_id}"
|
45
|
+
rescue PhraseAppUpdater::LocaleFile::BadFileTypeError => e
|
46
|
+
puts "Bad filetype for localization files: #{e.message}"
|
44
47
|
rescue StandardError => e
|
45
|
-
puts "Unknown error when pushing files"
|
48
|
+
puts "Unknown error when pushing files."
|
46
49
|
raise e
|
47
50
|
end
|
48
51
|
end
|
@@ -56,7 +59,7 @@ class PhraseAppUpdaterCLI < Thor
|
|
56
59
|
option :config_file_path, type: :string, desc: "Path to .phraseapp.yml config file to read API key and project ID."
|
57
60
|
|
58
61
|
def pull
|
59
|
-
phraseapp_api_key, phraseapp_project_id =
|
62
|
+
phraseapp_api_key, phraseapp_project_id, file_format = load_phraseapp_configuration(options)
|
60
63
|
|
61
64
|
fallback_path = options[:fallback_path]
|
62
65
|
validate_readable_path!('fallback_path', fallback_path)
|
@@ -65,12 +68,14 @@ class PhraseAppUpdaterCLI < Thor
|
|
65
68
|
validate_writable_path!('destination_path', destination_path)
|
66
69
|
|
67
70
|
begin
|
68
|
-
files = PhraseAppUpdater.new(phraseapp_api_key, phraseapp_project_id).pull(fallback_path)
|
71
|
+
files = PhraseAppUpdater.new(phraseapp_api_key, phraseapp_project_id, file_format).pull(fallback_path)
|
69
72
|
write_locale_files(destination_path, files)
|
70
73
|
rescue PhraseAppUpdater::PhraseAppAPI::BadAPIKeyError => e
|
71
74
|
puts "Bad PhraseApp API key."
|
72
75
|
rescue PhraseAppUpdater::PhraseAppAPI::BadProjectIDError => e
|
73
76
|
puts "Bad PhraseApp project ID: #{phraseapp_project_id}"
|
77
|
+
rescue PhraseAppUpdater::LocaleFile::BadFileTypeError => e
|
78
|
+
puts "Bad filetype for localization files: #{e.message}"
|
74
79
|
rescue StandardError => e
|
75
80
|
puts "Unknown error when pulling files"
|
76
81
|
raise e
|
@@ -92,10 +97,10 @@ class PhraseAppUpdaterCLI < Thor
|
|
92
97
|
|
93
98
|
private
|
94
99
|
|
95
|
-
def
|
100
|
+
def load_phraseapp_configuration(options)
|
96
101
|
if options[:config_file_path]
|
97
102
|
|
98
|
-
if
|
103
|
+
if [:phraseapp_api_key, :phraseapp_project_id, :file_format].any? { |option| options.has_key?(:option) }
|
99
104
|
raise RuntimeError.new("Provided both a path to PhraseApp config file and command line arguments. Specify only one. #{options}")
|
100
105
|
end
|
101
106
|
|
@@ -103,9 +108,11 @@ class PhraseAppUpdaterCLI < Thor
|
|
103
108
|
|
104
109
|
phraseapp_api_key = config.api_key
|
105
110
|
phraseapp_project_id = config.project_id
|
111
|
+
file_format = config.file_format
|
106
112
|
else
|
107
113
|
phraseapp_api_key = options.fetch(:phraseapp_api_key, ENV["PA_API_KEY"]).to_s
|
108
114
|
phraseapp_project_id = options.fetch(:phraseapp_project_id, ENV["PA_PROJECT_ID"]).to_s
|
115
|
+
file_format = options.fetch(:file_format, ENV["PA_FILE_FORMAT"]).to_s
|
109
116
|
end
|
110
117
|
|
111
118
|
if phraseapp_api_key.empty?
|
@@ -116,7 +123,11 @@ class PhraseAppUpdaterCLI < Thor
|
|
116
123
|
raise RuntimeError.new("Must provide Phraseapp project ID. --phraseapp_project_id or PA_PROJECT_ID")
|
117
124
|
end
|
118
125
|
|
119
|
-
|
126
|
+
if file_format.empty?
|
127
|
+
raise RuntimeError.new("Must provide file format for Phraseapp project. --file_format or PA_FILE_FORMAT")
|
128
|
+
end
|
129
|
+
|
130
|
+
return [phraseapp_api_key, phraseapp_project_id, file_format]
|
120
131
|
end
|
121
132
|
|
122
133
|
def validate_path!(name, path)
|
data/lib/phraseapp_updater.rb
CHANGED
@@ -2,15 +2,16 @@ require 'phraseapp_updater/version'
|
|
2
2
|
require 'phraseapp_updater/index_by'
|
3
3
|
require 'phraseapp_updater/differ'
|
4
4
|
require 'phraseapp_updater/locale_file'
|
5
|
-
require 'phraseapp_updater/
|
5
|
+
require 'phraseapp_updater/locale_file/loader'
|
6
6
|
require 'phraseapp_updater/phraseapp_api'
|
7
7
|
require 'phraseapp_updater/yml_config_loader'
|
8
8
|
|
9
9
|
class PhraseAppUpdater
|
10
10
|
using IndexBy
|
11
11
|
|
12
|
-
def initialize(phraseapp_api_key, phraseapp_project_id)
|
13
|
-
@
|
12
|
+
def initialize(phraseapp_api_key, phraseapp_project_id, file_format)
|
13
|
+
@locale_file_class = LocaleFile.class_for_file_format(file_format)
|
14
|
+
@phraseapp_api = PhraseAppAPI.new(phraseapp_api_key, phraseapp_project_id, @locale_file_class)
|
14
15
|
end
|
15
16
|
|
16
17
|
def self.load_config(config_file_path)
|
@@ -38,7 +39,7 @@ class PhraseAppUpdater
|
|
38
39
|
primary: new_locale_file.parsed_content,
|
39
40
|
secondary: phraseapp_file.parsed_content)
|
40
41
|
|
41
|
-
|
42
|
+
@locale_file_class.from_hash(previous_locale_file.name, resolved_content)
|
42
43
|
end
|
43
44
|
|
44
45
|
# Upload all of the secondary languages first,
|
@@ -88,7 +89,7 @@ class PhraseAppUpdater
|
|
88
89
|
fallback = clear_empty_strings!(fallback_files[phraseapp_without_unverified_file.name].parsed_content)
|
89
90
|
|
90
91
|
restore_unverified_originals!(fallback, with_unverified, without_unverified)
|
91
|
-
|
92
|
+
@locale_file_class.from_hash(phraseapp_without_unverified_file.name, without_unverified)
|
92
93
|
end
|
93
94
|
end
|
94
95
|
|
@@ -107,8 +108,9 @@ class PhraseAppUpdater
|
|
107
108
|
end
|
108
109
|
|
109
110
|
def load_locale_files(*paths)
|
111
|
+
loader = LocaleFile::Loader.new(@locale_file_class::EXTENSION)
|
110
112
|
paths.map do |path|
|
111
|
-
|
113
|
+
loader.filenames(path).map { |l| loader.load(l) }
|
112
114
|
end
|
113
115
|
end
|
114
116
|
|
@@ -1,18 +1,28 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
|
4
|
-
# We're working with pure JSON, not
|
5
|
-
# serialized Ruby objects
|
6
|
-
Oj.default_options = {mode: :strict}
|
1
|
+
require "phraseapp_updater/locale_file/json_file"
|
2
|
+
require "phraseapp_updater/locale_file/yaml_file"
|
7
3
|
|
8
4
|
class PhraseAppUpdater
|
9
5
|
class LocaleFile
|
10
6
|
attr_reader :name, :content, :parsed_content
|
11
7
|
|
8
|
+
class BadFileTypeError < StandardError ; end
|
9
|
+
|
12
10
|
def self.from_hash(name, hash)
|
13
|
-
new(
|
11
|
+
raise RuntimeError.new("Must be implemented in a subclass.")
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.class_for_file_format(type)
|
15
|
+
case type.downcase
|
16
|
+
when "json"
|
17
|
+
JSONFile
|
18
|
+
when "yml", "yaml"
|
19
|
+
YAMLFile
|
20
|
+
else
|
21
|
+
raise BadFileTypeError.new("Invalid file type: #{type}")
|
22
|
+
end
|
14
23
|
end
|
15
24
|
|
25
|
+
# Expects a Ruby hash
|
16
26
|
def initialize(name, content)
|
17
27
|
@name = name
|
18
28
|
@content = content
|
@@ -25,20 +35,17 @@ class PhraseAppUpdater
|
|
25
35
|
end
|
26
36
|
|
27
37
|
def name_with_extension
|
28
|
-
"#{name}.
|
38
|
+
"#{name}.#{self.class::EXTENSION}"
|
29
39
|
end
|
30
40
|
|
31
41
|
private
|
32
42
|
|
33
43
|
def parse(content)
|
34
|
-
|
35
|
-
rescue MultiJson::ParseError => e
|
36
|
-
raise ArgumentError.new("Provided content was not valid JSON")
|
44
|
+
raise RuntimeError.new("Must be implemented in a subclass.")
|
37
45
|
end
|
38
46
|
|
39
47
|
def format_content!
|
40
|
-
|
41
|
-
@content = MultiJson.dump(MultiJson.load(@content), pretty: true)
|
48
|
+
raise RuntimeError.new("Must be implemented in a subclass.")
|
42
49
|
end
|
43
50
|
end
|
44
51
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
require 'oj'
|
3
|
+
|
4
|
+
# We're working with pure JSON, not
|
5
|
+
# serialized Ruby objects
|
6
|
+
Oj.default_options = {mode: :strict}
|
7
|
+
|
8
|
+
class PhraseAppUpdater
|
9
|
+
class LocaleFile
|
10
|
+
class JSONFile < LocaleFile
|
11
|
+
EXTENSION = "json"
|
12
|
+
def self.from_hash(name, hash)
|
13
|
+
new(name, MultiJson.dump(hash))
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse(content)
|
17
|
+
MultiJson.load(content)
|
18
|
+
rescue MultiJson::ParseError => e
|
19
|
+
raise ArgumentError.new("Provided content was not valid JSON: #{e}")
|
20
|
+
end
|
21
|
+
|
22
|
+
def format_content!
|
23
|
+
# Add indentation for better diffs
|
24
|
+
@content = MultiJson.dump(MultiJson.load(@content), pretty: true)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'phraseapp_updater/locale_file'
|
2
|
+
|
3
|
+
class PhraseAppUpdater
|
4
|
+
class LocaleFile
|
5
|
+
class Loader
|
6
|
+
def initialize(extension)
|
7
|
+
@extension = extension
|
8
|
+
end
|
9
|
+
|
10
|
+
def load(filename)
|
11
|
+
unless File.readable?(filename) && File.file?(filename)
|
12
|
+
raise RuntimeError.new("Couldn't read localization file at #{filename}")
|
13
|
+
end
|
14
|
+
|
15
|
+
LocaleFile.class_for_file_format(@extension).new(File.basename(filename).chomp(".#{@extension}"), File.read(filename))
|
16
|
+
end
|
17
|
+
|
18
|
+
def filenames(locale_directory)
|
19
|
+
Dir["#{locale_directory}/*.#{@extension}"]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'psych'
|
2
|
+
class PhraseAppUpdater
|
3
|
+
class LocaleFile
|
4
|
+
class YAMLFile < LocaleFile
|
5
|
+
EXTENSION = "yml"
|
6
|
+
def self.from_hash(name, hash)
|
7
|
+
new(name, Psych.dump(hash))
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse(content)
|
11
|
+
Psych.load(content)
|
12
|
+
rescue Psych::SyntaxError => e
|
13
|
+
raise ArgumentError.new("Provided content was not valid YAML")
|
14
|
+
end
|
15
|
+
|
16
|
+
def format_content!
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -4,9 +4,10 @@ require 'thread'
|
|
4
4
|
|
5
5
|
class PhraseAppUpdater
|
6
6
|
class PhraseAppAPI
|
7
|
-
def initialize(api_key, project_id)
|
8
|
-
@client
|
9
|
-
@project_id
|
7
|
+
def initialize(api_key, project_id, locale_file_class)
|
8
|
+
@client = PhraseApp::Client.new(PhraseApp::Auth::Credentials.new(token: api_key))
|
9
|
+
@project_id = project_id
|
10
|
+
@locale_file_class = locale_file_class
|
10
11
|
end
|
11
12
|
|
12
13
|
def download_locales
|
@@ -23,7 +24,7 @@ class PhraseAppUpdater
|
|
23
24
|
puts "Downloading file for #{locale}"
|
24
25
|
download_file(locale, skip_unverified)
|
25
26
|
end.map do |locale, file_contents|
|
26
|
-
|
27
|
+
@locale_file_class.new(locale.name, file_contents)
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
@@ -2,7 +2,7 @@ require 'yaml'
|
|
2
2
|
|
3
3
|
class PhraseAppUpdater
|
4
4
|
class YMLConfigLoader
|
5
|
-
attr_reader :api_key, :project_id
|
5
|
+
attr_reader :api_key, :project_id, :file_format
|
6
6
|
def initialize(file_path)
|
7
7
|
unless File.readable?(file_path)
|
8
8
|
raise RuntimeError.new("Can't read config file at #{file_path}")
|
@@ -14,8 +14,33 @@ class PhraseAppUpdater
|
|
14
14
|
raise RuntimeError.new("Couldn't parse file contents: #{File.read(file_path)}")
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
|
17
|
+
config = parsed_yaml.fetch("phraseapp")
|
18
|
+
|
19
|
+
@api_key = config.fetch("access_token")
|
20
|
+
@project_id = config.fetch("project_id")
|
21
|
+
|
22
|
+
push_file_format = config.fetch("push").fetch("sources").first.fetch("params").fetch("file_format")
|
23
|
+
pull_file_format = config.fetch("pull").fetch("targets").first.fetch("params").fetch("file_format")
|
24
|
+
|
25
|
+
unless push_file_format == pull_file_format
|
26
|
+
raise ArgumentError.new("Push and pull must be the same format")
|
27
|
+
end
|
28
|
+
|
29
|
+
@file_format = convert(push_file_format)
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def convert(phraseapp_file_format)
|
36
|
+
case phraseapp_file_format
|
37
|
+
when "nested_json"
|
38
|
+
"json"
|
39
|
+
when "yml"
|
40
|
+
"yml"
|
41
|
+
else
|
42
|
+
raise ArugmentError.new("Unsupported type: #{phraseapp_file_format}")
|
43
|
+
end
|
19
44
|
end
|
20
45
|
end
|
21
46
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phraseapp_updater
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Griffin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-02
|
11
|
+
date: 2017-08-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -174,7 +174,9 @@ files:
|
|
174
174
|
- lib/phraseapp_updater/differ.rb
|
175
175
|
- lib/phraseapp_updater/index_by.rb
|
176
176
|
- lib/phraseapp_updater/locale_file.rb
|
177
|
-
- lib/phraseapp_updater/
|
177
|
+
- lib/phraseapp_updater/locale_file/json_file.rb
|
178
|
+
- lib/phraseapp_updater/locale_file/loader.rb
|
179
|
+
- lib/phraseapp_updater/locale_file/yaml_file.rb
|
178
180
|
- lib/phraseapp_updater/phraseapp_api.rb
|
179
181
|
- lib/phraseapp_updater/version.rb
|
180
182
|
- lib/phraseapp_updater/yml_config_loader.rb
|
@@ -199,7 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
199
201
|
version: '0'
|
200
202
|
requirements: []
|
201
203
|
rubyforge_project:
|
202
|
-
rubygems_version: 2.
|
204
|
+
rubygems_version: 2.6.11
|
203
205
|
signing_key:
|
204
206
|
specification_version: 4
|
205
207
|
summary: A three-way differ for PhraseApp projects.
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'phraseapp_updater/locale_file'
|
2
|
-
|
3
|
-
class PhraseAppUpdater
|
4
|
-
class LocaleFileLoader
|
5
|
-
def self.load(filename)
|
6
|
-
unless File.readable?(filename) && File.file?(filename)
|
7
|
-
raise RuntimeError.new("Couldn't read localization file at #{filename}")
|
8
|
-
end
|
9
|
-
|
10
|
-
LocaleFile.new(File.basename(filename).chomp(".json"), File.read(filename))
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.filenames(locale_directory)
|
14
|
-
Dir["#{locale_directory}/*.json"]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|