i18n_generator 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/Gemfile +10 -0
- data/Gemfile.lock +64 -0
- data/LICENSE.txt +22 -0
- data/README.rdoc +34 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/bin/i18n_generator +10 -0
- data/examples/example_labels.xlsx +0 -0
- data/i18n_generator.gemspec +70 -0
- data/i18n_generator.rb +17 -0
- data/lib/i18n_generator/excel_parser.rb +69 -0
- data/lib/i18n_generator/label.rb +30 -0
- data/lib/i18n_generator/label_writer.rb +78 -0
- data/lib/i18n_generator.rb +15 -0
- data/test/excel_parser_test.rb +18 -0
- data/test/helper.rb +14 -0
- data/test/label_test.rb +81 -0
- data/test/label_writer_test.rb +49 -0
- metadata +135 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 772f9f32d17277d30dc3aa1e4298e1977a75109c
|
|
4
|
+
data.tar.gz: 0c2f3605bbea977f1512721544e7db23b6f27acb
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 935201dd79cf72add33ed59b42cd36b2764c9392761ab43e9468b4c8a1cf0c50a6d9caec967f443c7cf9e1aa373c7c765a049682f78c2df8b5684a01e5967123
|
|
7
|
+
data.tar.gz: 618ed8c7bea2e8d83e569d757c898f46ffc7b0dba4e56853a92cde69fb7783e3dae50cf644355e559d745f56c3613edcc27651f25569e1bcfe39b756d67fc2bb
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
GEM
|
|
2
|
+
remote: http://rubygems.org/
|
|
3
|
+
specs:
|
|
4
|
+
addressable (2.3.5)
|
|
5
|
+
builder (3.2.2)
|
|
6
|
+
faraday (0.8.8)
|
|
7
|
+
multipart-post (~> 1.2.0)
|
|
8
|
+
git (1.2.5)
|
|
9
|
+
github_api (0.10.1)
|
|
10
|
+
addressable
|
|
11
|
+
faraday (~> 0.8.1)
|
|
12
|
+
hashie (>= 1.2)
|
|
13
|
+
multi_json (~> 1.4)
|
|
14
|
+
nokogiri (~> 1.5.2)
|
|
15
|
+
oauth2
|
|
16
|
+
hashie (2.0.5)
|
|
17
|
+
highline (1.6.19)
|
|
18
|
+
httpauth (0.2.0)
|
|
19
|
+
jeweler (1.8.6)
|
|
20
|
+
builder
|
|
21
|
+
bundler (~> 1.0)
|
|
22
|
+
git (>= 1.2.5)
|
|
23
|
+
github_api (= 0.10.1)
|
|
24
|
+
highline (>= 1.6.15)
|
|
25
|
+
nokogiri (= 1.5.10)
|
|
26
|
+
rake
|
|
27
|
+
rdoc
|
|
28
|
+
json (1.8.0)
|
|
29
|
+
jwt (0.1.8)
|
|
30
|
+
multi_json (>= 1.5)
|
|
31
|
+
minitest (5.0.6)
|
|
32
|
+
multi_json (1.7.8)
|
|
33
|
+
multi_xml (0.5.5)
|
|
34
|
+
multipart-post (1.2.0)
|
|
35
|
+
nokogiri (1.5.10)
|
|
36
|
+
oauth2 (0.9.2)
|
|
37
|
+
faraday (~> 0.8)
|
|
38
|
+
httpauth (~> 0.2)
|
|
39
|
+
jwt (~> 0.1.4)
|
|
40
|
+
multi_json (~> 1.0)
|
|
41
|
+
multi_xml (~> 0.5)
|
|
42
|
+
rack (~> 1.2)
|
|
43
|
+
rack (1.5.2)
|
|
44
|
+
rake (10.1.0)
|
|
45
|
+
rdoc (3.12.2)
|
|
46
|
+
json (~> 1.4)
|
|
47
|
+
roo (1.11.2)
|
|
48
|
+
nokogiri
|
|
49
|
+
rubyzip
|
|
50
|
+
spreadsheet (> 0.6.4)
|
|
51
|
+
ruby-ole (1.2.11.7)
|
|
52
|
+
rubyzip (0.9.9)
|
|
53
|
+
spreadsheet (0.8.8)
|
|
54
|
+
ruby-ole (>= 1.0)
|
|
55
|
+
|
|
56
|
+
PLATFORMS
|
|
57
|
+
ruby
|
|
58
|
+
|
|
59
|
+
DEPENDENCIES
|
|
60
|
+
bundler (~> 1.3.5)
|
|
61
|
+
jeweler (~> 1.8.4)
|
|
62
|
+
minitest (~> 5.0.6)
|
|
63
|
+
rdoc (~> 3.12)
|
|
64
|
+
roo (~> 1.11.2)
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2013 Rule Financial
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
### i18n_generator
|
|
2
|
+
|
|
3
|
+
Generates locale-specific resource bundles (.properties) from an Excel spreadsheet containing translations.
|
|
4
|
+
`ruby i18n_generator.rb </path/to/spreadsheet> </output_directory>`
|
|
5
|
+
|
|
6
|
+
#### How to run
|
|
7
|
+
|
|
8
|
+
1. `bundle install`
|
|
9
|
+
1. `ruby i18n_generator.rb </path/to/spreadsheet> </output_directory>`
|
|
10
|
+
|
|
11
|
+
### Spreadsheet format
|
|
12
|
+
|
|
13
|
+
i18n_generator expects a translation spreadsheet which meets the criteria below; an example can be found [here](/test/example_labels.xlsx).
|
|
14
|
+
|
|
15
|
+
Label (required) | Description (optional) | en (required) | fr | de
|
|
16
|
+
--- | --- | --- | --- | --- |
|
|
17
|
+
*label.message.hello* | *Some useful translation context* | *Hello* | | Guten tag
|
|
18
|
+
|
|
19
|
+
- The first two columns are the key and optional description
|
|
20
|
+
- Translations appear in columns to the right of the key and description
|
|
21
|
+
- The 'en' translation must be present for all labels
|
|
22
|
+
- If no value is present for a locale, the default ('en') locale's value will be used
|
|
23
|
+
|
|
24
|
+
### Compatibility
|
|
25
|
+
|
|
26
|
+
Tested on:
|
|
27
|
+
|
|
28
|
+
- OSX 10.8.4, Ruby 2.0.0p0
|
|
29
|
+
- Windows 7 Professional, Ruby 1.9.3p448
|
|
30
|
+
|
|
31
|
+
### Copyright
|
|
32
|
+
|
|
33
|
+
Copyright (c) 2013 Rule Financial. See LICENSE.txt for
|
|
34
|
+
further details.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'bundler'
|
|
5
|
+
begin
|
|
6
|
+
Bundler.setup(:default, :development)
|
|
7
|
+
rescue Bundler::BundlerError => e
|
|
8
|
+
$stderr.puts e.message
|
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
|
10
|
+
exit e.status_code
|
|
11
|
+
end
|
|
12
|
+
require 'rake'
|
|
13
|
+
|
|
14
|
+
require 'jeweler'
|
|
15
|
+
Jeweler::Tasks.new do |gem|
|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
|
17
|
+
gem.name = "i18n_generator"
|
|
18
|
+
gem.homepage = "http://github.com/rulefinancial/i18n_generator"
|
|
19
|
+
gem.license = "MIT"
|
|
20
|
+
gem.summary = "Generates locale-specific resource bundles from Excel-based translations"
|
|
21
|
+
gem.description = "Generates locale-specific resource bundles (.properties files) from translations held in an Excel spreadsheet"
|
|
22
|
+
gem.email = "robyoung26@gmail.com"
|
|
23
|
+
gem.authors = ["Rob Young"]
|
|
24
|
+
# dependencies defined in Gemfile
|
|
25
|
+
end
|
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
|
27
|
+
|
|
28
|
+
require 'rake/testtask'
|
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
|
30
|
+
test.libs << 'lib' << 'test'
|
|
31
|
+
test.pattern = 'test/**/*_test.rb'
|
|
32
|
+
test.verbose = true
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
task :default => :test
|
|
36
|
+
|
|
37
|
+
require 'rdoc/task'
|
|
38
|
+
Rake::RDocTask.new do |rdoc|
|
|
39
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
|
40
|
+
|
|
41
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
42
|
+
rdoc.title = "i18n_generator #{version}"
|
|
43
|
+
rdoc.rdoc_files.include('README*')
|
|
44
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
45
|
+
end
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.0.1
|
data/bin/i18n_generator
ADDED
|
Binary file
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Generated by jeweler
|
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
|
4
|
+
# -*- encoding: utf-8 -*-
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |s|
|
|
7
|
+
s.name = "i18n_generator"
|
|
8
|
+
s.version = "0.0.1"
|
|
9
|
+
|
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
|
+
s.authors = ["Rob Young"]
|
|
12
|
+
s.date = "2013-08-07"
|
|
13
|
+
s.description = "Generates locale-specific resource bundles (.properties files) from translations held in an Excel spreadsheet"
|
|
14
|
+
s.email = "robyoung26@gmail.com"
|
|
15
|
+
s.executables = ["i18n_generator"]
|
|
16
|
+
s.extra_rdoc_files = [
|
|
17
|
+
"LICENSE.txt",
|
|
18
|
+
"README.rdoc"
|
|
19
|
+
]
|
|
20
|
+
s.files = [
|
|
21
|
+
"Gemfile",
|
|
22
|
+
"Gemfile.lock",
|
|
23
|
+
"LICENSE.txt",
|
|
24
|
+
"README.rdoc",
|
|
25
|
+
"Rakefile",
|
|
26
|
+
"VERSION",
|
|
27
|
+
"bin/i18n_generator",
|
|
28
|
+
"examples/example_labels.xlsx",
|
|
29
|
+
"i18n_generator.gemspec",
|
|
30
|
+
"i18n_generator.rb",
|
|
31
|
+
"lib/i18n_generator.rb",
|
|
32
|
+
"lib/i18n_generator/excel_parser.rb",
|
|
33
|
+
"lib/i18n_generator/label.rb",
|
|
34
|
+
"lib/i18n_generator/label_writer.rb",
|
|
35
|
+
"test/excel_parser_test.rb",
|
|
36
|
+
"test/helper.rb",
|
|
37
|
+
"test/label_test.rb",
|
|
38
|
+
"test/label_writer_test.rb"
|
|
39
|
+
]
|
|
40
|
+
s.homepage = "http://github.com/rulefinancial/i18n_generator"
|
|
41
|
+
s.licenses = ["MIT"]
|
|
42
|
+
s.require_paths = ["lib"]
|
|
43
|
+
s.rubygems_version = "2.0.3"
|
|
44
|
+
s.summary = "Generates locale-specific resource bundles from Excel-based translations"
|
|
45
|
+
|
|
46
|
+
if s.respond_to? :specification_version then
|
|
47
|
+
s.specification_version = 4
|
|
48
|
+
|
|
49
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
|
50
|
+
s.add_runtime_dependency(%q<roo>, ["~> 1.11.2"])
|
|
51
|
+
s.add_development_dependency(%q<minitest>, ["~> 5.0.6"])
|
|
52
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
|
53
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.3.5"])
|
|
54
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
|
55
|
+
else
|
|
56
|
+
s.add_dependency(%q<roo>, ["~> 1.11.2"])
|
|
57
|
+
s.add_dependency(%q<minitest>, ["~> 5.0.6"])
|
|
58
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
|
59
|
+
s.add_dependency(%q<bundler>, ["~> 1.3.5"])
|
|
60
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
|
61
|
+
end
|
|
62
|
+
else
|
|
63
|
+
s.add_dependency(%q<roo>, ["~> 1.11.2"])
|
|
64
|
+
s.add_dependency(%q<minitest>, ["~> 5.0.6"])
|
|
65
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
|
66
|
+
s.add_dependency(%q<bundler>, ["~> 1.3.5"])
|
|
67
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
data/i18n_generator.rb
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#!/usr/bin/env ruby
|
|
3
|
+
|
|
4
|
+
require_relative 'lib/label'
|
|
5
|
+
require_relative 'lib/excel_parser'
|
|
6
|
+
require_relative 'lib/label_writer'
|
|
7
|
+
|
|
8
|
+
unless ARGV.size == 2
|
|
9
|
+
puts "Usage : label_generator.rb <input.xlsx> </path/to/output/dir>"
|
|
10
|
+
exit
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
excel_parser = ExcelParser.new(ARGV[0])
|
|
14
|
+
label_writer = LabelWriter.new(ARGV[1])
|
|
15
|
+
|
|
16
|
+
labels = excel_parser.parse
|
|
17
|
+
label_writer.write_labels(labels, excel_parser.translation_languages)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'roo'
|
|
4
|
+
require 'i18n_generator/label'
|
|
5
|
+
|
|
6
|
+
module I18nGenerator
|
|
7
|
+
##
|
|
8
|
+
# Responsible for parsing Excel spreadsheet to an array of Label objects
|
|
9
|
+
# and inspecting a spreadsheet to return a list of included translations
|
|
10
|
+
class ExcelParser
|
|
11
|
+
|
|
12
|
+
FIRST_DATA_ROW_NUMBER = 2
|
|
13
|
+
FIRST_TRANSLATION_COLUMN = 3
|
|
14
|
+
|
|
15
|
+
LABEL_ID_COLUMN_INDEX = 1
|
|
16
|
+
LABEL_DESCRIPTION_COLUMN_INDEX= 2
|
|
17
|
+
|
|
18
|
+
def initialize(file_path)
|
|
19
|
+
raise 'Invalid path supplied to ExcelParser' unless file_path
|
|
20
|
+
|
|
21
|
+
begin
|
|
22
|
+
@excel_data = excel_sheet_from_path(file_path)
|
|
23
|
+
rescue Exception => e
|
|
24
|
+
raise "Error while creating excel data: #{e}"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
##
|
|
29
|
+
# Returns the appropraite Roo Excel object from a
|
|
30
|
+
# given path
|
|
31
|
+
def excel_sheet_from_path(file_path)
|
|
32
|
+
case File.extname(file_path)
|
|
33
|
+
when '.xls'
|
|
34
|
+
Roo::Excel.new(file_path)
|
|
35
|
+
when '.xlsx'
|
|
36
|
+
Roo::Excelx.new(file_path)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
# Parses the spreadsheet to a list of Labels
|
|
42
|
+
def parse
|
|
43
|
+
labels = [].tap do |labels_array|
|
|
44
|
+
params_hash = {}
|
|
45
|
+
|
|
46
|
+
FIRST_DATA_ROW_NUMBER.upto @excel_data.last_row do |row_num|
|
|
47
|
+
|
|
48
|
+
params_hash[:id] = @excel_data.cell(row_num, LABEL_ID_COLUMN_INDEX)
|
|
49
|
+
params_hash[:description] = @excel_data.cell(row_num, LABEL_DESCRIPTION_COLUMN_INDEX)
|
|
50
|
+
|
|
51
|
+
FIRST_TRANSLATION_COLUMN.upto @excel_data.last_column do |col_num|
|
|
52
|
+
params_hash[@excel_data.cell(FIRST_DATA_ROW_NUMBER-1, col_num).to_sym] = @excel_data.cell(row_num, col_num)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
labels_array << Label.new(params_hash)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
##
|
|
61
|
+
# Returns an array of symbols representing the translation languages
|
|
62
|
+
# contained in the Excel spreadsheet
|
|
63
|
+
def translation_languages
|
|
64
|
+
header_row = @excel_data.row(@excel_data.first_row)
|
|
65
|
+
header_row[FIRST_TRANSLATION_COLUMN-1,header_row.size].map(&:to_sym)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module I18nGenerator
|
|
4
|
+
##
|
|
5
|
+
# Represents a text item for translation
|
|
6
|
+
# Instantiated with a hash of parameters
|
|
7
|
+
# Validates required parameters are present on creation
|
|
8
|
+
# Creates class variables and accessors for supplied parameters
|
|
9
|
+
class Label
|
|
10
|
+
def initialize(params_hash)
|
|
11
|
+
validate_params(params_hash)
|
|
12
|
+
|
|
13
|
+
params_hash.each do |param, value|
|
|
14
|
+
instance_variable_set("@#{param}", value)
|
|
15
|
+
|
|
16
|
+
define_singleton_method param.to_sym do
|
|
17
|
+
instance_variable_get("@#{param}")
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# Ensures required parameters are present
|
|
24
|
+
def validate_params(params)
|
|
25
|
+
%w(id en).map(&:to_sym).each do |req_param|
|
|
26
|
+
raise "Label is missing required parameter [#{req_param}]" unless params[req_param] && !params[req_param].empty?
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'i18n_generator/label'
|
|
4
|
+
|
|
5
|
+
module I18nGenerator
|
|
6
|
+
##
|
|
7
|
+
# Responsible for processing a list of Labels for output
|
|
8
|
+
# and writing them to output files
|
|
9
|
+
class LabelWriter
|
|
10
|
+
|
|
11
|
+
FILENAME_PREFIX = "labels_"
|
|
12
|
+
|
|
13
|
+
FILE_HEADER_TEXT = <<-HEADER
|
|
14
|
+
# THIS FILE IS GENERATED - PLEASE DO NOT EDIT (https://github.com/rulefinancial/i18n_generator)
|
|
15
|
+
HEADER
|
|
16
|
+
|
|
17
|
+
def initialize(output_directory)
|
|
18
|
+
raise 'LabelWriter requires an output path' unless output_directory
|
|
19
|
+
@output_path = output_directory
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# Processes a list of Label with target languages
|
|
24
|
+
# Returns a hash keyed by language, containing the
|
|
25
|
+
# lines of the resource bundle to be written
|
|
26
|
+
def prepare_output(labels, languages)
|
|
27
|
+
output_files = Hash.new {|k,v| k[v] = [FILE_HEADER_TEXT]}
|
|
28
|
+
|
|
29
|
+
labels.each do |label|
|
|
30
|
+
languages.each do |language|
|
|
31
|
+
output_files[language] << content_for_label(label, language)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
output_files
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
##
|
|
38
|
+
# Orchestrates the processing of Labels to be written
|
|
39
|
+
# Writes files to output location
|
|
40
|
+
def write_labels(labels, languages)
|
|
41
|
+
output_files = prepare_output(labels, languages)
|
|
42
|
+
|
|
43
|
+
Dir.mkdir(@output_path) unless Dir.exists?(@output_path)
|
|
44
|
+
|
|
45
|
+
output_files.keys.each_with_index do |language, idx|
|
|
46
|
+
output_filename = File.join(@output_path,label_filename(language))
|
|
47
|
+
|
|
48
|
+
File.open(output_filename, 'w') do |file|
|
|
49
|
+
file.write(output_files[language].join("\n"))
|
|
50
|
+
puts "[#{idx+1}/#{output_files.size}] Generated [#{label_filename(language)}]"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
##
|
|
56
|
+
# Returns the content for a Label in a given language
|
|
57
|
+
# Description is included if present
|
|
58
|
+
def content_for_label(label, language)
|
|
59
|
+
content = []
|
|
60
|
+
content << "\# #{label.description}" if label.description
|
|
61
|
+
content << "#{label.id}=#{translation_for_label(label, language)}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
##
|
|
65
|
+
# Returns the translation for a label in a given language
|
|
66
|
+
# If the target language is not present, English will be used
|
|
67
|
+
def translation_for_label(label, language)
|
|
68
|
+
translation = label.send(language)
|
|
69
|
+
"#{translation && !translation.empty? ? translation : label.en}"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# Produces the filename for a resource bundle
|
|
74
|
+
def label_filename(language)
|
|
75
|
+
FILENAME_PREFIX + language.to_s + ".properties"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'i18n_generator/excel_parser'
|
|
2
|
+
require 'i18n_generator/label'
|
|
3
|
+
require 'i18n_generator/label_writer'
|
|
4
|
+
|
|
5
|
+
module I18nGenerator
|
|
6
|
+
class << self
|
|
7
|
+
def process(source_spreadsheet, output_directory)
|
|
8
|
+
excel_parser = I18nGenerator::ExcelParser.new(ARGV[0])
|
|
9
|
+
label_writer = I18nGenerator::LabelWriter.new(ARGV[1])
|
|
10
|
+
|
|
11
|
+
labels = excel_parser.parse
|
|
12
|
+
label_writer.write_labels(labels, excel_parser.translation_languages)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'helper'
|
|
4
|
+
|
|
5
|
+
class ExcelParserTest < Minitest::Test
|
|
6
|
+
def setup
|
|
7
|
+
@excel_parser = I18nGenerator::ExcelParser.new(File.join(File.dirname(__FILE__), "..", "examples", "example_labels.xlsx"))
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def test_not_null
|
|
11
|
+
refute_nil(@excel_parser)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_translation_languages
|
|
15
|
+
assert_equal(%w(en fr de ru jp gr).map(&:to_sym), @excel_parser.translation_languages,
|
|
16
|
+
"Excel Parser should return the correct translation languages")
|
|
17
|
+
end
|
|
18
|
+
end
|
data/test/helper.rb
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'bundler'
|
|
3
|
+
begin
|
|
4
|
+
Bundler.setup(:default, :development)
|
|
5
|
+
rescue Bundler::BundlerError => e
|
|
6
|
+
$stderr.puts e.message
|
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
|
8
|
+
exit e.status_code
|
|
9
|
+
end
|
|
10
|
+
require 'minitest/autorun'
|
|
11
|
+
|
|
12
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
13
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
14
|
+
require 'i18n_generator'
|
data/test/label_test.rb
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'helper'
|
|
4
|
+
|
|
5
|
+
class LabelTest < Minitest::Test
|
|
6
|
+
def setup
|
|
7
|
+
@valid_label = I18nGenerator::Label.new({
|
|
8
|
+
:id => "label.message.goodbye",
|
|
9
|
+
:description => "A friendly goodbye",
|
|
10
|
+
:en => "Goodbye",
|
|
11
|
+
:fr => "Au revoir",
|
|
12
|
+
:jp => "別れる時に発する語"
|
|
13
|
+
})
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_not_null
|
|
17
|
+
refute_nil(@valid_label, "A valid label should be instantiated successfully")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_missing_id
|
|
21
|
+
assert_raises(RuntimeError) do
|
|
22
|
+
I18nGenerator::Label.new({
|
|
23
|
+
:description => "A friendly goodbye",
|
|
24
|
+
:en => "Goodbye",
|
|
25
|
+
:fr => "Au revoir",
|
|
26
|
+
:jp => "別れる時に発する語"
|
|
27
|
+
})
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_blank_id
|
|
32
|
+
assert_raises(RuntimeError) do
|
|
33
|
+
I18nGenerator::Label.new({
|
|
34
|
+
:id => "",
|
|
35
|
+
:description => "A friendly goodbye",
|
|
36
|
+
:en => "Goodbye",
|
|
37
|
+
:fr => "Au revoir",
|
|
38
|
+
:jp => "別れる時に発する語"
|
|
39
|
+
})
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_missing_english_translation
|
|
44
|
+
assert_raises(RuntimeError) do
|
|
45
|
+
I18nGenerator::Label.new({
|
|
46
|
+
:id => "label.message.goodbye",
|
|
47
|
+
:description => "A friendly goodbye",
|
|
48
|
+
:fr => "Au revoir",
|
|
49
|
+
:jp => "別れる時に発する語"
|
|
50
|
+
})
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_blank_english_translation
|
|
55
|
+
assert_raises(RuntimeError) do
|
|
56
|
+
I18nGenerator::Label.new({
|
|
57
|
+
:id => "label.message.goodbye",
|
|
58
|
+
:description => "A friendly goodbye",
|
|
59
|
+
:en => "",
|
|
60
|
+
:fr => "Au revoir",
|
|
61
|
+
:jp => "別れる時に発する語"
|
|
62
|
+
})
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def test_id_assignment
|
|
67
|
+
assert_equal("label.message.goodbye", @valid_label.id)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_description_assignment
|
|
71
|
+
assert_equal("A friendly goodbye", @valid_label.description)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def test_english_assignment
|
|
75
|
+
assert_equal("Goodbye", @valid_label.en)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_jp_assignment
|
|
79
|
+
assert_equal("別れる時に発する語", @valid_label.jp)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'helper'
|
|
4
|
+
|
|
5
|
+
class LabelWriterTest < Minitest::Test
|
|
6
|
+
def setup
|
|
7
|
+
@label_writer = I18nGenerator::LabelWriter.new("output_path")
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def test_not_null
|
|
11
|
+
refute_nil(@label_writer)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_label_filename_generation
|
|
15
|
+
assert_equal(@label_writer.label_filename("en"), "labels_en.properties")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_present_translation
|
|
19
|
+
label = I18nGenerator::Label.new({
|
|
20
|
+
:id => "label.message.goodbye",
|
|
21
|
+
:description => "A friendly goodbye",
|
|
22
|
+
:en => "Goodbye",
|
|
23
|
+
:fr => "Au revoir",
|
|
24
|
+
:jp => "別れる時に発する語"
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
assert_equal(@label_writer.translation_for_label(label, "jp"),
|
|
28
|
+
"別れる時に発する語",
|
|
29
|
+
"Translation should be returned correctly when language is present")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_english_used_when_translation_not_present
|
|
33
|
+
label = I18nGenerator::Label.new({
|
|
34
|
+
:id => "label.message.goodbye",
|
|
35
|
+
:description => "A friendly goodbye",
|
|
36
|
+
:en => "Goodbye",
|
|
37
|
+
:fr => "",
|
|
38
|
+
:jp => ""
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
assert_equal(@label_writer.translation_for_label(label, "fr"),
|
|
42
|
+
"Goodbye",
|
|
43
|
+
"English translation should be used when target language is not present")
|
|
44
|
+
|
|
45
|
+
assert_equal(@label_writer.translation_for_label(label, "jp"),
|
|
46
|
+
"Goodbye",
|
|
47
|
+
"English translation should be used when target language is not present")
|
|
48
|
+
end
|
|
49
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: i18n_generator
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Rob Young
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2013-08-07 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: roo
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ~>
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 1.11.2
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ~>
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 1.11.2
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: minitest
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ~>
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 5.0.6
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ~>
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 5.0.6
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rdoc
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ~>
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3.12'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ~>
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '3.12'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: bundler
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ~>
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 1.3.5
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ~>
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: 1.3.5
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: jeweler
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ~>
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: 1.8.4
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ~>
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: 1.8.4
|
|
83
|
+
description: Generates locale-specific resource bundles (.properties files) from translations
|
|
84
|
+
held in an Excel spreadsheet
|
|
85
|
+
email: robyoung26@gmail.com
|
|
86
|
+
executables:
|
|
87
|
+
- i18n_generator
|
|
88
|
+
extensions: []
|
|
89
|
+
extra_rdoc_files:
|
|
90
|
+
- LICENSE.txt
|
|
91
|
+
- README.rdoc
|
|
92
|
+
files:
|
|
93
|
+
- Gemfile
|
|
94
|
+
- Gemfile.lock
|
|
95
|
+
- LICENSE.txt
|
|
96
|
+
- README.rdoc
|
|
97
|
+
- Rakefile
|
|
98
|
+
- VERSION
|
|
99
|
+
- bin/i18n_generator
|
|
100
|
+
- examples/example_labels.xlsx
|
|
101
|
+
- i18n_generator.gemspec
|
|
102
|
+
- i18n_generator.rb
|
|
103
|
+
- lib/i18n_generator.rb
|
|
104
|
+
- lib/i18n_generator/excel_parser.rb
|
|
105
|
+
- lib/i18n_generator/label.rb
|
|
106
|
+
- lib/i18n_generator/label_writer.rb
|
|
107
|
+
- test/excel_parser_test.rb
|
|
108
|
+
- test/helper.rb
|
|
109
|
+
- test/label_test.rb
|
|
110
|
+
- test/label_writer_test.rb
|
|
111
|
+
homepage: http://github.com/rulefinancial/i18n_generator
|
|
112
|
+
licenses:
|
|
113
|
+
- MIT
|
|
114
|
+
metadata: {}
|
|
115
|
+
post_install_message:
|
|
116
|
+
rdoc_options: []
|
|
117
|
+
require_paths:
|
|
118
|
+
- lib
|
|
119
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - '>='
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '0'
|
|
124
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
|
+
requirements:
|
|
126
|
+
- - '>='
|
|
127
|
+
- !ruby/object:Gem::Version
|
|
128
|
+
version: '0'
|
|
129
|
+
requirements: []
|
|
130
|
+
rubyforge_project:
|
|
131
|
+
rubygems_version: 2.0.3
|
|
132
|
+
signing_key:
|
|
133
|
+
specification_version: 4
|
|
134
|
+
summary: Generates locale-specific resource bundles from Excel-based translations
|
|
135
|
+
test_files: []
|