i18n-migrations 1.1.6 → 1.2.0
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 +4 -4
- data/.i18n-migrations.default.yml +3 -0
- data/bin/i18n-migrate +51 -61
- data/lib/i18n/migrations/backends/crowd_translate_backend.rb +37 -0
- data/lib/i18n/migrations/backends/crowd_translate_client.rb +73 -0
- data/lib/i18n/migrations/backends/google_spreadsheet.rb +23 -0
- data/lib/i18n/migrations/backends/google_spreadsheets_backend.rb +84 -0
- data/lib/i18n/migrations/config.rb +23 -6
- data/lib/i18n/migrations/locale.rb +42 -86
- data/lib/i18n/migrations/migrator.rb +17 -42
- data/lib/i18n/migrations/version.rb +1 -1
- metadata +6 -4
- data/lib/i18n/migrations/crowd_translate_client.rb +0 -75
- data/lib/i18n/migrations/google_spreadsheet.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4d01adcb15a5984163cc175fbd044377722a00894ec47bddde58d809ceb6179
|
4
|
+
data.tar.gz: 50b65ac56c6a5947c8f63a28f0c0b828002d1606cc8c018dcfd9ae911443b56f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: edc8b29b0caba7fc2777b025e229bb9e01bee80ed6797ae4652053dc4dc82cc5d91486e9eb57c315f503a2cecc34c5332ba8e37a361c4e8efc3fd332c9de0664
|
7
|
+
data.tar.gz: 832badb95a3490dc496caf1e3a938dd9335cc3279cd6e79a63291934d4f2ad5640890a3a1b41a71b5c9b7f4e17d61327f3b9d992782b350b6b7abc9ba1eba390
|
@@ -4,6 +4,9 @@ migration_dir: i18n/migrate
|
|
4
4
|
# this is where your locale files will live (en.yml, es.yml, etc). it will be relative to your config file
|
5
5
|
locales_dir: config/locales
|
6
6
|
|
7
|
+
# choose either google_spreadsheets or crowd_translate as a backend
|
8
|
+
backend: google_spreadsheets
|
9
|
+
|
7
10
|
# number of threads to concurrently perform migration operations for locales (optional)
|
8
11
|
# concurrency: 4
|
9
12
|
|
data/bin/i18n-migrate
CHANGED
@@ -11,65 +11,58 @@ def extract_option(name)
|
|
11
11
|
end
|
12
12
|
|
13
13
|
case ARGV.shift
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
when 'push'
|
46
|
-
force = extract_option('-f')
|
47
|
-
migrator.push(ARGV[0] || 'all', force)
|
48
|
-
|
49
|
-
when 'ct-pull'
|
50
|
-
migrator.exp_pull(ARGV[0] || 'all')
|
51
|
-
|
52
|
-
when 'ct-push'
|
53
|
-
force = extract_option('-f')
|
54
|
-
migrator.exp_push(ARGV[0] || 'all', force)
|
55
|
-
|
56
|
-
when 'validate'
|
57
|
-
migrator.validate(ARGV[0] || 'all')
|
58
|
-
|
59
|
-
when 'new_locale'
|
60
|
-
locale = ARGV.shift
|
61
|
-
if locale
|
62
|
-
migrator.new_locale(locale)
|
63
|
-
else
|
64
|
-
STDERR.puts 'Usage: im new_locale [name]'
|
65
|
-
exit 1
|
66
|
-
end
|
67
|
-
|
68
|
-
when 'version'
|
69
|
-
migrator.version
|
14
|
+
when 'setup'
|
15
|
+
puts 'Where should we create a default config file? [.]'
|
16
|
+
dir = gets.chomp
|
17
|
+
dir = dir == '' ? '.' : dir
|
18
|
+
file = I18n::Migrations::Config.copy_default_config_file(dir)
|
19
|
+
|
20
|
+
puts 'You will need to configure this file before you can get going.'
|
21
|
+
puts File.expand_path(file)
|
22
|
+
|
23
|
+
when 'new'
|
24
|
+
name = ARGV.shift
|
25
|
+
if name
|
26
|
+
migrator.new_migration name
|
27
|
+
else
|
28
|
+
STDERR.puts 'Usage: im new [name]'
|
29
|
+
exit 1
|
30
|
+
end
|
31
|
+
|
32
|
+
when 'migrate'
|
33
|
+
migrator.migrate(ARGV[0] || 'all')
|
34
|
+
|
35
|
+
when 'rollback'
|
36
|
+
migrator.rollback(ARGV[0] || 'all')
|
37
|
+
|
38
|
+
when 'redo'
|
39
|
+
migrator.rollback(ARGV[0] || 'all')
|
40
|
+
migrator.migrate(ARGV[0] || 'all')
|
41
|
+
|
42
|
+
when 'pull'
|
43
|
+
migrator.pull(ARGV[0] || 'all')
|
70
44
|
|
45
|
+
when 'push'
|
46
|
+
force = extract_option('-f')
|
47
|
+
migrator.push(ARGV[0] || 'all', force)
|
48
|
+
|
49
|
+
when 'validate'
|
50
|
+
migrator.validate(ARGV[0] || 'all')
|
51
|
+
|
52
|
+
when 'new_locale'
|
53
|
+
locale = ARGV.shift
|
54
|
+
if locale
|
55
|
+
migrator.new_locale(locale)
|
71
56
|
else
|
72
|
-
puts
|
57
|
+
STDERR.puts 'Usage: im new_locale [name]'
|
58
|
+
exit 1
|
59
|
+
end
|
60
|
+
|
61
|
+
when 'version'
|
62
|
+
migrator.version
|
63
|
+
|
64
|
+
else
|
65
|
+
puts <<-USAGE
|
73
66
|
Usage: i18n-migrate [command]
|
74
67
|
|
75
68
|
Commands:
|
@@ -84,9 +77,6 @@ Commands:
|
|
84
77
|
new_locale - Copy your current main locale file to a new language, translating all keys.
|
85
78
|
version - Print version of locales.
|
86
79
|
|
87
|
-
ct-pull - Pull from CrowdTranslate
|
88
|
-
ct-push - Push to CrowdTranslate
|
89
|
-
|
90
80
|
i18n-migrations version #{I18n::Migrations::VERSION}
|
91
|
-
|
81
|
+
USAGE
|
92
82
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative './crowd_translate_client'
|
2
|
+
|
3
|
+
module I18n
|
4
|
+
module Migrations
|
5
|
+
module Backends
|
6
|
+
class CrowdTranslateBackend
|
7
|
+
attr_reader :client
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@client = CrowdTranslateClient.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def pull(locale)
|
14
|
+
pull_from_crowd_translate(locale)
|
15
|
+
locale.migrate!
|
16
|
+
end
|
17
|
+
|
18
|
+
def push(locale, force = false)
|
19
|
+
raise "CrowdTranslate does not support -f flag yet" if force
|
20
|
+
|
21
|
+
# do this just once
|
22
|
+
unless @migrations_synced
|
23
|
+
@client.sync_migrations(locale.migrations)
|
24
|
+
@migrations_synced = true
|
25
|
+
end
|
26
|
+
pull(locale)
|
27
|
+
end
|
28
|
+
|
29
|
+
def pull_from_crowd_translate(locale)
|
30
|
+
data = @client.get_locale_file(locale.name)
|
31
|
+
locale.write_raw_data("#{locale.name}.yml", data)
|
32
|
+
locale.write_remote_version(YAML::load(data)[locale.name])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'active_support/core_ext/object'
|
3
|
+
|
4
|
+
module I18n
|
5
|
+
module Migrations
|
6
|
+
module Backends
|
7
|
+
class CrowdTranslateClient
|
8
|
+
def initialize
|
9
|
+
token = ENV['CROWD_TRANSLATE_API_TOKEN']
|
10
|
+
raise("You must define CROWD_TRANSLATE_API_TOKEN in order to talk to Crowd Translate") unless token.present?
|
11
|
+
|
12
|
+
server = ENV['CROWD_TRANSLATE_SERVER'] || 'https://crowd-translate.herokuapp.com'
|
13
|
+
@faraday = Faraday.new(
|
14
|
+
url: "#{server}/api/v1",
|
15
|
+
headers: { 'X-CrowdTranslateApiToken' => token },
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def sync_migrations(migrations)
|
20
|
+
local_versions = migrations.all_versions
|
21
|
+
remote_versions = JSON.parse(get('migrations.json'))
|
22
|
+
|
23
|
+
if (extra_versions = remote_versions - local_versions).present?
|
24
|
+
raise("You may not upload migrations to the server because it has migrations not found locally: " +
|
25
|
+
"#{extra_versions.join(', ')}")
|
26
|
+
end
|
27
|
+
|
28
|
+
if (versions_to_add = local_versions - remote_versions).present?
|
29
|
+
versions_to_add.each do |version|
|
30
|
+
begin
|
31
|
+
put("migrations/#{version}.json",
|
32
|
+
migration: { ruby_file: migrations.get_migration(version: version) })
|
33
|
+
rescue
|
34
|
+
puts "There was an error updating migration:".red
|
35
|
+
puts " #{migrations.migration_file(version: version)}".bold
|
36
|
+
raise
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_locale_file(locale_code)
|
43
|
+
get("locales/#{locale_code}.yml")
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def get(path)
|
49
|
+
puts "GET #{path}".bold
|
50
|
+
parse_response @faraday.get path
|
51
|
+
end
|
52
|
+
|
53
|
+
def put(path, params = {})
|
54
|
+
puts "PUT #{path} #{params.to_s[0..50]}#{'...' if params.to_s.length > 50}".bold
|
55
|
+
parse_response @faraday.put path, params
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse_response(response)
|
59
|
+
if response.success?
|
60
|
+
response.body
|
61
|
+
else
|
62
|
+
error = begin
|
63
|
+
JSON.parse(response.body)['error']
|
64
|
+
rescue
|
65
|
+
response.body
|
66
|
+
end
|
67
|
+
raise error
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'google_drive'
|
2
|
+
|
3
|
+
module I18n
|
4
|
+
module Migrations
|
5
|
+
module Backends
|
6
|
+
class GoogleSpreadsheet
|
7
|
+
attr_reader :sheet
|
8
|
+
|
9
|
+
def initialize(locale, spreadsheet_url, key_path)
|
10
|
+
@session = GoogleDrive::Session.from_service_account_key(key_path)
|
11
|
+
|
12
|
+
url = spreadsheet_url || raise("Can't find google spreadsheet for #{locale}")
|
13
|
+
@spreadsheet = @session.spreadsheet_by_url(url)
|
14
|
+
@sheet = sheet_for("Sheet1")
|
15
|
+
end
|
16
|
+
|
17
|
+
def sheet_for(name)
|
18
|
+
@spreadsheet.worksheet_by_title(name) || raise("couldn't find worksheet for #{name}")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require_relative './google_spreadsheet'
|
2
|
+
|
3
|
+
module I18n
|
4
|
+
module Migrations
|
5
|
+
module Backends
|
6
|
+
class GoogleSpreadsheetsBackend
|
7
|
+
def initialize(config)
|
8
|
+
@config = config
|
9
|
+
end
|
10
|
+
|
11
|
+
def pull(locale)
|
12
|
+
return if locale.main_locale?
|
13
|
+
|
14
|
+
sheet = get_google_spreadsheet(locale.name)
|
15
|
+
pull_from_sheet(sheet, locale)
|
16
|
+
locale.migrate!
|
17
|
+
end
|
18
|
+
|
19
|
+
def push(locale, force = false)
|
20
|
+
return if locale.main_locale?
|
21
|
+
|
22
|
+
sheet = get_google_spreadsheet(locale.name)
|
23
|
+
unless force
|
24
|
+
pull_from_sheet(sheet, locale)
|
25
|
+
locale.migrate!
|
26
|
+
end
|
27
|
+
push_to_sheet(sheet, locale)
|
28
|
+
end
|
29
|
+
|
30
|
+
private def get_google_spreadsheet(locale)
|
31
|
+
GoogleSpreadsheet.new(locale,
|
32
|
+
@config.google_spreadsheet(locale),
|
33
|
+
@config.google_service_account_key_path).sheet
|
34
|
+
end
|
35
|
+
|
36
|
+
def pull_from_sheet(sheet, locale)
|
37
|
+
puts "Pulling #{locale.name}"
|
38
|
+
data = {}
|
39
|
+
notes = {}
|
40
|
+
count = 0
|
41
|
+
|
42
|
+
(2..sheet.num_rows).each do |row|
|
43
|
+
key, value, note = sheet[row, 1], sheet[row, 3], sheet[row, 4]
|
44
|
+
if key.present?
|
45
|
+
locale.assign_complex_key(data, key.split('.'), value.present? ? value : '')
|
46
|
+
if note.present?
|
47
|
+
locale.assign_complex_key(notes, key.split('.'), note)
|
48
|
+
end
|
49
|
+
count += 1
|
50
|
+
print '.'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
locale.write_data_and_notes(data, notes)
|
55
|
+
locale.write_remote_version(data)
|
56
|
+
|
57
|
+
puts "\n#{count} keys"
|
58
|
+
end
|
59
|
+
|
60
|
+
def push_to_sheet(sheet, locale)
|
61
|
+
main_data = locale.main_locale.read_data
|
62
|
+
data, notes = locale.read_data_and_notes
|
63
|
+
row = 2
|
64
|
+
|
65
|
+
puts "Pushing #{locale.name}"
|
66
|
+
|
67
|
+
main_data.each do |key, value|
|
68
|
+
sheet[row, 1] = key
|
69
|
+
sheet[row, 2] = value
|
70
|
+
sheet[row, 3] = data[key]
|
71
|
+
sheet[row, 4] = notes[key]
|
72
|
+
row += 1
|
73
|
+
print '.'
|
74
|
+
end
|
75
|
+
|
76
|
+
sheet.synchronize
|
77
|
+
locale.write_remote_version(data)
|
78
|
+
|
79
|
+
puts "\n#{main_data.keys.length} keys"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -6,6 +6,9 @@ module I18n
|
|
6
6
|
CONFIG_FILE_NAME = '.i18n-migrations.yml'
|
7
7
|
DEFAULT_CONCURRENCY = 4
|
8
8
|
DEFAULT_WAIT_SECONDS = 0
|
9
|
+
CROWD_TRANSLATE_BACKEND = 'crowd_translate'
|
10
|
+
GOOGLE_SPREADSHEET_BACKEND = 'google_spreadsheets'
|
11
|
+
VALID_BACKENDS = [CROWD_TRANSLATE_BACKEND, GOOGLE_SPREADSHEET_BACKEND]
|
9
12
|
|
10
13
|
def initialize(config_file_name = CONFIG_FILE_NAME)
|
11
14
|
@config_file_name = config_file_name
|
@@ -23,6 +26,20 @@ module I18n
|
|
23
26
|
get_value(:main_locale)
|
24
27
|
end
|
25
28
|
|
29
|
+
def backend
|
30
|
+
value = get_value(:backend)
|
31
|
+
raise ArgumentError, "Backend must be one of #{VALID_BACKENDS}" unless VALID_BACKENDS.include?(value)
|
32
|
+
value
|
33
|
+
end
|
34
|
+
|
35
|
+
def crowd_translate?
|
36
|
+
backend == CROWD_TRANSLATE_BACKEND
|
37
|
+
end
|
38
|
+
|
39
|
+
def google_spreadsheet?
|
40
|
+
backend == GOOGLE_SPREADSHEET_BACKEND
|
41
|
+
end
|
42
|
+
|
26
43
|
def other_locales
|
27
44
|
get_value(:other_locales).keys
|
28
45
|
end
|
@@ -67,12 +84,12 @@ module I18n
|
|
67
84
|
@root_dir = File.dirname(yaml_file)
|
68
85
|
|
69
86
|
@config = begin
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
87
|
+
YAML::load(File.read(yaml_file))
|
88
|
+
rescue Psych::SyntaxError
|
89
|
+
STDERR.puts("YAML configuration file contains invalid syntax.")
|
90
|
+
STDERR.puts($!.message)
|
91
|
+
exit(1)
|
92
|
+
end
|
76
93
|
|
77
94
|
# todo check for required keys
|
78
95
|
self
|
@@ -13,7 +13,7 @@ module I18n
|
|
13
13
|
|
14
14
|
def initialize(name, locales_dir:, main_locale_name:, migrations:, dictionary:)
|
15
15
|
@name, @locales_dir, @main_locale_name, @migrations, @dictionary =
|
16
|
-
|
16
|
+
name, locales_dir, main_locale_name, migrations, dictionary
|
17
17
|
end
|
18
18
|
|
19
19
|
def validate(data, notes)
|
@@ -51,6 +51,12 @@ module I18n
|
|
51
51
|
write_data_and_notes(data, notes)
|
52
52
|
end
|
53
53
|
|
54
|
+
def migrate!
|
55
|
+
update_info do |data, notes|
|
56
|
+
migrate(data, notes)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
54
60
|
def migrate(data, notes)
|
55
61
|
missing_versions = (@migrations.all_versions - read_versions(data)).sort
|
56
62
|
if missing_versions.empty?
|
@@ -75,60 +81,6 @@ module I18n
|
|
75
81
|
migrate_to_version(data, notes, last_version, :down)
|
76
82
|
end
|
77
83
|
|
78
|
-
def pull(sheet)
|
79
|
-
puts "Pulling #{@name}"
|
80
|
-
data = {}
|
81
|
-
notes = {}
|
82
|
-
count = 0
|
83
|
-
|
84
|
-
(2..sheet.num_rows).each do |row|
|
85
|
-
key, value, note = sheet[row, 1], sheet[row, 3], sheet[row, 4]
|
86
|
-
if key.present?
|
87
|
-
assign_complex_key(data, key.split('.'), value.present? ? value : '')
|
88
|
-
if note.present?
|
89
|
-
assign_complex_key(notes, key.split('.'), note)
|
90
|
-
end
|
91
|
-
count += 1
|
92
|
-
print '.'
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
write_data_and_notes(data, notes)
|
97
|
-
write_remote_version(data)
|
98
|
-
|
99
|
-
puts "\n#{count} keys"
|
100
|
-
end
|
101
|
-
|
102
|
-
def pull_from_crowd_translate(client)
|
103
|
-
data = client.get_locale_file(name)
|
104
|
-
File.open(File.join(@locales_dir, "#{name}.yml"), 'w') do |file|
|
105
|
-
file << data
|
106
|
-
end
|
107
|
-
write_remote_version(YAML::load(data)[name])
|
108
|
-
end
|
109
|
-
|
110
|
-
def push(sheet)
|
111
|
-
main_data = main_locale.read_data
|
112
|
-
data, notes = read_data_and_notes
|
113
|
-
row = 2
|
114
|
-
|
115
|
-
puts "Pushing #{@name}"
|
116
|
-
|
117
|
-
main_data.each do |key, value|
|
118
|
-
sheet[row, 1] = key
|
119
|
-
sheet[row, 2] = value
|
120
|
-
sheet[row, 3] = data[key]
|
121
|
-
sheet[row, 4] = notes[key]
|
122
|
-
row += 1
|
123
|
-
print '.'
|
124
|
-
end
|
125
|
-
|
126
|
-
sheet.synchronize
|
127
|
-
write_remote_version(data)
|
128
|
-
|
129
|
-
puts "\n#{main_data.keys.length} keys"
|
130
|
-
end
|
131
|
-
|
132
84
|
def create(limit = nil)
|
133
85
|
new_data, new_notes = {}, {}
|
134
86
|
count = 0
|
@@ -158,7 +110,27 @@ module I18n
|
|
158
110
|
read_from_file("#{@name}.yml")
|
159
111
|
end
|
160
112
|
|
161
|
-
|
113
|
+
def read_data_and_notes
|
114
|
+
data = read_data
|
115
|
+
notes = main_locale? ? {} : read_from_file("../#{@name}_notes.yml")
|
116
|
+
[data, notes]
|
117
|
+
end
|
118
|
+
|
119
|
+
def write_data_and_notes(data, notes)
|
120
|
+
write_data(data)
|
121
|
+
write_to_file("../#{@name}_notes.yml", notes) unless main_locale?
|
122
|
+
end
|
123
|
+
|
124
|
+
def write_raw_data(filename, data)
|
125
|
+
File.open(File.join(@locales_dir, filename), 'w') do |file|
|
126
|
+
file << data
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def write_remote_version(data)
|
131
|
+
write_to_file("../#{@name}_remote_version.yml",
|
132
|
+
{ 'VERSION' => read_versions(data) })
|
133
|
+
end
|
162
134
|
|
163
135
|
def main_locale
|
164
136
|
Locale.new(@main_locale_name,
|
@@ -168,6 +140,19 @@ module I18n
|
|
168
140
|
dictionary: nil) # should not use dictionary on main locale
|
169
141
|
end
|
170
142
|
|
143
|
+
def assign_complex_key(hash, key, value)
|
144
|
+
if key.length == 0
|
145
|
+
# should never get here
|
146
|
+
elsif key.length == 1
|
147
|
+
hash[key[0]] = value
|
148
|
+
else
|
149
|
+
hash[key[0]] ||= {}
|
150
|
+
assign_complex_key(hash[key[0]], key[1..-1], value)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
171
156
|
def replace_errors_in_notes(all_notes, key, errors)
|
172
157
|
return if all_notes[key].blank? && errors.empty?
|
173
158
|
|
@@ -177,26 +162,10 @@ module I18n
|
|
177
162
|
all_notes[key] = (errors.map { |e| "[error: #{e}]" } + notes).join("\n")
|
178
163
|
end
|
179
164
|
|
180
|
-
def read_data_and_notes
|
181
|
-
data = read_data
|
182
|
-
notes = main_locale? ? {} : read_from_file("../#{@name}_notes.yml")
|
183
|
-
[data, notes]
|
184
|
-
end
|
185
|
-
|
186
|
-
def write_data_and_notes(data, notes)
|
187
|
-
write_data(data)
|
188
|
-
write_to_file("../#{@name}_notes.yml", notes) unless main_locale?
|
189
|
-
end
|
190
|
-
|
191
165
|
def write_data(data)
|
192
166
|
write_to_file("#{@name}.yml", data)
|
193
167
|
end
|
194
168
|
|
195
|
-
def write_remote_version(data)
|
196
|
-
write_to_file("../#{@name}_remote_version.yml",
|
197
|
-
{ 'VERSION' => read_versions(data) })
|
198
|
-
end
|
199
|
-
|
200
169
|
def migrate_to_version(data, notes, version, direction)
|
201
170
|
migrations.play_migration(version: version,
|
202
171
|
locale: @name,
|
@@ -235,20 +204,7 @@ module I18n
|
|
235
204
|
value = hash[key]
|
236
205
|
assign_complex_key(complex_hash, key.split('.'), value.present? ? value : '')
|
237
206
|
end
|
238
|
-
|
239
|
-
file << { @name => complex_hash }.to_yaml
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
def assign_complex_key(hash, key, value)
|
244
|
-
if key.length == 0
|
245
|
-
# should never get here
|
246
|
-
elsif key.length == 1
|
247
|
-
hash[key[0]] = value
|
248
|
-
else
|
249
|
-
hash[key[0]] ||= {}
|
250
|
-
assign_complex_key(hash[key[0]], key[1..-1], value)
|
251
|
-
end
|
207
|
+
write_raw_data(filename, { @name => complex_hash }.to_yaml)
|
252
208
|
end
|
253
209
|
|
254
210
|
# flattens new_hash and adds it to hash
|
@@ -4,12 +4,12 @@ require 'active_support/inflector'
|
|
4
4
|
require 'active_support/core_ext/object'
|
5
5
|
require 'colorize'
|
6
6
|
|
7
|
-
require 'i18n/migrations/
|
8
|
-
require 'i18n/migrations/
|
7
|
+
require 'i18n/migrations/backends/crowd_translate_backend'
|
8
|
+
require 'i18n/migrations/backends/google_spreadsheets_backend'
|
9
9
|
require 'i18n/migrations/config'
|
10
|
+
require 'i18n/migrations/google_translate_dictionary'
|
10
11
|
require 'i18n/migrations/locale'
|
11
12
|
require 'i18n/migrations/migration_factory'
|
12
|
-
require 'i18n/migrations/crowd_translate_client'
|
13
13
|
|
14
14
|
# this class knows how to do all the things the cli needs done.
|
15
15
|
# it mostly delegates to locale to do it, often asking multiple locales to do the same thing
|
@@ -58,9 +58,7 @@ end
|
|
58
58
|
|
59
59
|
def migrate(locale_or_all = 'all')
|
60
60
|
each_locale(locale_or_all) do |locale|
|
61
|
-
locale.
|
62
|
-
locale.migrate(data, notes)
|
63
|
-
end
|
61
|
+
locale.migrate!
|
64
62
|
end
|
65
63
|
end
|
66
64
|
|
@@ -75,41 +73,18 @@ end
|
|
75
73
|
def pull(locale_or_all)
|
76
74
|
each_locale(locale_or_all) do |locale|
|
77
75
|
next if locale.main_locale?
|
78
|
-
|
79
|
-
locale.pull(sheet)
|
80
|
-
migrate(locale.name)
|
76
|
+
backend.pull(locale)
|
81
77
|
end
|
82
78
|
end
|
83
79
|
|
84
80
|
def push(locale_or_all, force = false)
|
85
81
|
each_locale(locale_or_all, concurrency: config.push_concurrency) do |locale|
|
86
|
-
|
87
|
-
sheet = get_google_spreadsheet(locale.name)
|
88
|
-
unless force
|
89
|
-
locale.pull(sheet)
|
90
|
-
migrate(locale.name)
|
91
|
-
end
|
92
|
-
locale.push(sheet)
|
82
|
+
backend.push(locale, force)
|
93
83
|
wait
|
94
84
|
end
|
95
85
|
end
|
96
86
|
|
97
|
-
def
|
98
|
-
client = new_crowd_translate_client
|
99
|
-
each_locale(locale_or_all) do |locale|
|
100
|
-
locale.pull_from_crowd_translate(client)
|
101
|
-
migrate(locale.name)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def exp_push(locale_or_all, force = false)
|
106
|
-
client = new_crowd_translate_client
|
107
|
-
client.sync_migrations(new_migrations)
|
108
|
-
client.play_all_migrations
|
109
|
-
exp_pull(locale_or_all)
|
110
|
-
end
|
111
|
-
|
112
|
-
def new_locale(new_locale, limit = nil)
|
87
|
+
def new_locale(new_locale)
|
113
88
|
locale_for(new_locale).create
|
114
89
|
end
|
115
90
|
|
@@ -128,11 +103,13 @@ end
|
|
128
103
|
end
|
129
104
|
end
|
130
105
|
|
131
|
-
private def each_locale(name = 'all',
|
106
|
+
private def each_locale(name = 'all',
|
107
|
+
async: config.google_spreadsheet?,
|
108
|
+
concurrency: config.concurrency)
|
132
109
|
locale_names = name == 'all' ? all_locale_names : [name]
|
133
110
|
|
134
|
-
puts "Using #{concurrency} concurrency"
|
135
111
|
if async
|
112
|
+
puts "Using #{concurrency} concurrency"
|
136
113
|
locale_names.each_slice(concurrency) do |some_locale_names|
|
137
114
|
threads = some_locale_names.map do |l|
|
138
115
|
locale = locale_for(l)
|
@@ -151,12 +128,6 @@ end
|
|
151
128
|
[config.main_locale] + config.other_locales
|
152
129
|
end
|
153
130
|
|
154
|
-
private def get_google_spreadsheet(locale)
|
155
|
-
GoogleSpreadsheet.new(locale,
|
156
|
-
config.google_spreadsheet(locale),
|
157
|
-
config.google_service_account_key_path).sheet
|
158
|
-
end
|
159
|
-
|
160
131
|
private def new_dictionary(locale)
|
161
132
|
GoogleTranslateDictionary.new(from_locale: config.main_locale,
|
162
133
|
to_locale: locale,
|
@@ -168,8 +139,12 @@ end
|
|
168
139
|
MigrationFactory.new(config.migration_dir)
|
169
140
|
end
|
170
141
|
|
171
|
-
private def
|
172
|
-
|
142
|
+
private def backend
|
143
|
+
@backend ||= if config.crowd_translate?
|
144
|
+
Backends::CrowdTranslateBackend.new
|
145
|
+
else
|
146
|
+
Backends::GoogleSpreadsheetsBackend.new(config)
|
147
|
+
end
|
173
148
|
end
|
174
149
|
|
175
150
|
private def wait
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: i18n-migrations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Lightsmith
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-02-
|
11
|
+
date: 2020-02-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -123,9 +123,11 @@ files:
|
|
123
123
|
- example/i18n/migrate/201901311613_add_colors.rb
|
124
124
|
- i18n-migrations.gemspec
|
125
125
|
- lib/i18n-migrations.rb
|
126
|
+
- lib/i18n/migrations/backends/crowd_translate_backend.rb
|
127
|
+
- lib/i18n/migrations/backends/crowd_translate_client.rb
|
128
|
+
- lib/i18n/migrations/backends/google_spreadsheet.rb
|
129
|
+
- lib/i18n/migrations/backends/google_spreadsheets_backend.rb
|
126
130
|
- lib/i18n/migrations/config.rb
|
127
|
-
- lib/i18n/migrations/crowd_translate_client.rb
|
128
|
-
- lib/i18n/migrations/google_spreadsheet.rb
|
129
131
|
- lib/i18n/migrations/google_translate_dictionary.rb
|
130
132
|
- lib/i18n/migrations/locale.rb
|
131
133
|
- lib/i18n/migrations/migration.rb
|
@@ -1,75 +0,0 @@
|
|
1
|
-
require 'faraday'
|
2
|
-
require 'active_support/core_ext/object'
|
3
|
-
|
4
|
-
module I18n
|
5
|
-
module Migrations
|
6
|
-
class CrowdTranslateClient
|
7
|
-
def initialize
|
8
|
-
token = ENV['CROWD_TRANSLATE_API_TOKEN']
|
9
|
-
raise("You must define CROWD_TRANSLATE_API_TOKEN in order to talk to Crowd Translate") unless token.present?
|
10
|
-
|
11
|
-
server = ENV['CROWD_TRANSLATE_SERVER'] || 'https://crowd-translate.herokuapp.com'
|
12
|
-
@faraday = Faraday.new(
|
13
|
-
url: "#{server}/api/v1",
|
14
|
-
headers: { 'X-CrowdTranslateApiToken' => token },
|
15
|
-
)
|
16
|
-
end
|
17
|
-
|
18
|
-
def sync_migrations(migrations)
|
19
|
-
local_versions = migrations.all_versions
|
20
|
-
remote_versions = JSON.parse(get('migrations.json'))
|
21
|
-
|
22
|
-
if (extra_versions = remote_versions - local_versions).present?
|
23
|
-
raise("You may not upload migrations to the server because it has migrations not found locally: " +
|
24
|
-
"#{extra_versions.join(', ')}")
|
25
|
-
end
|
26
|
-
|
27
|
-
if (versions_to_add = local_versions - remote_versions).present?
|
28
|
-
versions_to_add.each do |version|
|
29
|
-
begin
|
30
|
-
put("migrations/#{version}.json",
|
31
|
-
migration: { ruby_file: migrations.get_migration(version: version) })
|
32
|
-
rescue
|
33
|
-
puts "There was an error updating migration:".red
|
34
|
-
puts " #{migrations.migration_file(version: version)}".bold
|
35
|
-
raise
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def play_all_migrations
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
|
-
def get_locale_file(locale_code)
|
46
|
-
get("locales/#{locale_code}.yml")
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def get(path)
|
52
|
-
puts "GET #{path}".bold
|
53
|
-
parse_response @faraday.get path
|
54
|
-
end
|
55
|
-
|
56
|
-
def put(path, params = {})
|
57
|
-
puts "PUT #{path} #{params.to_s[0..50]}#{'...' if params.to_s.length > 50}".bold
|
58
|
-
parse_response @faraday.put path, params
|
59
|
-
end
|
60
|
-
|
61
|
-
def parse_response(response)
|
62
|
-
if response.success?
|
63
|
-
response.body
|
64
|
-
else
|
65
|
-
error = begin
|
66
|
-
JSON.parse(response.body)['error']
|
67
|
-
rescue
|
68
|
-
response.body
|
69
|
-
end
|
70
|
-
raise error
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
require 'google_drive'
|
2
|
-
|
3
|
-
module I18n
|
4
|
-
module Migrations
|
5
|
-
class GoogleSpreadsheet
|
6
|
-
attr_reader :sheet
|
7
|
-
|
8
|
-
def initialize(locale, spreadsheet_url, key_path)
|
9
|
-
@session = GoogleDrive::Session.from_service_account_key(key_path)
|
10
|
-
|
11
|
-
url = spreadsheet_url || raise("Can't find google spreadsheet for #{locale}")
|
12
|
-
@spreadsheet = @session.spreadsheet_by_url(url)
|
13
|
-
@sheet = sheet_for("Sheet1")
|
14
|
-
end
|
15
|
-
|
16
|
-
def sheet_for(name)
|
17
|
-
@spreadsheet.worksheet_by_title(name) || raise("couldn't find worksheet for #{name}")
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|