c11n 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|