lewagon 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/CHANGELOG.md +0 -0
- data/History.md +0 -0
- data/License.txt +20 -0
- data/README.md +0 -0
- data/bin/lewagon +5 -0
- data/lib/helpers/base58.rb +22 -0
- data/lib/helpers/char.rb +66 -0
- data/lib/helpers/unique_generator.rb +60 -0
- data/lib/lewagon/it/batch380.rb +11 -0
- data/lib/lewagon/version.rb +5 -0
- data/lib/lewagon.rb +310 -0
- data/lib/locales/README.md +40 -0
- data/lib/locales/ar.yml +102 -0
- data/lib/locales/bg.yml +44 -0
- data/lib/locales/ca-CAT.yml +24 -0
- data/lib/locales/ca.yml +23 -0
- data/lib/locales/da-DK.yml +73 -0
- data/lib/locales/de-AT.yml +56 -0
- data/lib/locales/de-CH.yml +19 -0
- data/lib/locales/de.yml +174 -0
- data/lib/locales/ee.yml +61 -0
- data/lib/locales/en/README.md +13 -0
- data/lib/locales/en/batch380.yml +4 -0
- data/lib/locales/en-AU.yml +28 -0
- data/lib/locales/en-BORK.yml +4 -0
- data/lib/locales/en-CA.yml +37 -0
- data/lib/locales/en-GB.yml +14 -0
- data/lib/locales/en-IND.yml +25 -0
- data/lib/locales/en-MS.yml +47 -0
- data/lib/locales/en-NEP.yml +49 -0
- data/lib/locales/en-NG.yml +77 -0
- data/lib/locales/en-NZ.yml +163 -0
- data/lib/locales/en-PAK.yml +18 -0
- data/lib/locales/en-SG.yml +35 -0
- data/lib/locales/en-TH.yml +360 -0
- data/lib/locales/en-UG.yml +128 -0
- data/lib/locales/en-US.yml +103 -0
- data/lib/locales/en-ZA.yml +148 -0
- data/lib/locales/en-au-ocker.yml +33 -0
- data/lib/locales/en.yml +11 -0
- data/lib/locales/es-MX.yml +105 -0
- data/lib/locales/es.yml +94 -0
- data/lib/locales/fa.yml +12 -0
- data/lib/locales/fi-FI.yml +35 -0
- data/lib/locales/fr-CA.yml +91 -0
- data/lib/locales/fr-CH.yml +78 -0
- data/lib/locales/fr.yml +115 -0
- data/lib/locales/he.yml +27 -0
- data/lib/locales/hy.yml +411 -0
- data/lib/locales/id.yml +24 -0
- data/lib/locales/it.yml +70 -0
- data/lib/locales/ja.yml +101 -0
- data/lib/locales/ko.yml +40 -0
- data/lib/locales/lv.yml +55 -0
- data/lib/locales/nb-NO.yml +62 -0
- data/lib/locales/nl.yml +92 -0
- data/lib/locales/no.yml +7 -0
- data/lib/locales/pl.yml +77 -0
- data/lib/locales/pt-BR.yml +718 -0
- data/lib/locales/pt.yml +66 -0
- data/lib/locales/ru.yml +76 -0
- data/lib/locales/sk.yml +78 -0
- data/lib/locales/sv.yml +81 -0
- data/lib/locales/th.yml +380 -0
- data/lib/locales/tr.yml +40 -0
- data/lib/locales/uk.yml +86 -0
- data/lib/locales/vi.yml +68 -0
- data/lib/locales/zh-CN.yml +56 -0
- data/lib/locales/zh-TW.yml +29 -0
- metadata +251 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5a59249bc762cfa6daf8e175b35a9ec859631d6a91c491a7e037c978dd4c46c1
|
4
|
+
data.tar.gz: 9d4a6f53e49e0fcae7f4bc022644bdaa1faa77cab7116fe9f13ec7c1b5aacb44
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3eea5ad6939d073a9921dc15a7252784bd91380c1e0a274b68803b5d40a4c9e20e94771f523b66b87803f60a0dadeec3d2a3f8ef24a1352dc2b66cef3aa7c658
|
7
|
+
data.tar.gz: 51f1cbb761a7b514bc84bbf40eef83565f9646b3db1c42b3b4277d959c94d62a9cca4c2322270953ae51c0ee980e621f656c64a13deff07dc0d15d8b3ee56228
|
data/CHANGELOG.md
ADDED
File without changes
|
data/History.md
ADDED
File without changes
|
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007-2019 Benjamin Curtis
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
File without changes
|
data/bin/lewagon
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LeWagon
|
4
|
+
module Base58
|
5
|
+
def self.encode(str)
|
6
|
+
alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
7
|
+
base = alphabet.size
|
8
|
+
|
9
|
+
lv = 0
|
10
|
+
str.split('').reverse.each_with_index { |v, i| lv += v.unpack('C')[0] * 256**i }
|
11
|
+
|
12
|
+
ret = +''
|
13
|
+
while lv.positive?
|
14
|
+
lv, mod = lv.divmod(base)
|
15
|
+
ret << alphabet[mod]
|
16
|
+
end
|
17
|
+
|
18
|
+
npad = str.match(/^#{0.chr}*/)[0].to_s.size
|
19
|
+
'1' * npad + ret.reverse
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/helpers/char.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LeWagon
|
4
|
+
module Char
|
5
|
+
def self.prepare(string)
|
6
|
+
result = romanize_cyrillic string
|
7
|
+
result = fix_umlauts result
|
8
|
+
result.gsub(/\W/, '').downcase
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.fix_umlauts(string)
|
12
|
+
string.gsub(/[äöüß]/i) do |match|
|
13
|
+
case match.downcase
|
14
|
+
when 'ä' then 'ae'
|
15
|
+
when 'ö' then 'oe'
|
16
|
+
when 'ü' then 'ue'
|
17
|
+
when 'ß' then 'ss'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.romanize_cyrillic(string)
|
23
|
+
if LeWagon::Config.locale == 'uk'
|
24
|
+
# Based on conventions abopted by BGN/PCGN for Ukrainian
|
25
|
+
uk_chars = {
|
26
|
+
'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'h', 'ґ' => 'g', 'д' => 'd',
|
27
|
+
'е' => 'e', 'є' => 'ye', 'ж' => 'zh', 'з' => 'z', 'и' => 'y', 'і' => 'i',
|
28
|
+
'ї' => 'yi', 'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n',
|
29
|
+
'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't', 'у' => 'u',
|
30
|
+
'ф' => 'f', 'х' => 'kh', 'ц' => 'ts', 'ч' => 'ch', 'ш' => 'sh', 'щ' => 'shch',
|
31
|
+
'ю' => 'yu', 'я' => 'ya',
|
32
|
+
'А' => 'a', 'Б' => 'b', 'В' => 'v', 'Г' => 'h', 'Ґ' => 'g', 'Д' => 'd',
|
33
|
+
'Е' => 'e', 'Є' => 'ye', 'Ж' => 'zh', 'З' => 'z', 'И' => 'y', 'І' => 'i',
|
34
|
+
'Ї' => 'yi', 'Й' => 'y', 'К' => 'k', 'Л' => 'l', 'М' => 'm', 'Н' => 'n',
|
35
|
+
'О' => 'o', 'П' => 'p', 'Р' => 'r', 'С' => 's', 'Т' => 't', 'У' => 'u',
|
36
|
+
'Ф' => 'f', 'Х' => 'kh', 'Ц' => 'ts', 'Ч' => 'ch', 'Ш' => 'sh', 'Щ' => 'shch',
|
37
|
+
'Ю' => 'yu', 'Я' => 'ya',
|
38
|
+
'ь' => '' # Ignore symbol, because its standard presentation is not allowed in URLs
|
39
|
+
}
|
40
|
+
return string.gsub(/[а-яА-ЯіїєґІЇЄҐ]/, uk_chars)
|
41
|
+
end
|
42
|
+
|
43
|
+
if LeWagon::Config.locale == 'ru'
|
44
|
+
# Based on conventions abopted by BGN/PCGN for Russian
|
45
|
+
ru_chars = {
|
46
|
+
'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'h', 'д' => 'd', 'е' => 'e',
|
47
|
+
'ё' => 'ye', 'ж' => 'zh', 'з' => 'z', 'и' => 'i', 'й' => 'y', 'к' => 'k',
|
48
|
+
'л' => 'l', 'м' => 'm', 'н' => 'n', 'о' => 'o', 'п' => 'p', 'р' => 'r',
|
49
|
+
'с' => 's', 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'kh', 'ц' => 'ts',
|
50
|
+
'ч' => 'ch', 'ш' => 'sh', 'щ' => 'shch', 'ы' => 'у', 'э' => 'e', 'ю' => 'yu',
|
51
|
+
'я' => 'ya',
|
52
|
+
'А' => 'a', 'Б' => 'b', 'В' => 'v', 'Г' => 'h', 'Д' => 'd', 'Е' => 'e',
|
53
|
+
'Ё' => 'ye', 'Ж' => 'zh', 'З' => 'z', 'И' => 'i', 'Й' => 'y', 'К' => 'k',
|
54
|
+
'Л' => 'l', 'М' => 'm', 'Н' => 'n', 'О' => 'o', 'П' => 'p', 'Р' => 'r',
|
55
|
+
'С' => 's', 'Т' => 't', 'У' => 'u', 'Ф' => 'f', 'Х' => 'kh', 'Ц' => 'ts',
|
56
|
+
'Ч' => 'ch', 'Ш' => 'sh', 'Щ' => 'shch', 'Ы' => 'у', 'Э' => 'e', 'Ю' => 'yu',
|
57
|
+
'Я' => 'ya',
|
58
|
+
'ь' => '', 'ъ' => '' # Ignore symbols, because its standard presentation is not allowed in URLs
|
59
|
+
}
|
60
|
+
return string.gsub(/[а-яА-Я]/, ru_chars)
|
61
|
+
end
|
62
|
+
|
63
|
+
string
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LeWagon
|
4
|
+
class UniqueGenerator
|
5
|
+
@marked_unique = Set.new # Holds names of generators with unique values
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_reader :marked_unique
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(generator, max_retries)
|
12
|
+
@generator = generator
|
13
|
+
@max_retries = max_retries
|
14
|
+
@previous_results = Hash.new { |hash, key| hash[key] = Set.new }
|
15
|
+
end
|
16
|
+
|
17
|
+
# rubocop:disable Style/MethodMissingSuper
|
18
|
+
def method_missing(name, *arguments)
|
19
|
+
self.class.marked_unique.add(self)
|
20
|
+
|
21
|
+
@max_retries.times do
|
22
|
+
result = @generator.public_send(name, *arguments)
|
23
|
+
|
24
|
+
next if @previous_results[[name, arguments]].include?(result)
|
25
|
+
|
26
|
+
@previous_results[[name, arguments]] << result
|
27
|
+
return result
|
28
|
+
end
|
29
|
+
|
30
|
+
raise RetryLimitExceeded, "Retry limit exceeded for #{name}"
|
31
|
+
end
|
32
|
+
# Have method_missing use ruby 2.x keywords if the method exists.
|
33
|
+
# This is necessary because the syntax for passing arguments (`...`)
|
34
|
+
# is invalid on versions before Ruby 2.7, so it can't be used.
|
35
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
36
|
+
# rubocop:enable Style/MethodMissingSuper
|
37
|
+
|
38
|
+
def respond_to_missing?(method_name, include_private = false)
|
39
|
+
method_name.to_s.start_with?('lewagon_') || super
|
40
|
+
end
|
41
|
+
|
42
|
+
RetryLimitExceeded = Class.new(StandardError)
|
43
|
+
|
44
|
+
def clear
|
45
|
+
@previous_results.clear
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.clear
|
49
|
+
marked_unique.each(&:clear)
|
50
|
+
marked_unique.clear
|
51
|
+
end
|
52
|
+
|
53
|
+
def exclude(name, arguments, values)
|
54
|
+
values ||= []
|
55
|
+
values.each do |value|
|
56
|
+
@previous_results[[name, arguments]] << value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/lewagon.rb
ADDED
@@ -0,0 +1,310 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
mydir = __dir__
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'psych'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'i18n'
|
10
|
+
require 'set' # Fixes a bug in i18n 0.6.11
|
11
|
+
|
12
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'helpers', '*.rb')).sort.each { |file| require file }
|
13
|
+
|
14
|
+
I18n.load_path += Dir[File.join(mydir, 'locales', '**/*.yml')]
|
15
|
+
I18n.reload! if I18n.backend.initialized?
|
16
|
+
|
17
|
+
module LeWagon
|
18
|
+
class Config
|
19
|
+
@locale = nil
|
20
|
+
@random = nil
|
21
|
+
|
22
|
+
class << self
|
23
|
+
attr_writer :locale
|
24
|
+
attr_writer :random
|
25
|
+
|
26
|
+
def locale
|
27
|
+
@locale || I18n.locale
|
28
|
+
end
|
29
|
+
|
30
|
+
def own_locale
|
31
|
+
@locale
|
32
|
+
end
|
33
|
+
|
34
|
+
def random
|
35
|
+
@random || Random::DEFAULT
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Base
|
41
|
+
Numbers = Array(0..9)
|
42
|
+
ULetters = Array('A'..'Z')
|
43
|
+
LLetters = Array('a'..'z')
|
44
|
+
Letters = ULetters + LLetters
|
45
|
+
|
46
|
+
class << self
|
47
|
+
NOT_GIVEN = Object.new
|
48
|
+
|
49
|
+
## by default numerify results do not start with a zero
|
50
|
+
def numerify(number_string, leading_zero: false)
|
51
|
+
return number_string.gsub(/#/) { rand(10).to_s } if leading_zero
|
52
|
+
|
53
|
+
number_string.sub(/#/) { rand(1..9).to_s }.gsub(/#/) { rand(10).to_s }
|
54
|
+
end
|
55
|
+
|
56
|
+
def letterify(letter_string)
|
57
|
+
letter_string.gsub(/\?/) { sample(ULetters) }
|
58
|
+
end
|
59
|
+
|
60
|
+
def bothify(string)
|
61
|
+
letterify(numerify(string))
|
62
|
+
end
|
63
|
+
|
64
|
+
# Given a regular expression, attempt to generate a string
|
65
|
+
# that would match it. This is a rather simple implementation,
|
66
|
+
# so don't be shocked if it blows up on you in a spectacular fashion.
|
67
|
+
#
|
68
|
+
# It does not handle ., *, unbounded ranges such as {1,},
|
69
|
+
# extensions such as (?=), character classes, some abbreviations
|
70
|
+
# for character classes, and nested parentheses.
|
71
|
+
#
|
72
|
+
# I told you it was simple. :) It's also probably dog-slow,
|
73
|
+
# so you shouldn't use it.
|
74
|
+
#
|
75
|
+
# It will take a regex like this:
|
76
|
+
#
|
77
|
+
# /^[A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]? {1,2}[0-9][ABD-HJLN-UW-Z]{2}$/
|
78
|
+
#
|
79
|
+
# and generate a string like this:
|
80
|
+
#
|
81
|
+
# "U3V 3TP"
|
82
|
+
#
|
83
|
+
def regexify(reg)
|
84
|
+
reg = reg.source if reg.respond_to?(:source) # Handle either a Regexp or a String that looks like a Regexp
|
85
|
+
reg
|
86
|
+
.gsub(%r{^\/?\^?}, '').gsub(%r{\$?\/?$}, '') # Ditch the anchors
|
87
|
+
.gsub(/\{(\d+)\}/, '{\1,\1}').gsub(/\?/, '{0,1}') # All {2} become {2,2} and ? become {0,1}
|
88
|
+
.gsub(/(\[[^\]]+\])\{(\d+),(\d+)\}/) { |_match| Regexp.last_match(1) * sample(Array(Range.new(Regexp.last_match(2).to_i, Regexp.last_match(3).to_i))) } # [12]{1,2} becomes [12] or [12][12]
|
89
|
+
.gsub(/(\([^\)]+\))\{(\d+),(\d+)\}/) { |_match| Regexp.last_match(1) * sample(Array(Range.new(Regexp.last_match(2).to_i, Regexp.last_match(3).to_i))) } # (12|34){1,2} becomes (12|34) or (12|34)(12|34)
|
90
|
+
.gsub(/(\\?.)\{(\d+),(\d+)\}/) { |_match| Regexp.last_match(1) * sample(Array(Range.new(Regexp.last_match(2).to_i, Regexp.last_match(3).to_i))) } # A{1,2} becomes A or AA or \d{3} becomes \d\d\d
|
91
|
+
.gsub(/\((.*?)\)/) { |match| sample(match.gsub(/[\(\)]/, '').split('|')) } # (this|that) becomes 'this' or 'that'
|
92
|
+
.gsub(/\[([^\]]+)\]/) { |match| match.gsub(/(\w\-\w)/) { |range| sample(Array(Range.new(*range.split('-')))) } } # All A-Z inside of [] become C (or X, or whatever)
|
93
|
+
.gsub(/\[([^\]]+)\]/) { |_match| sample(Regexp.last_match(1).split('')) } # All [ABC] become B (or A or C)
|
94
|
+
.gsub('\d') { |_match| sample(Numbers) }
|
95
|
+
.gsub('\w') { |_match| sample(Letters) }
|
96
|
+
end
|
97
|
+
|
98
|
+
# Helper for the common approach of grabbing a translation
|
99
|
+
# with an array of values and selecting one of them.
|
100
|
+
def fetch(key)
|
101
|
+
fetched = sample(translate("lewagon.#{key}"))
|
102
|
+
if fetched&.match(%r{^\/}) && fetched&.match(%r{\/$}) # A regex
|
103
|
+
regexify(fetched)
|
104
|
+
else
|
105
|
+
fetched
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Helper for the common approach of grabbing a translation
|
110
|
+
# with an array of values and returning all of them.
|
111
|
+
def fetch_all(key)
|
112
|
+
fetched = translate("lewagon.#{key}")
|
113
|
+
fetched = fetched.last if fetched.size <= 1
|
114
|
+
if !fetched.respond_to?(:sample) && fetched.match(%r{^\/}) && fetched.match(%r{\/$}) # A regex
|
115
|
+
regexify(fetched)
|
116
|
+
else
|
117
|
+
fetched
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Load formatted strings from the locale, "parsing" them
|
122
|
+
# into method calls that can be used to generate a
|
123
|
+
# formatted translation: e.g., "#{first_name} #{last_name}".
|
124
|
+
def parse(key)
|
125
|
+
fetched = fetch(key)
|
126
|
+
parts = fetched.scan(/(\(?)#\{([A-Za-z]+\.)?([^\}]+)\}([^#]+)?/).map do |prefix, kls, meth, etc|
|
127
|
+
# If the token had a class Prefix (e.g., Name.first_name)
|
128
|
+
# grab the constant, otherwise use self
|
129
|
+
cls = kls ? LeWagon.const_get(kls.chop) : self
|
130
|
+
|
131
|
+
# If an optional leading parentheses is not present, prefix.should == "", otherwise prefix.should == "("
|
132
|
+
# In either case the information will be retained for reconstruction of the string.
|
133
|
+
text = prefix
|
134
|
+
|
135
|
+
# If the class has the method, call it, otherwise fetch the transation
|
136
|
+
# (e.g., lewagon.phone_number.area_code)
|
137
|
+
text += if cls.respond_to?(meth)
|
138
|
+
cls.send(meth)
|
139
|
+
else
|
140
|
+
# Do just enough snake casing to convert PhoneNumber to phone_number
|
141
|
+
key_path = cls.to_s.split('::').last.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
|
142
|
+
fetch("#{key_path}.#{meth.downcase}")
|
143
|
+
end
|
144
|
+
|
145
|
+
# And tack on spaces, commas, etc. left over in the string
|
146
|
+
text + etc.to_s
|
147
|
+
end
|
148
|
+
# If the fetched key couldn't be parsed, then fallback to numerify
|
149
|
+
parts.any? ? parts.join : numerify(fetched)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Call I18n.translate with our configured locale if no
|
153
|
+
# locale is specified
|
154
|
+
def translate(*args, **opts)
|
155
|
+
opts[:locale] ||= LeWagon::Config.locale
|
156
|
+
opts[:raise] = true
|
157
|
+
I18n.translate(*args, **opts)
|
158
|
+
rescue I18n::MissingTranslationData
|
159
|
+
opts[:locale] = :en
|
160
|
+
|
161
|
+
# Super-simple fallback -- fallback to en if the
|
162
|
+
# translation was missing. If the translation isn't
|
163
|
+
# in en either, then it will raise again.
|
164
|
+
disable_enforce_available_locales do
|
165
|
+
I18n.translate(*args, **opts)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Executes block with given locale set.
|
170
|
+
def with_locale(tmp_locale = nil)
|
171
|
+
current_locale = LeWagon::Config.own_locale
|
172
|
+
LeWagon::Config.locale = tmp_locale
|
173
|
+
|
174
|
+
disable_enforce_available_locales do
|
175
|
+
I18n.with_locale(tmp_locale) { yield }
|
176
|
+
end
|
177
|
+
ensure
|
178
|
+
LeWagon::Config.locale = current_locale
|
179
|
+
end
|
180
|
+
|
181
|
+
def flexible(key)
|
182
|
+
@flexible_key = key
|
183
|
+
end
|
184
|
+
|
185
|
+
# You can add whatever you want to the locale file, and it will get caught here.
|
186
|
+
# E.g., in your locale file, create a
|
187
|
+
# name:
|
188
|
+
# girls_name: ["Alice", "Cheryl", "Tatiana"]
|
189
|
+
# Then you can call LeWagon::Name.girls_name and it will act like #first_name
|
190
|
+
def method_missing(mth, *args, &block)
|
191
|
+
super unless @flexible_key
|
192
|
+
|
193
|
+
if (translation = translate("lewagon.#{@flexible_key}.#{mth}"))
|
194
|
+
sample(translation)
|
195
|
+
else
|
196
|
+
super
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def respond_to_missing?(method_name, include_private = false)
|
201
|
+
super
|
202
|
+
end
|
203
|
+
|
204
|
+
# Generates a random value between the interval
|
205
|
+
def rand_in_range(from, to)
|
206
|
+
from, to = to, from if to < from
|
207
|
+
rand(from..to)
|
208
|
+
end
|
209
|
+
|
210
|
+
# If an array or range is passed, a random value will be selected.
|
211
|
+
# All other values are simply returned.
|
212
|
+
def resolve(value)
|
213
|
+
case value
|
214
|
+
when Array then sample(value)
|
215
|
+
when Range then rand value
|
216
|
+
else value
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Return unique values from the generator every time.
|
221
|
+
#
|
222
|
+
# @param max_retries [Integer] The max number of retries that should be done before giving up.
|
223
|
+
# @return [self]
|
224
|
+
def unique(max_retries = 10_000)
|
225
|
+
@unique ||= UniqueGenerator.new(self, max_retries)
|
226
|
+
end
|
227
|
+
|
228
|
+
def sample(list)
|
229
|
+
list.respond_to?(:sample) ? list.sample(random: LeWagon::Config.random) : list
|
230
|
+
end
|
231
|
+
|
232
|
+
def shuffle(list)
|
233
|
+
list.shuffle(random: LeWagon::Config.random)
|
234
|
+
end
|
235
|
+
|
236
|
+
def rand(max = nil)
|
237
|
+
if max.nil?
|
238
|
+
LeWagon::Config.random.rand
|
239
|
+
elsif max.is_a?(Range) || max.to_i.positive?
|
240
|
+
LeWagon::Config.random.rand(max)
|
241
|
+
else
|
242
|
+
0
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def disable_enforce_available_locales
|
247
|
+
old_enforce_available_locales = I18n.enforce_available_locales
|
248
|
+
I18n.enforce_available_locales = false
|
249
|
+
yield
|
250
|
+
ensure
|
251
|
+
I18n.enforce_available_locales = old_enforce_available_locales
|
252
|
+
end
|
253
|
+
|
254
|
+
private
|
255
|
+
|
256
|
+
def warn_for_deprecated_arguments
|
257
|
+
keywords = []
|
258
|
+
yield(keywords)
|
259
|
+
|
260
|
+
return if keywords.empty?
|
261
|
+
|
262
|
+
method_name = caller.first.match(/`(?<method_name>.*)'/)[:method_name]
|
263
|
+
|
264
|
+
keywords.each.with_index(1) do |keyword, index|
|
265
|
+
i = case index
|
266
|
+
when 1 then '1st'
|
267
|
+
when 2 then '2nd'
|
268
|
+
when 3 then '3rd'
|
269
|
+
else "#{index}th"
|
270
|
+
end
|
271
|
+
|
272
|
+
warn_with_uplevel(<<~MSG, uplevel: 5)
|
273
|
+
Passing `#{keyword}` with the #{i} argument of `#{method_name}` is deprecated. Use keyword argument like `#{method_name}(#{keyword}: ...)` instead.
|
274
|
+
MSG
|
275
|
+
end
|
276
|
+
|
277
|
+
warn(<<~MSG)
|
278
|
+
|
279
|
+
To automatically update from positional arguments to keyword arguments,
|
280
|
+
install rubocop-lewagon and run:
|
281
|
+
|
282
|
+
rubocop \\
|
283
|
+
--require rubocop-lewagon \\
|
284
|
+
--only LeWagon/DeprecatedArguments \\
|
285
|
+
--auto-correct
|
286
|
+
|
287
|
+
MSG
|
288
|
+
end
|
289
|
+
|
290
|
+
# Workaround for emulating `warn '...', uplevel: 1` in Ruby 2.4 or lower.
|
291
|
+
def warn_with_uplevel(message, uplevel: 1)
|
292
|
+
at = parse_caller(caller[uplevel]).join(':')
|
293
|
+
warn "#{at}: #{message}"
|
294
|
+
end
|
295
|
+
|
296
|
+
def parse_caller(at)
|
297
|
+
# rubocop:disable Style/GuardClause
|
298
|
+
if /^(.+?):(\d+)(?::in `.*')?/ =~ at
|
299
|
+
file = Regexp.last_match(1)
|
300
|
+
line = Regexp.last_match(2).to_i
|
301
|
+
[file, line]
|
302
|
+
end
|
303
|
+
# rubocop:enable Style/GuardClause
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
# require lewagon objects
|
310
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'lewagon', '/**/*.rb')).sort.each { |file| require file }
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# How Locales Work
|
2
|
+
|
3
|
+
The default locale is English. You can see how it is implemented in the "translate" method in [LeWagon.rb](/lib/lewagon.rb).
|
4
|
+
|
5
|
+
Here's how to set it:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
# Sets the locale to "Simplified Chinese":
|
9
|
+
LeWagon::Config.locale = 'zh-CN'
|
10
|
+
```
|
11
|
+
|
12
|
+
It works so that once the LeWagon locale is set to a different location, the translate method will check that .yml file for an equivalent and use that data. If it doesn't exist, it defaults back to English. It uses the "i18n" gem to do this.
|
13
|
+
|
14
|
+
Using Chinese as an example, when the locale is set to Chinese and you attempt to call for hipster ipsem (which doesn't exist at the time of this writing), you will get English back. It checks the "zh-CH.yml" file, does not find "hipster" and then checks the "en.yml" file and returns a word from that array.
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
LeWagon::Config.locale = 'zh-CN'
|
18
|
+
LeWagon::Hipster.word #=> "kogi"
|
19
|
+
```
|
20
|
+
|
21
|
+
In order to update a locale with more translation features, simply add a new field to the .yml file that corresponds to an existing piece of functionality in the "en.yml" file. In this example, that would mean providing Chinese hipster words.
|
22
|
+
|
23
|
+
```yaml
|
24
|
+
# /lib/locales/zh-CN.yml
|
25
|
+
hipster:
|
26
|
+
- "屌丝"
|
27
|
+
```
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
# Now this should work:
|
31
|
+
LeWagon::Hipster.word #=> "屌丝"
|
32
|
+
```
|
33
|
+
|
34
|
+
After you've done that, find or create a test file for the locale you've updated and test the functionality for that language.
|
35
|
+
|
36
|
+
In our hypothetical example here, one would add something like this to the "test-zh-locale.rb" file in the "test_ch_methods" method:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
assert LeWagon::Hipster.word.is_a? String
|
40
|
+
```
|