twine 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9c61dcacafc740f0edf24674f331c77c83b1d94b
4
- data.tar.gz: e45d63d180e8d396194d1f86d408acefb6813886
3
+ metadata.gz: e3466fcfcd027a2fd2af846ddd8bdba4d822cd39
4
+ data.tar.gz: 7f5df06f8206324c53d5e23de67aa8e35d90a6aa
5
5
  SHA512:
6
- metadata.gz: 05f6f055d5eb781de1173a0556921e286381a0effbe328a8be5d586405fc10b0a25fc2e1c235f58a9ddbd96264f3fd3a1f27bc965386302e9522c1806184b961
7
- data.tar.gz: ef330b79c5c17f265823e2646b04f30e7a415cf39569148968f5708cee40c7b2108dc9de64f5facfced1d8ec35d6e7a1ed129d3677234ab38f5a6b10126cfb4f
6
+ metadata.gz: 04dbdfb83e0ba690b5893d6b52539ae65b2ad687a6143fb7f998cacb6671418ff8ecedb0731ccf0404cc5f56b93b68ac2c1459ced44ddf840551ceea351cffcf
7
+ data.tar.gz: a9e1c41cdcea98f785eff464dde70f2883ea3b9080e40fce4271bbe429faafa98c1a756820d8fba189d560bc6b9e7751555b50ea0412ccfdd12e7247933ecdfb
data/Gemfile CHANGED
@@ -1,2 +1,2 @@
1
- source :rubygems
1
+ source "https://rubygems.org"
2
2
  gemspec
data/README.md CHANGED
@@ -76,6 +76,7 @@ Twine currently supports the following formats for outputting strings:
76
76
  * [Android String Resources][androidstrings] (format: android)
77
77
  * [Gettext PO Files][gettextpo] (format: gettext)
78
78
  * [jquery-localize Language Files][jquerylocalize] (format: jquery)
79
+ * [Django PO Files][djangopo] (format: django)
79
80
 
80
81
  If you would like to enable twine to create language files in another format, create an appropriate formatter in `lib/twine/formatters`.
81
82
 
@@ -157,15 +158,23 @@ It is easy to incorporate Twine right into your iOS and OS X app build processes
157
158
 
158
159
  Now, whenever you build your application, Xcode will automatically invoke Twine to make sure that your `.strings` files are up-to-date.
159
160
 
161
+ ## User Interface
162
+
163
+ * [Twine TextMate 2 Bundle](https://github.com/mobiata/twine.tmbundle) — This [TextMate 2](https://github.com/textmate/textmate) bundle will make it easier for you to work with Twine strings files. In particular, it lets you use code folding to easily collapse and expand both strings and sections.
164
+ * [twine_ui](https://github.com/Daij-Djan/twine_ui) — A user interface for Twine written by [Dominik Pich](https://github.com/Daij-Djan/). Consider using this if you would prefer to use Twine without dropping to a command line.
165
+
160
166
  ## Contributors
161
167
 
162
168
  Many thanks to all of the contributors to the Twine project, including:
163
169
 
170
+ * [Blake Watters](https://github.com/blakewatters)
164
171
  * [Ishitoya Kentaro](https://github.com/kent013)
172
+ * [Joseph Earl](https://github.com/JosephEarl)
165
173
  * [Kevin Everets](https://github.com/keverets)
166
174
  * [Kevin Wood](https://github.com/kwood)
167
175
  * [Mohammad Hejazi](https://github.com/MohammadHejazi)
168
176
  * [Robert Guo](http://www.robertguo.me/)
177
+ * [Shai Shamir](https://github.com/pichirichi)
169
178
 
170
179
 
171
180
  [rubyzip]: http://rubygems.org/gems/rubyzip
@@ -175,3 +184,4 @@ Many thanks to all of the contributors to the Twine project, including:
175
184
  [androidstrings]: http://developer.android.com/guide/topics/resources/string-resource.html
176
185
  [gettextpo]: http://www.gnu.org/savannah-checkouts/gnu/gettext/manual/html_node/PO-Files.html
177
186
  [jquerylocalize]: https://github.com/coderifous/jquery-localize
187
+ [djangopo]: https://docs.djangoproject.com/en/dev/topics/i18n/translation/
@@ -4,9 +4,10 @@ require 'twine/formatters/apple'
4
4
  require 'twine/formatters/flash'
5
5
  require 'twine/formatters/gettext'
6
6
  require 'twine/formatters/jquery'
7
+ require 'twine/formatters/django'
7
8
 
8
9
  module Twine
9
10
  module Formatters
10
- FORMATTERS = [Formatters::Apple, Formatters::Android, Formatters::Gettext, Formatters::JQuery, Formatters::Flash]
11
+ FORMATTERS = [Formatters::Apple, Formatters::Android, Formatters::Gettext, Formatters::JQuery, Formatters::Flash, Formatters::Django]
11
12
  end
12
13
  end
@@ -14,42 +14,8 @@ module Twine
14
14
  end
15
15
 
16
16
  def iosify_substitutions(str)
17
- # 1) use "@" instead of "s" for substituting strings
17
+ # use "@" instead of "s" for substituting strings
18
18
  str.gsub!(/%([0-9\$]*)s/, '%\1@')
19
-
20
- # 2) if substitutions are numbered, see if we can remove the numbering safely
21
- expectedSub = 1
22
- startFound = false
23
- foundSub = 0
24
- str.each_char do |c|
25
- if startFound
26
- if c == "%"
27
- # this is a literal %, keep moving
28
- startFound = false
29
- elsif c.match(/\d/)
30
- foundSub *= 10
31
- foundSub += Integer(c)
32
- elsif c == "$"
33
- if expectedSub == foundSub
34
- # okay to keep going
35
- startFound = false
36
- expectedSub += 1
37
- else
38
- # the numbering appears to be important (or non-existent), leave it alone
39
- return str
40
- end
41
- end
42
- elsif c == "%"
43
- startFound = true
44
- foundSub = 0
45
- end
46
- end
47
-
48
- # if we got this far, then the numbering (if any) is in order left-to-right and safe to remove
49
- if expectedSub > 1
50
- str.gsub!(/%\d+\$(.)/, '%\1')
51
- end
52
-
53
19
  return str
54
20
  end
55
21
 
@@ -152,12 +118,23 @@ module Twine
152
118
  end
153
119
 
154
120
  file_name = @options[:file_name] || default_file_name
121
+ langs_written = []
155
122
  Dir.foreach(path) do |item|
156
- lang = determine_language_given_path(item)
157
- if lang
158
- write_file(File.join(path, item, file_name), lang)
123
+ if item == "." or item == ".."
124
+ next
125
+ end
126
+ item = File.join(path, item)
127
+ if File.directory?(item)
128
+ lang = determine_language_given_path(item)
129
+ if lang
130
+ write_file(File.join(item, file_name), lang)
131
+ langs_written << lang
132
+ end
159
133
  end
160
134
  end
135
+ if langs_written.empty?
136
+ raise Twine::Error.new("Failed to genertate any files: No languages found at #{path}")
137
+ end
161
138
  end
162
139
  end
163
140
  end
@@ -49,7 +49,7 @@ module Twine
49
49
  end
50
50
 
51
51
  def read_file(path, lang)
52
- resources_regex = /<resources>(.*)<\/resources>/m
52
+ resources_regex = /<resources(?:[^>]*)>(.*)<\/resources>/m
53
53
  key_regex = /<string name="(\w+)">/
54
54
  comment_regex = /<!-- (.*) -->/
55
55
  value_regex = /<string name="\w+">(.*)<\/string>/
@@ -0,0 +1,143 @@
1
+ module Twine
2
+ module Formatters
3
+ class Django < Abstract
4
+ FORMAT_NAME = 'django'
5
+ EXTENSION = '.po'
6
+ DEFAULT_FILE_NAME = 'strings.po'
7
+
8
+ def self.can_handle_directory?(path)
9
+ Dir.entries(path).any? { |item| /^.+\.po$/.match(item) }
10
+ end
11
+
12
+ def default_file_name
13
+ return DEFAULT_FILE_NAME
14
+ end
15
+
16
+ def determine_language_given_path(path)
17
+ path_arr = path.split(File::SEPARATOR)
18
+ path_arr.each do |segment|
19
+ match = /(..)\.po$/.match(segment)
20
+ if match
21
+ return match[1]
22
+ end
23
+ end
24
+
25
+ return
26
+ end
27
+
28
+ def read_file(path, lang)
29
+ comment_regex = /#.? *"(.*)"$/
30
+ key_regex = /msgid *"(.*)"$/
31
+ value_regex = /msgstr *"(.*)"$/m
32
+
33
+ encoding = Twine::Encoding.encoding_for_path(path)
34
+ sep = nil
35
+ if !encoding.respond_to?(:encode)
36
+ # This code is not necessary in 1.9.3 and does not work as it did in 1.8.7.
37
+ if encoding.end_with? 'LE'
38
+ sep = "\x0a\x00"
39
+ elsif encoding.end_with? 'BE'
40
+ sep = "\x00\x0a"
41
+ else
42
+ sep = "\n"
43
+ end
44
+ end
45
+
46
+ if encoding.index('UTF-16')
47
+ mode = "rb:#{encoding}"
48
+ else
49
+ mode = "r:#{encoding}"
50
+ end
51
+
52
+ File.open(path, mode) do |f|
53
+ last_comment = nil
54
+ while line = (sep) ? f.gets(sep) : f.gets
55
+ if encoding.index('UTF-16')
56
+ if line.respond_to? :encode!
57
+ line.encode!('UTF-8')
58
+ else
59
+ require 'iconv'
60
+ line = Iconv.iconv('UTF-8', encoding, line).join
61
+ end
62
+ end
63
+ if @options[:consume_comments]
64
+ comment_match = comment_regex.match(line)
65
+ if comment_match
66
+ comment = comment_match[1]
67
+ end
68
+ else
69
+ comment = nil
70
+ end
71
+ key_match = key_regex.match(line)
72
+ if key_match
73
+ key = key_match[1].gsub('\\"', '"')
74
+ end
75
+ value_match = value_regex.match(line)
76
+ if value_match
77
+ value = value_match[1].gsub(/"\n"/, '').gsub('\\"', '"')
78
+ end
79
+
80
+
81
+ if key and key.length > 0 and value and value.length > 0
82
+ set_translation_for_key(key, lang, value)
83
+ if comment and comment.length > 0 and !comment.start_with?("--------- ")
84
+ set_comment_for_key(key, comment)
85
+ end
86
+ comment = nil
87
+ end
88
+
89
+ end
90
+ end
91
+ end
92
+
93
+ def write_file(path, lang)
94
+ default_lang = @strings.language_codes[0]
95
+ encoding = @options[:output_encoding] || 'UTF-8'
96
+ File.open(path, "w:#{encoding}") do |f|
97
+ f.puts "##\n # Django Strings File\n # Generated by Twine #{Twine::VERSION}\n # Language: #{lang}\n "
98
+ @strings.sections.each do |section|
99
+ printed_section = false
100
+ section.rows.each do |row|
101
+ if row.matches_tags?(@options[:tags], @options[:untagged])
102
+ f.puts ''
103
+ if !printed_section
104
+ if section.name && section.name.length > 0
105
+ f.print "#--------- #{section.name} ---------#\n\n"
106
+ end
107
+ printed_section = true
108
+ end
109
+
110
+ basetrans = row.translated_string_for_lang(default_lang)
111
+
112
+ key = row.key
113
+ key = key.gsub('"', '\\\\"')
114
+
115
+ value = row.translated_string_for_lang(lang, default_lang)
116
+ if value
117
+ value = value.gsub('"', '\\\\"')
118
+
119
+ comment = row.comment
120
+
121
+ if comment
122
+ comment = comment.gsub('"', '\\\\"')
123
+ end
124
+
125
+ if comment && comment.length > 0
126
+ f.print "#. #{comment} \n"
127
+ end
128
+
129
+ if basetrans && basetrans.length > 0
130
+ f.print "# base translation: \"#{basetrans}\"\n"
131
+ end
132
+
133
+ f.print "msgid \"#{key}\"\n"
134
+ f.print "msgstr \"#{value}\"\n"
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Twine
2
4
  module Formatters
3
5
  class Gettext < Abstract
@@ -35,25 +37,24 @@ module Twine
35
37
  value = nil
36
38
  comment = nil
37
39
 
38
- for line in item.split(/\r?\n/)
39
- comment_match = comment_regex.match(line)
40
- if comment_match
41
- comment = comment_match[1]
42
- end
43
- key_match = key_regex.match(line)
44
- if key_match
45
- key = key_match[1].gsub('\\"', '"')
46
- end
47
- value_match = value_regex.match(line)
48
- if value_match
49
- value = value_match[1].gsub('\\"', '"')
50
- end
40
+ comment_match = comment_regex.match(item)
41
+ if comment_match
42
+ comment = comment_match[1]
43
+ end
44
+ key_match = key_regex.match(item)
45
+ if key_match
46
+ key = key_match[1].gsub('\\"', '"')
47
+ end
48
+ value_match = value_regex.match(item)
49
+ if value_match
50
+ value = value_match[1].gsub(/"\n"/, '').gsub('\\"', '"')
51
51
  end
52
52
  if key and key.length > 0 and value and value.length > 0
53
53
  set_translation_for_key(key, lang, value)
54
- if comment and comment.length > 0
54
+ if comment and comment.length > 0 and !comment.start_with?("SECTION:")
55
55
  set_comment_for_key(key, comment)
56
56
  end
57
+ comment = nil
57
58
  end
58
59
  end
59
60
  end
@@ -68,6 +69,15 @@ module Twine
68
69
  printed_section = false
69
70
  section.rows.each do |row|
70
71
  if row.matches_tags?(@options[:tags], @options[:untagged])
72
+ if !printed_section
73
+ f.puts ''
74
+ if section.name && section.name.length > 0
75
+ section_name = section.name.gsub('--', '—')
76
+ f.puts "# SECTION: #{section_name}"
77
+ end
78
+ printed_section = true
79
+ end
80
+
71
81
  basetrans = row.translated_string_for_lang(default_lang)
72
82
 
73
83
  if basetrans
@@ -167,7 +167,7 @@ module Twine
167
167
  end
168
168
  @language_codes[1..-1].each do |lang|
169
169
  value = row.translations[lang]
170
- if value && value != row.translations[dev_lang]
170
+ if value
171
171
  if value[0,1] == ' ' || value[-1,1] == ' ' || (value[0,1] == '`' && value[-1,1] == '`')
172
172
  value = '`' + value + '`'
173
173
  end
data/lib/twine/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Twine
2
- VERSION = '0.4.0'
2
+ VERSION = '0.5.0'
3
3
  end
@@ -0,0 +1,23 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Language: en\n"
4
+ "X-Generator: Twine\n"
5
+
6
+ msgctxt "key1"
7
+ msgid "key1-english"
8
+ msgstr "key1-english"
9
+
10
+ msgctxt "key3"
11
+ msgid "key3-english"
12
+ msgstr ""
13
+
14
+ msgctxt "key4"
15
+ msgid "key4"
16
+ "multiline"
17
+ msgstr "A multi"
18
+ "line string\n"
19
+ "can occur"
20
+
21
+ msgctxt "key5"
22
+ msgid "A new string"
23
+ msgstr "A new string"
@@ -3,6 +3,8 @@ msgstr ""
3
3
  "Language: en\n"
4
4
  "X-Generator: Twine <%= Twine::VERSION %>\n"
5
5
 
6
+
7
+ # SECTION: My Strings
6
8
  #. "This is a comment"
7
9
  msgctxt "key1"
8
10
  msgid "key1-english"
@@ -0,0 +1,21 @@
1
+ [[Uncategorized]]
2
+ [key5]
3
+ en = A new string
4
+
5
+ [[My Strings]]
6
+ [key1]
7
+ en = key1-english
8
+ tags = tag1
9
+ comment = This is a comment
10
+ es = key1-spanish
11
+ fr = key1-french
12
+ [key2]
13
+ en = key2-english
14
+ tags = tag2
15
+ fr = key2-french
16
+ [key3]
17
+ en = key3-english
18
+ tags = tag1,tag2
19
+ es = key3-spanish
20
+ [key4]
21
+ en = A multiline string\ncan occur
data/test/twine_test.rb CHANGED
@@ -84,6 +84,14 @@ class TwineTest < Test::Unit::TestCase
84
84
  end
85
85
  end
86
86
 
87
+ def test_consume_string_file_5
88
+ Dir.mktmpdir do |dir|
89
+ output_path = File.join(dir, 'strings.txt')
90
+ Twine::Runner.run(%W(consume-string-file test/fixtures/strings-1.txt test/fixtures/en-2.po -o #{output_path} -l en -a))
91
+ assert_equal(File.read('test/fixtures/test-output-9.txt'), File.read(output_path))
92
+ end
93
+ end
94
+
87
95
  def test_generate_report_1
88
96
  Twine::Runner.run(%w(generate-report test/fixtures/strings-1.txt))
89
97
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian Celis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-05-17 00:00:00.000000000 Z
11
+ date: 2014-02-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubyzip
@@ -56,6 +56,7 @@ files:
56
56
  - lib/twine/formatters/abstract.rb
57
57
  - lib/twine/formatters/android.rb
58
58
  - lib/twine/formatters/apple.rb
59
+ - lib/twine/formatters/django.rb
59
60
  - lib/twine/formatters/flash.rb
60
61
  - lib/twine/formatters/gettext.rb
61
62
  - lib/twine/formatters/jquery.rb
@@ -68,6 +69,7 @@ files:
68
69
  - test/fixtures/en-1.json
69
70
  - test/fixtures/en-1.po
70
71
  - test/fixtures/en-1.strings
72
+ - test/fixtures/en-2.po
71
73
  - test/fixtures/fr-1.xml
72
74
  - test/fixtures/strings-1.txt
73
75
  - test/fixtures/strings-2.txt
@@ -80,6 +82,7 @@ files:
80
82
  - test/fixtures/test-output-6.txt
81
83
  - test/fixtures/test-output-7.txt
82
84
  - test/fixtures/test-output-8.txt
85
+ - test/fixtures/test-output-9.txt
83
86
  - test/twine_test.rb
84
87
  homepage: https://github.com/mobiata/twine
85
88
  licenses: []
@@ -100,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
103
  version: '0'
101
104
  requirements: []
102
105
  rubyforge_project:
103
- rubygems_version: 2.0.0
106
+ rubygems_version: 2.0.3
104
107
  signing_key:
105
108
  specification_version: 4
106
109
  summary: Manage strings and their translations for your iOS and Android projects.