i18n_googledocs 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,60 @@
1
+
2
+ namespace :i18n do
3
+
4
+ desc "Find and list translation keys that do not exist in all locales"
5
+ task :missing_keys => :environment do
6
+ finder = LocalchI18n::MissingKeysFinder.new(I18n.backend)
7
+ finder.find_missing_keys
8
+ end
9
+
10
+ desc "Download translations from Google Spreadsheet and save them to YAML files."
11
+ task :import_translations => :environment do
12
+ raise "'Rails' not found! Tasks can only run within a Rails application!" if !defined?(Rails)
13
+
14
+ config_file = Rails.root.join('config', 'translations.yml')
15
+ raise "No config file 'config/translations.yml' found." if !File.exists?(config_file)
16
+
17
+ tmp_dir = Rails.root.join('tmp')
18
+
19
+ translations = LocalchI18n::Translations.new(config_file, tmp_dir)
20
+ translations.download_files
21
+ translations.store_translations
22
+ translations.clean_up
23
+
24
+ end
25
+
26
+ # http://stackoverflow.com/questions/1357639/rails-rake-how-to-pass-in-arguments-to-a-task-with-environment
27
+ desc "Export all language files to CSV files (only files contained in base folder are considered, default = en)"
28
+ task :export_translations, [:base] => :environment do |t, args|
29
+ raise "'Rails' not found! Tasks can only run within a Rails application!" if !defined?(Rails)
30
+
31
+ args.with_defaults(:base => 'en')
32
+
33
+ source_dir = Rails.root.join('config', 'locales')
34
+ output_dir = Rails.root.join('tmp')
35
+ locales = I18n.available_locales
36
+
37
+ input_files = Dir[File.join(source_dir, base_locale, '*.yml')]
38
+
39
+ puts ""
40
+ puts " Detected locales: #{locales}"
41
+ puts " Detected files:"
42
+ input_files.each {|f| puts " * #{File.basename(f)}" }
43
+
44
+ puts ""
45
+ puts " Start exporting files:"
46
+
47
+ input_files.each do |file|
48
+ file = File.basename(file)
49
+ exporter = LocalchI18n::TranslationFileExport.new(source_dir, file, output_dir, locales)
50
+ exporter.export
51
+ end
52
+
53
+ puts ""
54
+ puts " CSV files can be removed safely after uploading them manually to Google Spreadsheet."
55
+ puts ""
56
+ end
57
+
58
+ end
59
+
60
+
data/tasks/test.rake ADDED
@@ -0,0 +1,9 @@
1
+ require 'rake/testtask'
2
+
3
+ # Test::Unit Tests
4
+ Rake::TestTask.new(:test) do |test|
5
+ test.libs << 'lib' << 'test'
6
+ test.pattern = 'test/**/*_test.rb'
7
+ test.verbose = true
8
+ end
9
+
@@ -0,0 +1,9 @@
1
+ #
2
+ # Configure all spreadsheets you want to import:
3
+ #
4
+ # files:
5
+ # first.yml: http://www.google.com/spreadsheet/first.csv
6
+ # second.yml: http://www.google.com/spreadsheet/second.csv
7
+ #
8
+ files:
9
+ download.yml: "https://docs.google.com/spreadsheet/pub?key=0ApnemdIdiDXedEpiVFR1RkdWMDhnTTgtdzRJMWZMLUE&single=true&gid=0&output=csv"
@@ -0,0 +1,8 @@
1
+ de:
2
+ header:
3
+ search: Finden
4
+ phonebook: Telefonbuch
5
+ the_yellow_pages: Die Gelben Seiten
6
+ property: Immobilien
7
+ map: Karte
8
+ copyright: (c) local.ch
@@ -0,0 +1,8 @@
1
+ en:
2
+ header:
3
+ search: Find
4
+ phonebook: Phone Book
5
+ the_yellow_pages: The Yellow Pages
6
+ property: Property
7
+ map: Map
8
+ copyright: (c) local.ch
@@ -0,0 +1,24 @@
1
+ key,en,de
2
+ tel.browse_access_title,Largest cities,Grösste Städte
3
+ tel.browse_all_link,» Look-up all cities (A-Z),» Alle Orte A-Z
4
+ tel.extended.area_field_teaser,"",""
5
+ tel.extended.area_label,"Region, Canton","Region, Kanton"
6
+ tel.extended.city_field_teaser,"",""
7
+ tel.extended.city_label,"City, ZIP","Ort, PLZ"
8
+ tel.extended.company_field_teaser,"e.g. doctor, farmer","z.B. pizzaiolo, doktor"
9
+ tel.extended.company_label,Occupation,Beruf
10
+ tel.extended.name_field_teaser,"e.g. smith, phil*","z.B. meier, hans*"
11
+ tel.extended.name_label,"Name, First name","Name, Vorname"
12
+ tel.extended.phone_field_teaser,"",""
13
+ tel.extended.phone_label,Phone,Telefon
14
+ tel.extended.street_field_teaser,"",""
15
+ tel.extended.street_label,Street,Strasse
16
+ tel.homepage.meta.description,The official phone book for Switzerland by Swisscom Directories with over 6 million listings of private people and businesses in your vicinity.,Firmen und Privatpersonen in Ihrer Nähe einfach finden.
17
+ tel.homepage.meta.keywords,"phone book, city, Switzerland, directory, address, white pages","Telefonbuch, Schweiz, aktuell, Directories, Adresse"
18
+ tel.homepage.meta.title,Switzerland's official Phone Book by local.ch,Offizielles Telefonbuch der Schweiz von local.ch
19
+ tel.search_button,Find It,Finden
20
+ tel.search_for_people,Find names or numbers,Namen oder Nummern finden
21
+ tel.what_field_teaser,"e.g. Smith, Bar Odeon or 044 308 68 68","z.B. Müller, Bar Odeon oder 044 308 68 68"
22
+ tel.what_label,Who?,Wer?
23
+ tel.where_field_teaser,"e.g. Bern, 8004 or Hauptstrasse","z.B. Luzern, 5700 oder Bergstrasse"
24
+ tel.where_label,Where?,Wo?
@@ -0,0 +1,24 @@
1
+ key,en,de,fr,it
2
+ tel.browse_access_title,Largest cities,Grösste Städte,Villes Principales,Città principali
3
+ tel.browse_all_link,» Look-up all cities (A-Z),» Alle Orte A-Z,» Toutes les localités (A-Z),» Tutte le località A-Z
4
+ tel.extended.area_field_teaser,"","","",""
5
+ tel.extended.area_label,"Region, Canton","Region, Kanton","Région, Canton","Regione, Cantone"
6
+ tel.extended.city_field_teaser,"","","",""
7
+ tel.extended.city_label,"City, ZIP","Ort, PLZ","Localité, NPA","Località, Codice postale"
8
+ tel.extended.company_field_teaser,"e.g. doctor, farmer","z.B. pizzaiolo, doktor","par ex. médecin, agriculteur","per es. medico, agricoltore"
9
+ tel.extended.company_label,Occupation,Beruf,Profession,Professione
10
+ tel.extended.name_field_teaser,"e.g. smith, phil*","z.B. meier, hans*","par ex. berdoz, jean*","per es. rossi, robert*"
11
+ tel.extended.name_label,"Name, First name","Name, Vorname","Nom, Prénom","Cognome, Nome"
12
+ tel.extended.phone_field_teaser,"","","",""
13
+ tel.extended.phone_label,Phone,Telefon,Téléphone,Telefono
14
+ tel.extended.street_field_teaser,"","","",""
15
+ tel.extended.street_label,Street,Strasse,Rue,Via
16
+ tel.homepage.meta.description,The official phone book for Switzerland by Swisscom Directories with over 6 million listings of private people and businesses in your vicinity.,Firmen und Privatpersonen in Ihrer Nähe einfach finden.,Trouver simplement des entreprise et des personnes dans vos alentours.,Trovare con facilità privati ed aziende a voi vicine.
17
+ tel.homepage.meta.keywords,"phone book, city, Switzerland, directory, address, white pages","Telefonbuch, Schweiz, aktuell, Directories, Adresse","annuaire, Suisse, actuel, Directories, adresse","Elenco telefonico, Svizzera, attualità, Directories, indirizzo"
18
+ tel.homepage.meta.title,Switzerland's official Phone Book by local.ch,Offizielles Telefonbuch der Schweiz von local.ch,Annuaire téléphonique officiel sur local.ch,L’elenco telefonico della Svizzera su local.ch
19
+ tel.search_button,Find It,Finden,Trouver,Trovare
20
+ tel.search_for_people,Find names or numbers,Namen oder Nummern finden,Trouver un nom ou un numéro,Trova nomi e numeri
21
+ tel.what_field_teaser,"e.g. Smith, Bar Odeon or 044 308 68 68","z.B. Müller, Bar Odeon oder 044 308 68 68","par ex. Favre, Bar Cuba ou 044 308 68 68","per es. Rossi, Bar Incontro o 044 308 68 68"
22
+ tel.what_label,Who?,Wer?,Quoi ?,Cosa?
23
+ tel.where_field_teaser,"e.g. Bern, 8004 or Hauptstrasse","z.B. Luzern, 5700 oder Bergstrasse","par ex. Neuchâtel, 1630 ou rue de Tivoli","per es. Locarno, 6900 o via Molinazzo"
24
+ tel.where_label,Where?,Wo?,Où ?,Dove?
@@ -0,0 +1,26 @@
1
+ require 'test/unit'
2
+ require 'fileutils'
3
+ require 'localch-i18n'
4
+
5
+ module TestHelper
6
+
7
+ def fixture_path
8
+ File.join(File.expand_path(File.dirname(__FILE__)), 'fixtures')
9
+ end
10
+
11
+ def tmp_dir
12
+ File.join(fixture_path, 'tmp')
13
+ end
14
+
15
+ def create_tmp_dir
16
+ FileUtils::mkdir(tmp_dir) if ! File.exists?(tmp_dir)
17
+ end
18
+
19
+ def remove_tmp_dir
20
+ FileUtils::rmtree(tmp_dir)
21
+ end
22
+
23
+ end
24
+
25
+
26
+
@@ -0,0 +1,137 @@
1
+ require 'test_helper'
2
+ require 'mocha'
3
+ require 'awesome_print'
4
+
5
+ # run test: ruby -I test/ -I lib/ test/unit/csv_to_yaml_test.rb
6
+
7
+ Rails = Struct.new(:dummy)
8
+
9
+ module UnitTests
10
+
11
+ class CsvToYamlTest < Test::Unit::TestCase
12
+ include TestHelper
13
+
14
+ def setup
15
+ create_tmp_dir
16
+
17
+ @input_file = File.join(fixture_path, 'minimal.csv')
18
+ @output_file = File.join(tmp_dir, 'test.yml')
19
+ @locales = ['de', 'en']
20
+
21
+ Rails.stubs(:root).returns(stub(:join => @output_file))
22
+
23
+ @csv_to_yaml = LocalchI18n::CsvToYaml.new(@input_file, @output_file, @locales)
24
+ end
25
+
26
+ def teardown
27
+ remove_tmp_dir
28
+ end
29
+
30
+ def test_process_row
31
+ row1 = {'key' => 'homepage.meta.title', 'en' => 'Phonebook of Switzerland', 'de' => 'Telefonbuch der Schweiz'}
32
+ row2 = {'key' => 'homepage.welcome', 'en' => 'Welcome', 'de' => 'Willkommen'}
33
+ @csv_to_yaml.process_row(row1)
34
+ @csv_to_yaml.process_row(row2)
35
+
36
+ translations = @csv_to_yaml.translations
37
+ assert_equal 'Telefonbuch der Schweiz', translations['de']['homepage']['meta']['title']
38
+ assert_equal 'Willkommen', translations['de']['homepage']['welcome']
39
+ assert_equal 'Phonebook of Switzerland', translations['en']['homepage']['meta']['title']
40
+ assert_equal 'Welcome', translations['en']['homepage']['welcome']
41
+ end
42
+
43
+ def test_row_containing_non_locale_columns
44
+ row = {'key' => 'homepage.title', 'en' => "We are the Phonebook", 'de' => 'Test DE', 'comment' => "Test comment"}
45
+ @csv_to_yaml.process_row(row)
46
+
47
+ translations = @csv_to_yaml.translations
48
+ assert_equal 'We are the Phonebook', translations['en']['homepage']['title']
49
+ end
50
+
51
+
52
+ def test_empty_string_replacement_value
53
+ # As Google Spreadsheet does not export empty cells we use '_' as a fake whitespace which
54
+ # we replace with an empty string during CVS2YAML conversion.
55
+ row = {'key' => 'homepage.meta.title', 'en' => 'Phonebook of Switzerland', 'de' => '_'}
56
+ @csv_to_yaml.process_row(row)
57
+
58
+ translations = @csv_to_yaml.translations
59
+ assert_equal '', translations['de']['homepage']['meta']['title']
60
+ assert_equal 'Phonebook of Switzerland', translations['en']['homepage']['meta']['title']
61
+ end
62
+
63
+
64
+ def test_empty_string_value
65
+ row = {'key' => 'homepage.meta.title', 'en' => 'Phonebook of Switzerland', 'de' => ''}
66
+ @csv_to_yaml.process_row(row)
67
+
68
+ translations = @csv_to_yaml.translations
69
+ assert_equal '', translations['de']['homepage']['meta']['title']
70
+ assert_equal 'Phonebook of Switzerland', translations['en']['homepage']['meta']['title']
71
+ end
72
+
73
+
74
+ def test_space_value
75
+ row = {'key' => 'homepage.meta.title', 'en' => 'Phonebook of Switzerland', 'de' => ' '}
76
+ @csv_to_yaml.process_row(row)
77
+
78
+ translations = @csv_to_yaml.translations
79
+ assert_equal ' ', translations['de']['homepage']['meta']['title']
80
+ assert_equal 'Phonebook of Switzerland', translations['en']['homepage']['meta']['title']
81
+ end
82
+
83
+ def test_nil_value
84
+ row = {'key' => 'homepage.meta.title', 'en' => 'Phonebook of Switzerland', 'de' => nil}
85
+ @csv_to_yaml.process_row(row)
86
+
87
+ translations = @csv_to_yaml.translations
88
+ assert_equal({}, translations['de'])
89
+ assert_equal 'Phonebook of Switzerland', translations['en']['homepage']['meta']['title']
90
+ end
91
+
92
+
93
+ def test_nil_value_deep_structure
94
+ row1 = {'key' => 'homepage.meta.title', 'en' => 'Phonebook of Switzerland', 'de' => nil}
95
+ row2 = {'key' => 'homepage.welcome', 'en' => 'Welcome', 'de' => 'Willkommen'}
96
+ @csv_to_yaml.process_row(row1)
97
+ @csv_to_yaml.process_row(row2)
98
+
99
+ translations = @csv_to_yaml.translations
100
+ assert_nil translations['de']['meta']
101
+ assert_equal 'Willkommen', translations['de']['homepage']['welcome']
102
+ assert_equal 'Phonebook of Switzerland', translations['en']['homepage']['meta']['title']
103
+ end
104
+
105
+
106
+ def test_store_translations
107
+ keys = ['homepage', 'meta', 'title']
108
+ @csv_to_yaml.store_translation(keys, 'de', 'Telefonbuch der Schweiz')
109
+
110
+ translations = @csv_to_yaml.translations
111
+ assert_equal 'Telefonbuch der Schweiz', translations['de']['homepage']['meta']['title']
112
+ end
113
+
114
+ def test_process
115
+ @locales.each do |locale|
116
+ assert_empty @csv_to_yaml.translations[locale], "expected translation hash for locale '#{locale}' to be empty"
117
+ end
118
+
119
+ @csv_to_yaml.process
120
+
121
+ @locales.each do |locale|
122
+ assert @csv_to_yaml.translations[locale]['tel']['extended']['company_label']
123
+ assert @csv_to_yaml.translations[locale]['tel']['extended']['company_label'].is_a?(String)
124
+ assert @csv_to_yaml.translations[locale]['tel']['search_button']
125
+ assert @csv_to_yaml.translations[locale]['tel']['search_button'].is_a?(String)
126
+ end
127
+ end
128
+
129
+ def test_write_files
130
+ assert !File.exists?(@output_file)
131
+ @csv_to_yaml.process
132
+ @csv_to_yaml.write_files
133
+ assert File.exists?(@output_file)
134
+ end
135
+
136
+ end
137
+ end
@@ -0,0 +1,84 @@
1
+ require 'test_helper'
2
+ require 'mocha'
3
+
4
+ require 'awesome_print'
5
+
6
+ # run test: ruby -I test/ -I lib/ test/unit/locale_builder_test.rb
7
+
8
+ module UnitTests
9
+ class TranslationFileExportTest < Test::Unit::TestCase
10
+ include TestHelper
11
+
12
+ def setup
13
+ create_tmp_dir
14
+
15
+ source_dir = fixture_path
16
+ source_file = 'header.yml'
17
+ output_dir = tmp_dir
18
+ locales = ['en', 'de']
19
+
20
+ @exporter = LocalchI18n::TranslationFileExport.new(source_dir, source_file, output_dir, locales)
21
+ @output_file = File.join(output_dir, 'header.csv')
22
+ end
23
+
24
+ def teardown
25
+ remove_tmp_dir
26
+ end
27
+
28
+
29
+ def test_export
30
+ assert !File.exists?(@output_file)
31
+ @exporter.export
32
+ assert File.exists?(@output_file), "Expected to have a CSV file written"
33
+ end
34
+
35
+ def dtest_load_language
36
+ translations = @exporter.load_language('de')
37
+
38
+ assert translations, "Expected to return a hash with translations"
39
+ assert_equal translations['header']['search'], "Finden"
40
+ end
41
+
42
+ def dtest_flatten_translations_hash
43
+ translation_hash = {'a' => {
44
+ 'I' => '1',
45
+ 'II' => '2',
46
+ 'III' => {
47
+ 'Z' => '3'
48
+ }
49
+ },
50
+ 'b' => '4'
51
+ }
52
+
53
+ flat = @exporter.flatten_translations_hash(translation_hash)
54
+ assert_equal '1', flat['a.I']
55
+ assert_equal '2', flat['a.II']
56
+ assert_equal '3', flat['a.III.Z']
57
+ assert_equal '4', flat['b']
58
+ end
59
+
60
+ def dtest_load_translations
61
+ assert_empty @exporter.translations
62
+ @exporter.load_translations
63
+
64
+ assert @exporter.translations['de']
65
+ assert @exporter.translations['en']
66
+ assert_equal 'Finden', @exporter.translations['de']['header.search']
67
+ assert_equal 'Telefonbuch', @exporter.translations['de']['header.phonebook']
68
+ assert_equal '(c) local.ch', @exporter.translations['de']['copyright']
69
+ end
70
+
71
+ def dtest_write_to_csv
72
+ @exporter.translations = {'de' => {'numbers.one' => 'eins'},
73
+ 'en' => {'numbers.one' => 'one'}}
74
+
75
+ @exporter.write_to_csv
76
+
77
+ output = File.read(@output_file)
78
+ assert_match /^key,(en|de|,){3}$/, output
79
+ assert_match /^numbers.one,(one|eins|,){3}$/, output
80
+ end
81
+
82
+
83
+ end
84
+ end
@@ -0,0 +1,62 @@
1
+ require 'test_helper'
2
+ require 'mocha'
3
+
4
+ # run test: ruby -I test/ -I lib/ test/unit/locale_builder_test.rb
5
+
6
+ Rails = Struct.new(:dummy)
7
+
8
+ module UnitTests
9
+ class TranslationsTest < Test::Unit::TestCase
10
+ include TestHelper
11
+
12
+ def setup
13
+ create_tmp_dir
14
+
15
+ config_file = File.join(fixture_path, 'config.yml')
16
+ @translations = LocalchI18n::Translations.new(config_file, tmp_dir)
17
+ @translations.tmp_folder = tmp_dir
18
+ @translations.locales = ['de', 'en']
19
+
20
+ @fixture_file = File.join(fixture_path, 'minimal.csv')
21
+ @tmp_file = File.join(tmp_dir, 'downloaded.csv')
22
+ @output_file = File.join(tmp_dir, 'test.yml')
23
+
24
+ Rails.stubs(:root).returns(stub(:join => @output_file))
25
+ end
26
+
27
+ def teardown
28
+ remove_tmp_dir
29
+ end
30
+
31
+ def test_download
32
+ assert !File.exists?(@tmp_file)
33
+ @translations.download("https://docs.google.com/spreadsheet/pub?key=0ApnemdIdiDXedEpiVFR1RkdWMDhnTTgtdzRJMWZMLUE&single=true&gid=0&output=csv", @tmp_file)
34
+ assert File.exists?(@tmp_file), "Expected to have downloaded Google Spreadsheet to '#{@tmp_file}'"
35
+ end
36
+
37
+ def test_cleanup
38
+ @translations.csv_files = {'dummy.yml' => @tmp_file}
39
+ File.open(@tmp_file, "w") {}
40
+ assert File.exists?(@tmp_file)
41
+ @translations.clean_up
42
+ assert !File.exists?(@tmp_file), "Expected to delete file"
43
+ end
44
+
45
+ def test_store_translations
46
+ assert !File.exists?(@output_file)
47
+
48
+ @translations.csv_files = {@output_file => @fixture_file}
49
+ @translations.store_translations
50
+
51
+ assert File.exists?(@output_file)
52
+ end
53
+
54
+ def test_download_files
55
+ expected_file = File.join(tmp_dir, 'download.csv')
56
+ assert !File.exists?(expected_file)
57
+ @translations.download_files
58
+ assert File.exists?(expected_file)
59
+ end
60
+
61
+ end
62
+ end