c11n 0.0.1
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 +7 -0
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +52 -0
- data/Rakefile +6 -0
- data/bin/c11n +22 -0
- data/c11n.gemspec +25 -0
- data/lib/c11n.rb +8 -0
- data/lib/c11n/configuration.rb +72 -0
- data/lib/c11n/conversion/composed_key_deserializer.rb +37 -0
- data/lib/c11n/conversion/plain_deserializer.rb +21 -0
- data/lib/c11n/conversion/serializer.rb +51 -0
- data/lib/c11n/executable/runner.rb +43 -0
- data/lib/c11n/exporter/android.rb +41 -0
- data/lib/c11n/exporter/google_drive.rb +40 -0
- data/lib/c11n/exporter/ios.rb +21 -0
- data/lib/c11n/exporter/yaml.rb +26 -0
- data/lib/c11n/external/google_drive_driver.rb +64 -0
- data/lib/c11n/importer/android.rb +41 -0
- data/lib/c11n/importer/google_drive.rb +47 -0
- data/lib/c11n/importer/ios.rb +36 -0
- data/lib/c11n/importer/yaml.rb +42 -0
- data/lib/c11n/synchronizer.rb +58 -0
- data/lib/c11n/synchronizer/android.rb +50 -0
- data/lib/c11n/synchronizer/ios.rb +44 -0
- data/lib/c11n/synchronizer/rails.rb +41 -0
- data/lib/c11n/table.rb +131 -0
- data/lib/c11n/translations.rb +49 -0
- data/lib/c11n/types.rb +6 -0
- data/lib/c11n/version.rb +3 -0
- data/spec/c11n/configuration_spec.rb +61 -0
- data/spec/c11n/conversion/composed_key_deserializer_spec.rb +31 -0
- data/spec/c11n/conversion/serializer_spec.rb +32 -0
- data/spec/c11n/table_spec.rb +18 -0
- data/spec/c11n/translations_spec.rb +41 -0
- data/spec/spec_helper.rb +5 -0
- metadata +145 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'c11n/translations'
|
2
|
+
require 'c11n/importer/yaml'
|
3
|
+
require 'c11n/exporter/yaml'
|
4
|
+
|
5
|
+
module C11n
|
6
|
+
class Synchronizer
|
7
|
+
class Rails
|
8
|
+
def initialize(options = {})
|
9
|
+
@project_root = options[:root]
|
10
|
+
end
|
11
|
+
|
12
|
+
def importers
|
13
|
+
@importers ||= Hash[localization_files.map do |locale, file_path|
|
14
|
+
[locale, C11n::Importer::Yaml.new(path: file_path)]
|
15
|
+
end]
|
16
|
+
end
|
17
|
+
|
18
|
+
def exporters
|
19
|
+
@exporters ||= Hash[localization_files.map do |locale, file_path|
|
20
|
+
[locale, C11n::Exporter::Yaml.new(path: file_path)]
|
21
|
+
end]
|
22
|
+
end
|
23
|
+
|
24
|
+
def localization_files
|
25
|
+
Dir.new(locales_parent_directory_path).entries.select { |entry| entry =~ /\.yml$/ }.inject({}) do |files, entry|
|
26
|
+
files.merge locale_for(entry) => File.join(locales_parent_directory_path, entry)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def locales_parent_directory_path
|
31
|
+
File.join(@project_root, 'config/locales')
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def locale_for(localization_file)
|
37
|
+
localization_file.gsub(/\.yml$/, '').to_sym
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/c11n/table.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'c11n/conversion/plain_deserializer'
|
2
|
+
|
3
|
+
module C11n
|
4
|
+
# Translations in tabular form. The schema of translations table must match
|
5
|
+
# to the schema specified below:
|
6
|
+
#
|
7
|
+
# 1. If category information exists
|
8
|
+
#
|
9
|
+
# [Category] [Key] [Locale 1] [Locale 2] ... [Locale N]
|
10
|
+
#
|
11
|
+
# 2. If category information does not exist
|
12
|
+
#
|
13
|
+
# [Key] [Locale 1] [Locale 2] ... [Locale N]
|
14
|
+
#
|
15
|
+
# Columns composing the schema must appear on the first row of the sheet.
|
16
|
+
class Table
|
17
|
+
CATEGORY_COLUMN = 'Category'.freeze
|
18
|
+
TYPE_COLUMN = 'Type'.freeze
|
19
|
+
KEY_COLUMN = 'Key'.freeze
|
20
|
+
|
21
|
+
def initialize(raw_table, options = {})
|
22
|
+
@raw_table = raw_table
|
23
|
+
@deserializer_class = options[:deserializer_class] || C11n::Conversion::PlainDeserializer
|
24
|
+
@categories = {}
|
25
|
+
@types = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns key-value mappings for specified locale as an array
|
29
|
+
def table_for(locale)
|
30
|
+
@raw_table[1..-1].map do |columns|
|
31
|
+
if columns
|
32
|
+
key = key_column_from(columns)
|
33
|
+
translation = translation_column_from(columns, locale) || ''
|
34
|
+
|
35
|
+
key ? [key, translation] : nil
|
36
|
+
else
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
end.compact
|
40
|
+
end
|
41
|
+
|
42
|
+
def schema
|
43
|
+
@raw_table[0]
|
44
|
+
end
|
45
|
+
|
46
|
+
def locales
|
47
|
+
has_categories? ? schema[2..-1] : schema[1..-1]
|
48
|
+
end
|
49
|
+
|
50
|
+
def categories
|
51
|
+
{}
|
52
|
+
end
|
53
|
+
|
54
|
+
def types
|
55
|
+
if has_types?
|
56
|
+
@types = @raw_table[1..-1].inject({}) do |types, columns|
|
57
|
+
key = columns[key_column_index]
|
58
|
+
type = columns[type_index]
|
59
|
+
|
60
|
+
types.merge(key => type) if type
|
61
|
+
end
|
62
|
+
else
|
63
|
+
{}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_hash
|
68
|
+
Hash[locales.map { |locale| [locale.to_sym, @deserializer_class.new(table_for(locale)).deserialize] }]
|
69
|
+
end
|
70
|
+
|
71
|
+
def rows
|
72
|
+
@raw_table
|
73
|
+
end
|
74
|
+
|
75
|
+
def set(locale, key, translation, options = {})
|
76
|
+
unless locales.map(&:to_s).map(&:downcase).include? locale.to_s.downcase
|
77
|
+
schema[schema.length] = locale
|
78
|
+
end
|
79
|
+
|
80
|
+
row_with_key(key)[locale_index_of(locale)] = translation
|
81
|
+
row_with_key(key)[category_index] = options[:category] if has_categories? && options[:category]
|
82
|
+
row_with_key(key)[type_index] = options[:type] if has_types? && options[:type]
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def key_column_from(columns)
|
88
|
+
columns[key_column_index]
|
89
|
+
end
|
90
|
+
|
91
|
+
def key_column_index
|
92
|
+
schema.map(&:downcase).index(KEY_COLUMN.downcase)
|
93
|
+
end
|
94
|
+
|
95
|
+
def translation_column_from(columns, locale)
|
96
|
+
columns[locale_index_of(locale)]
|
97
|
+
end
|
98
|
+
|
99
|
+
def locale_index_of(locale)
|
100
|
+
schema.map(&:downcase).index(locale.to_s.downcase)
|
101
|
+
end
|
102
|
+
|
103
|
+
def category_index
|
104
|
+
schema.map(&:downcase).index(CATEGORY_COLUMN.downcase)
|
105
|
+
end
|
106
|
+
|
107
|
+
def type_index
|
108
|
+
schema.map(&:downcase).index(TYPE_COLUMN.downcase)
|
109
|
+
end
|
110
|
+
|
111
|
+
def has_categories?
|
112
|
+
schema.map(&:downcase).include?(CATEGORY_COLUMN.downcase)
|
113
|
+
end
|
114
|
+
|
115
|
+
def has_types?
|
116
|
+
schema.map(&:downcase).include?(TYPE_COLUMN.downcase)
|
117
|
+
end
|
118
|
+
|
119
|
+
def row_with_key(key)
|
120
|
+
@raw_table[1..-1].detect do |row|
|
121
|
+
row[key_column_index].to_s == key.to_s
|
122
|
+
end || @raw_table[@raw_table.length] = new_row_with_key(key)
|
123
|
+
end
|
124
|
+
|
125
|
+
def new_row_with_key(key)
|
126
|
+
[].tap do |row|
|
127
|
+
row[key_column_index] = key
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'c11n/conversion/composed_key_deserializer'
|
2
|
+
|
3
|
+
module C11n
|
4
|
+
class Translations
|
5
|
+
attr_reader :categories, :types
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@translations = {}
|
9
|
+
@deserializer_class = options[:deserializer_class] || C11n::Conversion::ComposedKeyDeserializer
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_translation(locale, key, value)
|
13
|
+
translations_for(locale.to_sym)[key] = value
|
14
|
+
end
|
15
|
+
|
16
|
+
def translation(locale, key)
|
17
|
+
translations_for(locale.to_sym)[key]
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_translations(locale, translations)
|
21
|
+
@translations[locale.to_sym] = translations
|
22
|
+
end
|
23
|
+
|
24
|
+
def import_with(importer, given_locale = nil)
|
25
|
+
importer.import.each do |locale, imported|
|
26
|
+
next if given_locale && given_locale.to_sym != locale.to_sym
|
27
|
+
|
28
|
+
add_translations(locale, imported)
|
29
|
+
end
|
30
|
+
|
31
|
+
@categories = importer.categories
|
32
|
+
@types = importer.types
|
33
|
+
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def export_with(exporter, locale)
|
38
|
+
exporter.export(self, locale)
|
39
|
+
end
|
40
|
+
|
41
|
+
def translations_for(locale)
|
42
|
+
@translations[locale.to_sym] ||= {}
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_hash
|
46
|
+
@translations
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/c11n/types.rb
ADDED
data/lib/c11n/version.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe C11n::Configuration do
|
4
|
+
let(:configuration) { C11n::Configuration.new }
|
5
|
+
|
6
|
+
describe '#method_missing' do
|
7
|
+
it { expect { configuration.some_key = 'value' }.not_to raise_error }
|
8
|
+
|
9
|
+
context 'when a setter method is invoked before' do
|
10
|
+
let(:value) { 'value' }
|
11
|
+
before { configuration.some_key = value }
|
12
|
+
|
13
|
+
it { expect(configuration.configurations[:some_key]).to eq(value) }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when a getter method is invoked' do
|
17
|
+
context 'when configurations has an exact match' do
|
18
|
+
let(:value) { 'configuration value' }
|
19
|
+
before { configuration.configurations[:some_key] = value }
|
20
|
+
|
21
|
+
it { expect(configuration.some_key).to eq(value) }
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when configurations does not have an exact match' do
|
25
|
+
it { expect { configuration.some_key }.to raise_error(NoMethodError) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#external' do
|
31
|
+
context 'when it is invoked with a block' do
|
32
|
+
it { expect(configuration.external(:google_drive) { |config| config.some = 'thing' }).to be_kind_of(C11n::Configuration) }
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when it is invoked without a block' do
|
36
|
+
context 'when an external service is configured before' do
|
37
|
+
before { configuration.external(:google_drive) { |config| config.some = 'thing' } }
|
38
|
+
|
39
|
+
it { expect(configuration.externals[:google_drive]).not_to be_nil }
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when no external service with matching name is configured before' do
|
43
|
+
it { expect { configuration.external(:google_drive) }.to raise_error(C11n::Configuration::NotConfigured) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#load_from_hash' do
|
49
|
+
let(:google_config) { { other: 'things' } }
|
50
|
+
let(:config_hash) { { some: 'thing', external: { google: google_config } } }
|
51
|
+
|
52
|
+
it { expect { configuration.load_from_hash(config_hash) }.not_to raise_error }
|
53
|
+
|
54
|
+
context 'when it is loaded' do
|
55
|
+
before { configuration.load_from_hash(config_hash) }
|
56
|
+
|
57
|
+
it { expect(configuration.some).to eq('thing') }
|
58
|
+
it { expect(configuration.external(:google).to_hash).to eq(google_config) }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe C11n::Conversion::ComposedKeyDeserializer do
|
6
|
+
describe '#deserialize' do
|
7
|
+
let(:source) { [['general.title', '너말고 니친구'], ['views.confirmations.title', '너말고 니친구 메일 인증'], ['views.confirmations.send', '확인 메일 다시 받기'], ['views.passwords.title', '패스워드 리셋하기']] }
|
8
|
+
let(:result) { { general: { title: '너말고 니친구' }, views: { confirmations: { title: '너말고 니친구 메일 인증', send: '확인 메일 다시 받기' }, passwords: { title: '패스워드 리셋하기' } } } }
|
9
|
+
let(:deserializer) { C11n::Conversion::ComposedKeyDeserializer.new(source) }
|
10
|
+
|
11
|
+
it { expect { deserializer.deserialize }.not_to raise_error }
|
12
|
+
it { expect(deserializer.deserialize).to eq(result) }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#path_for' do
|
16
|
+
let(:path) { 'views.confirmations.title' }
|
17
|
+
let(:deserializer) { C11n::Conversion::ComposedKeyDeserializer.new([]) }
|
18
|
+
|
19
|
+
it { expect(deserializer.send(:path_for, path)).to eq([:views, :confirmations, :title]) }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#create_or_get_leaf_node_for' do
|
23
|
+
let(:path) { [:views, :confirmations, :title] }
|
24
|
+
let(:deserializer) { C11n::Conversion::ComposedKeyDeserializer.new([]) }
|
25
|
+
|
26
|
+
before { deserializer.create_or_get_leaf_node_for(path) }
|
27
|
+
|
28
|
+
it { expect(deserializer.translations[:views]).not_to be_nil }
|
29
|
+
it { expect(deserializer.translations[:views][:confirmations]).not_to be_nil }
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe C11n::Conversion::Serializer do
|
6
|
+
describe '#serialize' do
|
7
|
+
let(:source) { { general: { title: '너말고 니친구' }, views: { confirmations: { title: '너말고 니친구 메일 인증', send: '확인 메일 다시 받기' }, passwords: { title: '패스워드 리셋하기' } } } }
|
8
|
+
let(:result) { { 'general.title' => '너말고 니친구', 'views.confirmations.title' => '너말고 니친구 메일 인증', 'views.confirmations.send' => '확인 메일 다시 받기', 'views.passwords.title' => '패스워드 리셋하기' } }
|
9
|
+
let(:serializer) { C11n::Conversion::Serializer.new(source) }
|
10
|
+
|
11
|
+
it { expect(serializer.serialize).to eq(result) }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#serialized_translations_for' do
|
15
|
+
let(:prefix) { 'prefix' }
|
16
|
+
let(:serializer) { C11n::Conversion::Serializer.new([]) }
|
17
|
+
|
18
|
+
context 'when depth of recursion is 0' do
|
19
|
+
let(:translations) { { hello: 'Hello', world: 'World' } }
|
20
|
+
let(:result) { [C11n::Conversion::Serializer::Pair.new('prefix.hello', 'Hello'), C11n::Conversion::Serializer::Pair.new('prefix.world', 'World')] }
|
21
|
+
|
22
|
+
it { expect(serializer.send(:serialized_translations_for, prefix, translations)).to eq(result) }
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when depth of recursion is larger than 0' do
|
26
|
+
let(:translations) { { recursive: { hello: 'Hello', world: 'World' } } }
|
27
|
+
let(:result) { [C11n::Conversion::Serializer::Pair.new('prefix.recursive.hello', 'Hello'), C11n::Conversion::Serializer::Pair.new('prefix.recursive.world', 'World')] }
|
28
|
+
|
29
|
+
it { expect(serializer.send(:serialized_translations_for, prefix, translations)).to eq(result) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe C11n::Table do
|
4
|
+
let(:raw_table) do
|
5
|
+
[
|
6
|
+
['Key', 'ko', 'en'],
|
7
|
+
['attribute_a', 'korean_a', 'english_a'],
|
8
|
+
['attribute_b', 'korean_b', 'english_b']
|
9
|
+
]
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:table) { C11n::Table.new(raw_table) }
|
13
|
+
|
14
|
+
describe '#table_for' do
|
15
|
+
it { expect(table.table_for(:ko)).to eq([['attribute_a', 'korean_a'], ['attribute_b', 'korean_b']]) }
|
16
|
+
it { expect(table.table_for(:en)).to eq([['attribute_a', 'english_a'], ['attribute_b', 'english_b']]) }
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe C11n::Translations do
|
4
|
+
let(:translations) { C11n::Translations.new }
|
5
|
+
let(:translations_hash) { translations.to_hash }
|
6
|
+
|
7
|
+
describe '#translations_for' do
|
8
|
+
it { expect(translations.translations_for(:en)).not_to be_nil }
|
9
|
+
it { expect(translations.translations_for(:en)).to be_empty }
|
10
|
+
it { expect(translations.translations_for(:en)).to eq({}) }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#add_translation' do
|
14
|
+
let(:key) { 'attribute_a' }
|
15
|
+
let(:value) { 'a' }
|
16
|
+
before { translations.add_translation(:en, key, value) }
|
17
|
+
|
18
|
+
it { expect(translations_hash[:en][key]).to eq(value) }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#add_translations' do
|
22
|
+
let(:raw_translations) { { 'attribute_a' => 'a', 'attribute_b' => 'b' } }
|
23
|
+
|
24
|
+
before { translations.add_translations(:en, raw_translations) }
|
25
|
+
|
26
|
+
it { expect(translations_hash[:en]).to eq(raw_translations) }
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#import_with' do
|
30
|
+
let(:raw_translations) { { 'attribute_a' => 'a', 'attribute_b' => 'b' } }
|
31
|
+
let(:mock_importer) { double(import: { en: raw_translations }, categories: {}, types: {}) }
|
32
|
+
|
33
|
+
it { expect { translations.import_with(mock_importer) }.not_to raise_error }
|
34
|
+
|
35
|
+
context 'when it is done before' do
|
36
|
+
before { translations.import_with(mock_importer) }
|
37
|
+
|
38
|
+
it { expect(translations_hash[:en]).to eq(raw_translations) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: c11n
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Inbeom Hwang
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: google_drive
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: nokogiri
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Imports/exports i18n translations from/to Google Drive Spreadsheet for
|
70
|
+
easier collaboration.
|
71
|
+
email:
|
72
|
+
- hwanginbeom@gmail.com
|
73
|
+
executables:
|
74
|
+
- c11n
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- .gitignore
|
79
|
+
- .rspec
|
80
|
+
- Gemfile
|
81
|
+
- LICENSE.txt
|
82
|
+
- README.md
|
83
|
+
- Rakefile
|
84
|
+
- bin/c11n
|
85
|
+
- c11n.gemspec
|
86
|
+
- lib/c11n.rb
|
87
|
+
- lib/c11n/configuration.rb
|
88
|
+
- lib/c11n/conversion/composed_key_deserializer.rb
|
89
|
+
- lib/c11n/conversion/plain_deserializer.rb
|
90
|
+
- lib/c11n/conversion/serializer.rb
|
91
|
+
- lib/c11n/executable/runner.rb
|
92
|
+
- lib/c11n/exporter/android.rb
|
93
|
+
- lib/c11n/exporter/google_drive.rb
|
94
|
+
- lib/c11n/exporter/ios.rb
|
95
|
+
- lib/c11n/exporter/yaml.rb
|
96
|
+
- lib/c11n/external/google_drive_driver.rb
|
97
|
+
- lib/c11n/importer/android.rb
|
98
|
+
- lib/c11n/importer/google_drive.rb
|
99
|
+
- lib/c11n/importer/ios.rb
|
100
|
+
- lib/c11n/importer/yaml.rb
|
101
|
+
- lib/c11n/synchronizer.rb
|
102
|
+
- lib/c11n/synchronizer/android.rb
|
103
|
+
- lib/c11n/synchronizer/ios.rb
|
104
|
+
- lib/c11n/synchronizer/rails.rb
|
105
|
+
- lib/c11n/table.rb
|
106
|
+
- lib/c11n/translations.rb
|
107
|
+
- lib/c11n/types.rb
|
108
|
+
- lib/c11n/version.rb
|
109
|
+
- spec/c11n/configuration_spec.rb
|
110
|
+
- spec/c11n/conversion/composed_key_deserializer_spec.rb
|
111
|
+
- spec/c11n/conversion/serializer_spec.rb
|
112
|
+
- spec/c11n/table_spec.rb
|
113
|
+
- spec/c11n/translations_spec.rb
|
114
|
+
- spec/spec_helper.rb
|
115
|
+
homepage: ''
|
116
|
+
licenses: []
|
117
|
+
metadata: {}
|
118
|
+
post_install_message:
|
119
|
+
rdoc_options: []
|
120
|
+
require_paths:
|
121
|
+
- lib
|
122
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
requirements: []
|
133
|
+
rubyforge_project:
|
134
|
+
rubygems_version: 2.0.6
|
135
|
+
signing_key:
|
136
|
+
specification_version: 4
|
137
|
+
summary: Manage i18n for your projects using Google Drive.
|
138
|
+
test_files:
|
139
|
+
- spec/c11n/configuration_spec.rb
|
140
|
+
- spec/c11n/conversion/composed_key_deserializer_spec.rb
|
141
|
+
- spec/c11n/conversion/serializer_spec.rb
|
142
|
+
- spec/c11n/table_spec.rb
|
143
|
+
- spec/c11n/translations_spec.rb
|
144
|
+
- spec/spec_helper.rb
|
145
|
+
has_rdoc:
|