fast_gettext 0.4.16

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.
Files changed (61) hide show
  1. data/.gitignore +2 -0
  2. data/CHANGELOG +6 -0
  3. data/README.markdown +181 -0
  4. data/Rakefile +42 -0
  5. data/VERSION +1 -0
  6. data/benchmark/base.rb +42 -0
  7. data/benchmark/baseline.rb +5 -0
  8. data/benchmark/fast_gettext.rb +18 -0
  9. data/benchmark/i18n_simple.rb +7 -0
  10. data/benchmark/ideal.rb +22 -0
  11. data/benchmark/locale/de.yml +127 -0
  12. data/benchmark/locale/de/LC_MESSAGES/large.mo +0 -0
  13. data/benchmark/misc/threadsave.rb +21 -0
  14. data/benchmark/namespace/fast_gettext.rb +15 -0
  15. data/benchmark/namespace/original.rb +14 -0
  16. data/benchmark/original.rb +15 -0
  17. data/examples/db/migration.rb +22 -0
  18. data/examples/missing_translation_logger.rb +13 -0
  19. data/fast_gettext.gemspec +114 -0
  20. data/lib/fast_gettext.rb +30 -0
  21. data/lib/fast_gettext/mo_file.rb +67 -0
  22. data/lib/fast_gettext/po_file.rb +14 -0
  23. data/lib/fast_gettext/storage.rb +188 -0
  24. data/lib/fast_gettext/translation.rb +53 -0
  25. data/lib/fast_gettext/translation_repository.rb +15 -0
  26. data/lib/fast_gettext/translation_repository/base.rb +49 -0
  27. data/lib/fast_gettext/translation_repository/chain.rb +43 -0
  28. data/lib/fast_gettext/translation_repository/db.rb +57 -0
  29. data/lib/fast_gettext/translation_repository/db_models/translation_key.rb +26 -0
  30. data/lib/fast_gettext/translation_repository/db_models/translation_text.rb +9 -0
  31. data/lib/fast_gettext/translation_repository/logger.rb +27 -0
  32. data/lib/fast_gettext/translation_repository/mo.rb +35 -0
  33. data/lib/fast_gettext/translation_repository/po.rb +18 -0
  34. data/spec/aa_unconfigued_spec.rb +21 -0
  35. data/spec/fast_gettext/mo_file_spec.rb +36 -0
  36. data/spec/fast_gettext/storage_spec.rb +309 -0
  37. data/spec/fast_gettext/translation_repository/base_spec.rb +21 -0
  38. data/spec/fast_gettext/translation_repository/chain_spec.rb +82 -0
  39. data/spec/fast_gettext/translation_repository/db_spec.rb +71 -0
  40. data/spec/fast_gettext/translation_repository/logger_spec.rb +41 -0
  41. data/spec/fast_gettext/translation_repository/mo_spec.rb +31 -0
  42. data/spec/fast_gettext/translation_repository/po_spec.rb +31 -0
  43. data/spec/fast_gettext/translation_spec.rb +152 -0
  44. data/spec/fast_gettext_spec.rb +44 -0
  45. data/spec/locale/de/LC_MESSAGES/test.mo +0 -0
  46. data/spec/locale/de/test.po +61 -0
  47. data/spec/locale/en/LC_MESSAGES/plural_test.mo +0 -0
  48. data/spec/locale/en/LC_MESSAGES/test.mo +0 -0
  49. data/spec/locale/en/plural_test.po +20 -0
  50. data/spec/locale/en/test.po +59 -0
  51. data/spec/spec_helper.rb +26 -0
  52. data/spec/vendor/fake_load_path/iconv.rb +2 -0
  53. data/spec/vendor/iconv_spec.rb +27 -0
  54. data/spec/vendor/string_spec.rb +67 -0
  55. data/vendor/README.rdoc +236 -0
  56. data/vendor/empty.mo +0 -0
  57. data/vendor/iconv.rb +107 -0
  58. data/vendor/mofile.rb +296 -0
  59. data/vendor/poparser.rb +331 -0
  60. data/vendor/string.rb +58 -0
  61. metadata +130 -0
@@ -0,0 +1,21 @@
1
+ require 'benchmark'
2
+ BASELINE = 0
3
+ def test
4
+ result = Benchmark.measure {1_000_000.times{ yield }}
5
+ result.to_s.strip.split(' ').first.to_f - BASELINE
6
+ end
7
+
8
+ BASELINE = (test{})
9
+ Thread.current[:library_name]={}
10
+ other = "x"
11
+ puts "Ruby #{VERSION}"
12
+
13
+ puts "generic:"
14
+ puts " Symbol: #{test{Thread.current[:library_name][:just_a_symbol]}}s"
15
+ puts " String concat: #{test{Thread.current["xxxxxx"<<other.to_s]}}s"
16
+ puts " String add: #{test{Thread.current["xxxxxx"+other.to_s]}}s"
17
+ puts " String insert: #{test{Thread.current["xxxxxx#{other}"]}}s"
18
+
19
+ puts "single:"
20
+ puts " Symbol: #{test{Thread.current[:long_unique_symbol]}}s"
21
+ puts " String: #{test{Thread.current["xxxxxx"]}}s"
@@ -0,0 +1,15 @@
1
+ #Iconv will not be defined, unless it is found -> normalize test results for users that have Iconv/those who do not have it
2
+ begin;require 'iconv';rescue;LoadError;end
3
+ initial = methods.count + Module.constants.count
4
+
5
+ #FastGettext
6
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__),'..','..','lib')
7
+ require 'fast_gettext'
8
+ FastGettext.locale = 'de'
9
+ FastGettext.add_text_domain 'test', :path=>'spec/locale'
10
+ FastGettext.text_domain = 'test'
11
+ include FastGettext::Translation
12
+ raise unless _('car')=='Auto'
13
+
14
+ puts "FastGettext"
15
+ puts methods.count + Module.constants.count - initial
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ initial = methods.count + Module.constants.count
3
+
4
+ #GetText
5
+ gem 'gettext', '>=2.0.0'
6
+ require 'gettext'
7
+ GetText.locale = 'de'
8
+ GetText.bindtextdomain('test',:path=>'spec/locale')
9
+ include GetText
10
+ raise unless _('car') == 'Auto'
11
+
12
+
13
+ puts "GetText"
14
+ puts methods.count + Module.constants.count - initial
@@ -0,0 +1,15 @@
1
+ require 'benchmark/base'
2
+
3
+ gem 'gettext', '>=2.0.0'
4
+ require 'gettext'
5
+ include GetText
6
+
7
+ self.locale = 'de'
8
+
9
+ puts "GetText #{GetText::VERSION}:"
10
+ bindtextdomain('test',:path=>locale_folder('test'))
11
+ results_test{_('car') == 'Auto'}
12
+
13
+ #i cannot add the large file, since its an internal applications mo file
14
+ bindtextdomain('large',:path=>locale_folder('large'))
15
+ results_large
@@ -0,0 +1,22 @@
1
+ class CreateTranslationTables < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :translation_keys do |t|
4
+ t.string :key, :unique=>true, :null=>false
5
+ t.timestamps
6
+ end
7
+ add_index :translation_keys, :key #I am not sure if this helps....
8
+
9
+ create_table :translation_texts do |t|
10
+ t.text :text
11
+ t.string :locale
12
+ t.integer :translation_key_id, :null=>false
13
+ t.timestamps
14
+ end
15
+ add_index :translation_texts, :translation_key_id
16
+ end
17
+
18
+ def self.down
19
+ drop_table :translation_keys
20
+ drop_table :translation_texts
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ class MissingTranslationLogger
2
+ def call(unfound)
3
+ logger.warn "#{FastGettext.locale}: #{unfound}" unless FastGettext.locale == 'en'
4
+ end
5
+
6
+ private
7
+
8
+ def logger
9
+ return @logger if @logger
10
+ require 'logger'
11
+ @logger = Logger.new("log/unfound_translations", 2, 5*(1024**2))#max 2x 5mb logfile
12
+ end
13
+ end
@@ -0,0 +1,114 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
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 = %q{fast_gettext}
8
+ s.version = "0.4.16"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Michael Grosser"]
12
+ s.date = %q{2009-10-16}
13
+ s.email = %q{grosser.michael@gmail.com}
14
+ s.extra_rdoc_files = [
15
+ "README.markdown"
16
+ ]
17
+ s.files = [
18
+ ".gitignore",
19
+ "CHANGELOG",
20
+ "README.markdown",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "benchmark/base.rb",
24
+ "benchmark/baseline.rb",
25
+ "benchmark/fast_gettext.rb",
26
+ "benchmark/i18n_simple.rb",
27
+ "benchmark/ideal.rb",
28
+ "benchmark/locale/de.yml",
29
+ "benchmark/locale/de/LC_MESSAGES/large.mo",
30
+ "benchmark/misc/threadsave.rb",
31
+ "benchmark/namespace/fast_gettext.rb",
32
+ "benchmark/namespace/original.rb",
33
+ "benchmark/original.rb",
34
+ "examples/db/migration.rb",
35
+ "examples/missing_translation_logger.rb",
36
+ "fast_gettext.gemspec",
37
+ "lib/fast_gettext.rb",
38
+ "lib/fast_gettext/mo_file.rb",
39
+ "lib/fast_gettext/po_file.rb",
40
+ "lib/fast_gettext/storage.rb",
41
+ "lib/fast_gettext/translation.rb",
42
+ "lib/fast_gettext/translation_repository.rb",
43
+ "lib/fast_gettext/translation_repository/base.rb",
44
+ "lib/fast_gettext/translation_repository/chain.rb",
45
+ "lib/fast_gettext/translation_repository/db.rb",
46
+ "lib/fast_gettext/translation_repository/db_models/translation_key.rb",
47
+ "lib/fast_gettext/translation_repository/db_models/translation_text.rb",
48
+ "lib/fast_gettext/translation_repository/logger.rb",
49
+ "lib/fast_gettext/translation_repository/mo.rb",
50
+ "lib/fast_gettext/translation_repository/po.rb",
51
+ "spec/aa_unconfigued_spec.rb",
52
+ "spec/fast_gettext/mo_file_spec.rb",
53
+ "spec/fast_gettext/storage_spec.rb",
54
+ "spec/fast_gettext/translation_repository/base_spec.rb",
55
+ "spec/fast_gettext/translation_repository/chain_spec.rb",
56
+ "spec/fast_gettext/translation_repository/db_spec.rb",
57
+ "spec/fast_gettext/translation_repository/logger_spec.rb",
58
+ "spec/fast_gettext/translation_repository/mo_spec.rb",
59
+ "spec/fast_gettext/translation_repository/po_spec.rb",
60
+ "spec/fast_gettext/translation_spec.rb",
61
+ "spec/fast_gettext_spec.rb",
62
+ "spec/locale/de/LC_MESSAGES/test.mo",
63
+ "spec/locale/de/test.po",
64
+ "spec/locale/en/LC_MESSAGES/plural_test.mo",
65
+ "spec/locale/en/LC_MESSAGES/test.mo",
66
+ "spec/locale/en/plural_test.po",
67
+ "spec/locale/en/test.po",
68
+ "spec/spec_helper.rb",
69
+ "spec/vendor/fake_load_path/iconv.rb",
70
+ "spec/vendor/iconv_spec.rb",
71
+ "spec/vendor/string_spec.rb",
72
+ "vendor/README.rdoc",
73
+ "vendor/empty.mo",
74
+ "vendor/iconv.rb",
75
+ "vendor/mofile.rb",
76
+ "vendor/poparser.rb",
77
+ "vendor/string.rb"
78
+ ]
79
+ s.homepage = %q{http://github.com/grosser/fast_gettext}
80
+ s.rdoc_options = ["--charset=UTF-8"]
81
+ s.require_paths = ["lib"]
82
+ s.rubyforge_project = %q{fast-gettext}
83
+ s.rubygems_version = %q{1.3.5}
84
+ s.summary = %q{A simple, fast and threadsafe implementation of GetText}
85
+ s.test_files = [
86
+ "spec/fast_gettext_spec.rb",
87
+ "spec/spec_helper.rb",
88
+ "spec/fast_gettext/translation_spec.rb",
89
+ "spec/fast_gettext/storage_spec.rb",
90
+ "spec/fast_gettext/translation_repository/chain_spec.rb",
91
+ "spec/fast_gettext/translation_repository/logger_spec.rb",
92
+ "spec/fast_gettext/translation_repository/base_spec.rb",
93
+ "spec/fast_gettext/translation_repository/po_spec.rb",
94
+ "spec/fast_gettext/translation_repository/db_spec.rb",
95
+ "spec/fast_gettext/translation_repository/mo_spec.rb",
96
+ "spec/fast_gettext/mo_file_spec.rb",
97
+ "spec/aa_unconfigued_spec.rb",
98
+ "spec/vendor/iconv_spec.rb",
99
+ "spec/vendor/fake_load_path/iconv.rb",
100
+ "spec/vendor/string_spec.rb",
101
+ "examples/db/migration.rb",
102
+ "examples/missing_translation_logger.rb"
103
+ ]
104
+
105
+ if s.respond_to? :specification_version then
106
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
107
+ s.specification_version = 3
108
+
109
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
110
+ else
111
+ end
112
+ else
113
+ end
114
+ end
@@ -0,0 +1,30 @@
1
+ require 'fast_gettext/mo_file'
2
+ require 'fast_gettext/storage'
3
+ require 'fast_gettext/translation'
4
+ require 'fast_gettext/translation_repository'
5
+ require File.join(File.dirname(__FILE__),'..','vendor','string')
6
+
7
+ module FastGettext
8
+ include FastGettext::Storage
9
+ extend self
10
+
11
+ VERSION = File.read( File.join(File.dirname(__FILE__),'..','VERSION') ).strip
12
+ LOCALE_REX = /^[a-z]{2}$|^[a-z]{2}_[A-Z]{2}$/
13
+ NAMESPACE_SEPERATOR = '|'
14
+
15
+ # users should not include FastGettext, since this would conterminate their namespace
16
+ # rather use
17
+ # FastGettext.locale = ..
18
+ # FastGettext.text_domain = ..
19
+ # and
20
+ # include FastGettext::Translation
21
+ FastGettext::Translation.public_instance_methods.each do |method|
22
+ define_method method do |*args|
23
+ Translation.send(method,*args)
24
+ end
25
+ end
26
+
27
+ def add_text_domain(name,options)
28
+ translation_repositories[name] = TranslationRepository.build(name,options)
29
+ end
30
+ end
@@ -0,0 +1,67 @@
1
+ require File.join(File.dirname(__FILE__),'..','..','vendor','mofile')
2
+ module FastGettext
3
+ # Responsibility:
4
+ # - abstract mo files for Mo Repository
5
+ class MoFile
6
+ PLURAL_SEPERATOR = "\000"
7
+
8
+ # file => path or FastGettext::GetText::MOFile
9
+ def initialize(file)
10
+ if file.is_a? FastGettext::GetText::MOFile
11
+ @data = file
12
+ else
13
+ @data = FastGettext::GetText::MOFile.open(file, "UTF-8")
14
+ end
15
+ make_singular_and_plural_available
16
+ end
17
+
18
+ def [](key)
19
+ @data[key]
20
+ end
21
+
22
+ #returns the plural forms or all singlgular translations that where found
23
+ def plural(*msgids)
24
+ translations = plural_translations(msgids)
25
+ return translations unless translations.empty?
26
+ msgids.map{|msgid| self[msgid] || msgid} #try to translate each id
27
+ end
28
+
29
+ def pluralisation_rule
30
+ #gettext uses 0 as default rule, which would turn off all pluralisation, very clever...
31
+ #additionally parsing fails when directly accessing po files, so this line was taken from gettext/mofile
32
+ (@data['']||'').split("\n").each do |line|
33
+ return lambda{|n|eval($2)} if /^Plural-Forms:\s*nplurals\s*\=\s*(\d*);\s*plural\s*\=\s*([^;]*)\n?/ =~ line
34
+ end
35
+ nil
36
+ end
37
+
38
+ def self.empty
39
+ MoFile.new(File.join(File.dirname(__FILE__),'..','..','vendor','empty.mo'))
40
+ end
41
+
42
+ private
43
+
44
+ #(if plural==singular, prefer singular)
45
+ def make_singular_and_plural_available
46
+ data = {}
47
+ @data.each do |key,translation|
48
+ next unless key.include? PLURAL_SEPERATOR
49
+ singular, plural = split_plurals(key)
50
+ translation = split_plurals(translation)
51
+ data[singular] ||= translation[0]
52
+ data[plural] ||= translation[1]
53
+ end
54
+ @data.merge!(data){|key,old,new| old}
55
+ end
56
+
57
+ def split_plurals(singular_plural)
58
+ singular_plural.split(PLURAL_SEPERATOR)
59
+ end
60
+
61
+ # Car, Cars => [Auto,Autos] or []
62
+ def plural_translations(msgids)
63
+ plurals = self[msgids*PLURAL_SEPERATOR]
64
+ if plurals then split_plurals(plurals) else [] end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,14 @@
1
+ require 'fast_gettext/mo_file'
2
+ module FastGettext
3
+ # Responsibility:
4
+ # - abstract po files for Po Repository
5
+ # TODO refactor...
6
+ class PoFile
7
+ def self.to_mo_file(file)
8
+ require File.join(File.dirname(__FILE__),'..','..','vendor','poparser')
9
+ mo_file = FastGettext::GetText::MOFile.new
10
+ FastGettext::GetText::PoParser.new.parse(File.read(file),mo_file)
11
+ MoFile.new(mo_file)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,188 @@
1
+ module FastGettext
2
+ # Responsibility:
3
+ # - store data threadsave
4
+ # - provide error messages when repositories are unconfigured
5
+ # - accept/reject locales that are set by the user
6
+ module Storage
7
+ class NoTextDomainConfigured < RuntimeError
8
+ def to_s
9
+ "Current textdomain (#{FastGettext.text_domain.inspect}) was not added, use FastGettext.add_text_domain !"
10
+ end
11
+ end
12
+
13
+ [:available_locales, :_locale, :text_domain, :pluralisation_rule].each do |method_name|
14
+ key = "fast_gettext_#{method_name}".to_sym
15
+ define_method method_name do
16
+ Thread.current[key]
17
+ end
18
+
19
+ define_method "#{method_name}=" do |value|
20
+ Thread.current[key]=value
21
+ update_current_cache
22
+ end
23
+ end
24
+ private :_locale, :_locale=
25
+
26
+
27
+ def available_locales
28
+ Thread.current[:fast_gettext_available_locales] || default_available_locales
29
+ end
30
+
31
+ # == cattr_accessor :default_available_locales
32
+ @@default_available_locales = nil
33
+ def default_available_locales=(avail_locales)
34
+ @@default_available_locales = avail_locales
35
+ update_current_cache
36
+ end
37
+
38
+ def default_available_locales
39
+ @@default_available_locales
40
+ end
41
+
42
+
43
+ def text_domain
44
+ Thread.current[:fast_gettext_text_domain] || default_text_domain
45
+ end
46
+
47
+ # == cattr_accessor :default_text_domain
48
+ @@default_text_domain = nil
49
+ def default_text_domain=(domain)
50
+ @@default_text_domain = domain
51
+ update_current_cache
52
+ end
53
+
54
+ def default_text_domain
55
+ @@default_text_domain
56
+ end
57
+
58
+
59
+ def pluralisation_rule
60
+ Thread.current[:fast_gettext_pluralisation_rule] || current_repository.pluralisation_rule || lambda{|i| i!=1}
61
+ end
62
+
63
+ def current_cache
64
+ Thread.current[:fast_gettext_current_cache] || {}
65
+ end
66
+
67
+ def current_cache=(cache)
68
+ Thread.current[:fast_gettext_current_cache] = cache
69
+ end
70
+
71
+ #global, since re-parsing whole folders takes too much time...
72
+ @@translation_repositories={}
73
+ def translation_repositories
74
+ @@translation_repositories
75
+ end
76
+
77
+ # used to speedup simple translations, does not work for pluralisation
78
+ # caches[text_domain][locale][key]=translation
79
+ @@caches={}
80
+ def caches
81
+ @@caches
82
+ end
83
+
84
+ def current_repository
85
+ translation_repositories[text_domain] || raise(NoTextDomainConfigured)
86
+ end
87
+
88
+ def key_exist?(key)
89
+ !!(cached_find key)
90
+ end
91
+
92
+ def cached_find(key)
93
+ translation = current_cache[key]
94
+ return translation if translation or translation == false #found or was not found before
95
+ current_cache[key] = current_repository[key] || false
96
+ end
97
+
98
+ def cached_plural_find(*keys)
99
+ key = '||||' + keys * '||||'
100
+ translation = current_cache[key]
101
+ return translation if translation or translation == false #found or was not found before
102
+ current_cache[key] = current_repository.plural(*keys) || false
103
+ end
104
+
105
+ def locale
106
+ _locale || ( default_locale || (available_locales||[]).first || 'en' )
107
+ end
108
+
109
+ def locale=(new_locale)
110
+ new_locale = best_locale_in(new_locale)
111
+ self._locale = new_locale if new_locale
112
+ end
113
+
114
+ # for chaining: puts set_locale('xx') == 'xx' ? 'applied' : 'rejected'
115
+ # returns the current locale, not the one that was supplied
116
+ # like locale=(), whoes behavior cannot be changed
117
+ def set_locale(new_locale)
118
+ self.locale = new_locale
119
+ locale
120
+ end
121
+
122
+ @@default_locale = nil
123
+ def default_locale=(new_locale)
124
+ @@default_locale = best_locale_in(new_locale)
125
+ update_current_cache
126
+ end
127
+
128
+ def default_locale
129
+ @@default_locale
130
+ end
131
+
132
+ #Opera: de-DE,de;q=0.9,en;q=0.8
133
+ #Firefox de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
134
+ #IE6/7 de
135
+ #nil if nothing matches
136
+ def best_locale_in(locales)
137
+ formatted_sorted_locales(locales).each do |candidate|
138
+ return candidate if not available_locales
139
+ return candidate if available_locales.include?(candidate)
140
+ return candidate[0..1] if available_locales.include?(candidate[0..1])#available locales include a langauge
141
+ end
142
+ return nil#nothing found im sorry :P
143
+ end
144
+
145
+ #turn off translation if none was defined to disable all resulting errors
146
+ def silence_errors
147
+ require 'fast_gettext/translation_repository/base'
148
+ translation_repositories[text_domain] = TranslationRepository::Base.new('x')
149
+ end
150
+
151
+ private
152
+
153
+ # de-de,DE-CH;q=0.9 -> ['de_DE','de_CH']
154
+ def formatted_sorted_locales(locales)
155
+ found = weighted_locales(locales).reject{|x|x.empty?}.sort_by{|l|l.last}.reverse #sort them by weight which is the last entry
156
+ found.flatten.map{|l| format_locale(l)}
157
+ end
158
+
159
+ #split the locale and seperate it into different languages
160
+ #de-de,de;q=0.9,en;q=0.8 => [['de-de','de','0.5'], ['en','0.8']]
161
+ def weighted_locales(locales)
162
+ locales = locales.to_s.gsub(/\s/,'')
163
+ found = [[]]
164
+ locales.split(',').each do |part|
165
+ if part =~ /;q=/ #contains language and weight ?
166
+ found.last << part.split(/;q=/)
167
+ found.last.flatten!
168
+ found << []
169
+ else
170
+ found.last << part
171
+ end
172
+ end
173
+ found
174
+ end
175
+
176
+ #de-de -> de_DE
177
+ def format_locale(locale)
178
+ locale.sub(/^([a-zA-Z]{2})[-_]([a-zA-Z]{2})$/){$1.downcase+'_'+$2.upcase}
179
+ end
180
+
181
+ def update_current_cache
182
+ caches[text_domain] ||= {}
183
+ caches[text_domain][locale] ||= {}
184
+ caches[text_domain][locale][""] = false #ignore gettext meta key when translating
185
+ self.current_cache = caches[text_domain][locale]
186
+ end
187
+ end
188
+ end