i18n-migrations 1.1.6 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|