when_exe 0.3.6 → 0.3.7

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 (117) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +171 -0
  3. data/lib/when_exe.rb +78 -47
  4. data/lib/when_exe/basictypes.rb +752 -747
  5. data/lib/when_exe/calendarnote.rb +805 -801
  6. data/lib/when_exe/calendartypes.rb +1583 -1531
  7. data/lib/when_exe/coordinates.rb +16 -15
  8. data/lib/when_exe/core/duration.rb +114 -110
  9. data/lib/when_exe/core/extension.rb +504 -504
  10. data/lib/when_exe/ephemeris.rb +1917 -1913
  11. data/lib/when_exe/ephemeris/moon.rb +333 -333
  12. data/lib/when_exe/ephemeris/notes.rb +389 -387
  13. data/lib/when_exe/ephemeris/planets.rb +585 -585
  14. data/lib/when_exe/ephemeris/sun.rb +214 -214
  15. data/lib/when_exe/googlecalendar.rb +144 -140
  16. data/lib/when_exe/icalendar.rb +1636 -1636
  17. data/lib/when_exe/inspect.rb +46 -22
  18. data/lib/when_exe/locales/akt.rb +176 -176
  19. data/lib/when_exe/locales/encoding_conversion.rb +134 -126
  20. data/lib/when_exe/locales/iast.rb +90 -90
  21. data/lib/when_exe/locales/locale.rb +750 -746
  22. data/lib/when_exe/locales/transliteration_table.rb +62 -62
  23. data/lib/when_exe/mini_application.rb +307 -305
  24. data/lib/when_exe/parts/enumerator.rb +2 -2
  25. data/lib/when_exe/parts/geometric_complex.rb +397 -397
  26. data/lib/when_exe/parts/method_cash.rb +224 -224
  27. data/lib/when_exe/parts/resource.rb +1069 -1071
  28. data/lib/when_exe/parts/timezone.rb +240 -230
  29. data/lib/when_exe/region/armenian.rb +56 -56
  30. data/lib/when_exe/region/babylonian.rb +405 -0
  31. data/lib/when_exe/region/bahai.rb +146 -146
  32. data/lib/when_exe/region/balinese.rb +622 -622
  33. data/lib/when_exe/region/chinese.rb +95 -25
  34. data/lib/when_exe/region/chinese/calendars.rb +1016 -1016
  35. data/lib/when_exe/region/chinese/epochs.rb +1 -1
  36. data/lib/when_exe/region/chinese/twins.rb +803 -795
  37. data/lib/when_exe/region/christian.rb +824 -824
  38. data/lib/when_exe/region/coptic.rb +106 -87
  39. data/lib/when_exe/region/discordian.rb +225 -225
  40. data/lib/when_exe/region/far_east.rb +188 -188
  41. data/lib/when_exe/region/french.rb +56 -56
  42. data/lib/when_exe/region/geologicalage.rb +639 -639
  43. data/lib/when_exe/region/goddess.rb +58 -58
  44. data/lib/when_exe/region/indian.rb +1254 -1251
  45. data/lib/when_exe/region/iranian.rb +8 -8
  46. data/lib/when_exe/region/islamic.rb +3 -3
  47. data/lib/when_exe/region/japanese.rb +93 -99
  48. data/lib/when_exe/region/japanese/calendars.rb +396 -397
  49. data/lib/when_exe/region/japanese/epochs.rb +26 -26
  50. data/lib/when_exe/region/japanese/nihon_shoki.rb +71 -71
  51. data/lib/when_exe/region/japanese/notes.rb +1383 -1386
  52. data/lib/when_exe/region/japanese/residues.rb +1306 -1306
  53. data/lib/when_exe/region/japanese/twins.rb +225 -225
  54. data/lib/when_exe/region/japanese/weeks.rb +112 -0
  55. data/lib/when_exe/region/javanese.rb +230 -230
  56. data/lib/when_exe/region/jewish.rb +126 -126
  57. data/lib/when_exe/region/korean.rb +378 -378
  58. data/lib/when_exe/region/m17n.rb +114 -113
  59. data/lib/when_exe/region/martian.rb +258 -255
  60. data/lib/when_exe/region/mayan.rb +32 -32
  61. data/lib/when_exe/region/residue.rb +89 -89
  62. data/lib/when_exe/region/roman.rb +36 -24
  63. data/lib/when_exe/region/ryukyu.rb +97 -97
  64. data/lib/when_exe/region/shire.rb +240 -240
  65. data/lib/when_exe/region/soviet.rb +209 -0
  66. data/lib/when_exe/region/symmetry.rb +50 -50
  67. data/lib/when_exe/region/thai.rb +336 -335
  68. data/lib/when_exe/region/tibetan.rb +316 -315
  69. data/lib/when_exe/region/vietnamese.rb +440 -439
  70. data/lib/when_exe/region/weekdate.rb +80 -80
  71. data/lib/when_exe/region/world.rb +175 -175
  72. data/lib/when_exe/region/yerm.rb +14 -14
  73. data/lib/when_exe/region/zoroastrian.rb +203 -203
  74. data/lib/when_exe/timestandard.rb +707 -681
  75. data/lib/when_exe/tmduration.rb +338 -330
  76. data/lib/when_exe/tmobjects.rb +1346 -1325
  77. data/lib/when_exe/tmposition.rb +2115 -2072
  78. data/lib/when_exe/tmreference.rb +1693 -1669
  79. data/lib/when_exe/version.rb +1 -1
  80. data/link_to_online_documents +1 -1
  81. data/test/examples/JapanHolidaysRFC6350.ics +1 -1
  82. data/test/test.rb +67 -61
  83. data/test/test/basictypes.rb +409 -409
  84. data/test/test/calendarnote.rb +86 -69
  85. data/test/test/calendartypes.rb +97 -97
  86. data/test/test/coordinates.rb +396 -396
  87. data/test/test/ephemeris.rb +83 -74
  88. data/test/test/ephemeris/moon.rb +14 -14
  89. data/test/test/ephemeris/planets.rb +14 -14
  90. data/test/test/ephemeris/sun.rb +14 -14
  91. data/test/test/googlecalendar.rb +194 -176
  92. data/test/test/icalendar.rb +867 -858
  93. data/test/test/inspect.rb +117 -117
  94. data/test/test/parts.rb +487 -487
  95. data/test/test/region/balinese.rb +34 -0
  96. data/test/test/region/chinese.rb +218 -206
  97. data/test/test/region/christian.rb +245 -245
  98. data/test/test/region/coptic.rb +27 -27
  99. data/test/test/region/french.rb +33 -33
  100. data/test/test/region/geologicalage.rb +17 -17
  101. data/test/test/region/indian.rb +57 -57
  102. data/test/test/region/iran.rb +54 -54
  103. data/test/test/region/islamic.rb +18 -18
  104. data/test/test/region/japanese.rb +237 -219
  105. data/test/test/region/jewish.rb +61 -61
  106. data/test/test/region/m17n.rb +184 -184
  107. data/test/test/region/mayan.rb +195 -195
  108. data/test/test/region/residue.rb +147 -139
  109. data/test/test/region/thai.rb +116 -116
  110. data/test/test/region/tibetan.rb +30 -30
  111. data/test/test/region/vietnamese.rb +102 -102
  112. data/test/test/region/yerm.rb +146 -146
  113. data/test/test/timestandard.rb +81 -81
  114. data/test/test/tmobjects.rb +328 -328
  115. data/test/test/tmposition.rb +397 -284
  116. data/test/test/tmreference.rb +157 -157
  117. metadata +13 -10
@@ -1,126 +1,134 @@
1
- # -*- coding: utf-8 -*-
2
- =begin
3
- Copyright (C) 2014 Takashi SUGA
4
-
5
- You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
- =end
7
-
8
- module When
9
-
10
- #
11
- # エンコーディングの変換
12
- #
13
- module EncodingConversion
14
-
15
- class << self
16
- if String.method_defined?(:encode)
17
- #
18
- # 内部エンコーディング文字列化
19
- #
20
- # @param [Object] source もとにする Object
21
- #
22
- # @return [Object] 内部エンコーディング化した Object
23
- #
24
- # @private
25
- def to_internal_encoding(source)
26
- default_internal = Encoding.default_internal||'UTF-8'
27
- case source
28
- when Locale ; source.to_internal_encoding
29
- when String ; (source.encoding == default_internal) ?
30
- source :
31
- source.encode(default_internal)
32
- when Regexp ; (source.encoding == default_internal) ?
33
- source :
34
- Regexp.new(source.to_s.encode(default_internal))
35
- when Array ; source.map {|e| to_internal_encoding(e)}
36
- when Hash
37
- hash = {}
38
- source.each_pair do |key, value|
39
- hash[to_internal_encoding(key)] = to_internal_encoding(value)
40
- end
41
- hash
42
- else ; source.respond_to?(:to_internal_encoding) ? source.to_internal_encoding : source
43
- end
44
- end
45
-
46
- #
47
- # 外部エンコーディング文字列化
48
- #
49
- # @param [Object] source もとにする Object
50
- #
51
- # @return [Object] 外部エンコーディング化した Object
52
- #
53
- # @private
54
- def to_external_encoding(source)
55
- default_external = Encoding.default_external
56
- case source
57
- when Locale ; source.to_external_encoding
58
- when String ; (source.encoding == default_external) ?
59
- source :
60
- source.encode(default_external)
61
- when Regexp ; (source.encoding == default_external) ?
62
- source :
63
- Regexp.new(source.to_s.encode(default_external))
64
- when Array ; source.map {|e| to_external_encoding(e)}
65
- when Hash
66
- hash = {}
67
- source.each_pair do |key, value|
68
- hash[to_external_encoding(key)] = to_external_encoding(value)
69
- end
70
- hash
71
- else ; source.respond_to?(:to_external_encoding) ? source.to_external_encoding : source
72
- end
73
- end
74
-
75
- else
76
- # 内部エンコーディング文字列化(ダミー)
77
- #
78
- # @param [String] string もとにする String または M17n
79
- #
80
- # @return [String] そのまま返す
81
- #
82
- def to_internal_encoding(string)
83
- string
84
- end
85
- #
86
- # 外部エンコーディング文字列化(ダミー)
87
- #
88
- # @param [String] string もとにする String または M17n
89
- #
90
- # @return [String] そのまま返す
91
- #
92
- def to_external_encoding(string)
93
- string
94
- end
95
- end
96
- end
97
-
98
- #
99
- # 内部エンコーディング文字列化
100
- #
101
- def to_internal_encoding
102
- EncodingConversion.to_internal_encoding(self)
103
- end
104
-
105
- #
106
- # 外部エンコーディング文字列化
107
- #
108
- def to_external_encoding
109
- EncodingConversion.to_external_encoding(self)
110
- end
111
-
112
- #
113
- # 内部エンコーディング文字列化(単項)
114
- #
115
- def +@
116
- to_internal_encoding
117
- end
118
-
119
- #
120
- # 外部エンコーディング文字列化(単項)
121
- #
122
- def -@
123
- to_external_encoding
124
- end
125
- end
126
- end
1
+ # -*- coding: utf-8 -*-
2
+ =begin
3
+ Copyright (C) 2014 Takashi SUGA
4
+
5
+ You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
+ =end
7
+
8
+ module When
9
+
10
+ #
11
+ # エンコーディングの変換
12
+ #
13
+ module EncodingConversion
14
+
15
+ class << self
16
+ if String.method_defined?(:encode)
17
+ #
18
+ # 内部エンコーディング文字列化
19
+ #
20
+ # @param [Object] source もとにする Object
21
+ #
22
+ # @return [Object] 内部エンコーディング化した Object
23
+ #
24
+ # @private
25
+ def to_internal_encoding(source)
26
+ default_internal = Encoding.default_internal||'UTF-8'
27
+ case source
28
+ when Locale ; source.to_internal_encoding
29
+ when String ; case source.encoding
30
+ when default_internal ; source
31
+ when Encoding::ASCII_8BIT ; source.dup.force_encoding(default_internal)
32
+ else ; source.encode(default_internal)
33
+ end
34
+ when Regexp ; case source.encoding
35
+ when default_internal ; source
36
+ when Encoding::ASCII_8BIT ; Regexp.new(source.dup.force_encoding(default_internal))
37
+ else ; Regexp.new(source.to_s.encode(default_internal))
38
+ end
39
+ when Array ; source.map {|e| to_internal_encoding(e)}
40
+ when Hash
41
+ hash = {}
42
+ source.each_pair do |key, value|
43
+ hash[to_internal_encoding(key)] = to_internal_encoding(value)
44
+ end
45
+ hash
46
+ else ; source.respond_to?(:to_internal_encoding) ? source.to_internal_encoding : source
47
+ end
48
+ end
49
+
50
+ #
51
+ # 外部エンコーディング文字列化
52
+ #
53
+ # @param [Object] source もとにする Object
54
+ #
55
+ # @return [Object] 外部エンコーディング化した Object
56
+ #
57
+ # @private
58
+ def to_external_encoding(source)
59
+ default_external = Encoding.default_external
60
+ case source
61
+ when Locale ; source.to_external_encoding
62
+ when String ; case source.encoding
63
+ when default_external ; source
64
+ when Encoding::ASCII_8BIT ; source.dup.force_encoding(default_external)
65
+ else ; source.encode(default_external)
66
+ end
67
+ when Regexp ; case source.encoding
68
+ when default_external ; source
69
+ when Encoding::ASCII_8BIT ; Regexp.new(source.dup.force_encoding(default_external))
70
+ else ; Regexp.new(source.to_s.encode(default_external))
71
+ end
72
+ when Array ; source.map {|e| to_external_encoding(e)}
73
+ when Hash
74
+ hash = {}
75
+ source.each_pair do |key, value|
76
+ hash[to_external_encoding(key)] = to_external_encoding(value)
77
+ end
78
+ hash
79
+ else ; source.respond_to?(:to_external_encoding) ? source.to_external_encoding : source
80
+ end
81
+ end
82
+
83
+ else
84
+ # 内部エンコーディング文字列化(ダミー)
85
+ #
86
+ # @param [String] string もとにする String または M17n
87
+ #
88
+ # @return [String] そのまま返す
89
+ #
90
+ def to_internal_encoding(string)
91
+ string
92
+ end
93
+ #
94
+ # 外部エンコーディング文字列化(ダミー)
95
+ #
96
+ # @param [String] string もとにする String または M17n
97
+ #
98
+ # @return [String] そのまま返す
99
+ #
100
+ def to_external_encoding(string)
101
+ string
102
+ end
103
+ end
104
+ end
105
+
106
+ #
107
+ # 内部エンコーディング文字列化
108
+ #
109
+ def to_internal_encoding
110
+ EncodingConversion.to_internal_encoding(self)
111
+ end
112
+
113
+ #
114
+ # 外部エンコーディング文字列化
115
+ #
116
+ def to_external_encoding
117
+ EncodingConversion.to_external_encoding(self)
118
+ end
119
+
120
+ #
121
+ # 内部エンコーディング文字列化(単項)
122
+ #
123
+ def +@
124
+ to_internal_encoding
125
+ end
126
+
127
+ #
128
+ # 外部エンコーディング文字列化(単項)
129
+ #
130
+ def -@
131
+ to_external_encoding
132
+ end
133
+ end
134
+ end
@@ -1,90 +1,90 @@
1
- # -*- coding: utf-8 -*-
2
- =begin
3
- Copyright (C) 2014 Takashi SUGA
4
-
5
- You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
- =end
7
-
8
- require 'when_exe/locales/transliteration_table'
9
-
10
- module When
11
- module Locale
12
-
13
- _IAST_Part_I = {
14
- "A" => "अ", "a" => "अ",
15
- "Ā" => "आ", "ā" => "आ",
16
- "I" => "इ", "i" => "इ",
17
- "Ī" => "ई", "ī" => "ई",
18
- "U" => "उ", "u" => "उ",
19
- "Ū" => "ऊ", "ū" => "ऊ",
20
- "Ṛ" => "ऋ", "ṛ" => "ऋ",
21
- "Ṝ" => "ॠ", "ṝ" => "ॠ",
22
- "Ḷ" => "ऌ", "ḷ" => "ऌ",
23
- "Ḹ" => "ॡ", "ḹ" => "ॡ",
24
- "E" => "ए", "e" => "ए",
25
- "Ai" => "ऐ", "ai" => "ऐ",
26
- "O" => "ओ", "o" => "ओ",
27
- "Au" => "औ", "au" => "औ",
28
- "Ṃ" => "अं", "ṃ" => "अं",
29
- "Ḥ" => "अः", "ḥ" => "अः",
30
- "'" => "अऽ",
31
-
32
- "K" => "क", "k" => "क",
33
- "C" => "च", "c" => "च",
34
- "Ṭ" => "ट", "ṭ" => "ट",
35
- "T" => "त", "t" => "त",
36
- "P" => "प", "p" => "प",
37
- "Kh" => "ख", "kh" => "ख",
38
- "Ch" => "छ", "ch" => "छ",
39
- "Ṭh" => "ठ", "ṭh" => "ठ",
40
- "Th" => "थ", "th" => "थ",
41
- "Ph" => "फ", "ph" => "फ",
42
- "G" => "ग", "g" => "ग",
43
- "J" => "ज", "j" => "ज",
44
- "Ḍ" => "ड", "ḍ" => "ड",
45
- "D" => "द", "d" => "द",
46
- "B" => "ब", "b" => "ब",
47
- "Gh" => "घ", "gh" => "घ",
48
- "Jh" => "झ", "jh" => "झ",
49
- "Ḍh" => "ढ", "ḍh" => "ढ",
50
- "Dh" => "ध", "dh" => "ध",
51
- "Bh" => "भ", "bh" => "भ",
52
- "Ṅ" => "ङ", "ṅ" => "ङ",
53
- "Ñ" => "ञ", "ñ" => "ञ",
54
- "Ṇ" => "ण", "ṇ" => "ण",
55
- "N" => "न", "n" => "न",
56
- "M" => "म", "m" => "म",
57
- "H" => "ह", "h" => "ह",
58
- "Y" => "य", "y" => "य",
59
- "R" => "र", "r" => "र",
60
- "L" => "ल", "l" => "ल",
61
- "V" => "व", "v" => "व",
62
- "Ś" => "श", "ś" => "श",
63
- "Ṣ" => "ष", "ṣ" => "ष",
64
- "S" => "स", "s" => "स"
65
- }
66
-
67
- _IAST_Part_II = {
68
- "R̥" => "ऋ", "r̥" => "ऋ",
69
- "R̥̄" => "ॠ", "r̥̄" => "ॠ",
70
- "Ē" => "ए", "ē" => "ए",
71
- "Ō" => "ओ", "ō" => "ओ",
72
- "Ṁ" => "अं", "ṁ" => "अं"
73
- }
74
-
75
- #
76
- # IAST: International Alphabet of Sanskrit Transliteration
77
- #
78
- IAST = {
79
- 'hi' => _IAST_Part_I.merge(_IAST_Part_II)
80
- }
81
-
82
- #
83
- # IASTR: International Alphabet of Sanskrit Transliteration - Reverse
84
- #
85
- IASTR = {
86
- 'hi' => _IAST_Part_I.invert
87
- }
88
-
89
- end
90
- end
1
+ # -*- coding: utf-8 -*-
2
+ =begin
3
+ Copyright (C) 2014 Takashi SUGA
4
+
5
+ You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
+ =end
7
+
8
+ require 'when_exe/locales/transliteration_table'
9
+
10
+ module When
11
+ module Locale
12
+
13
+ _IAST_Part_I = {
14
+ "A" => "अ", "a" => "अ",
15
+ "Ā" => "आ", "ā" => "आ",
16
+ "I" => "इ", "i" => "इ",
17
+ "Ī" => "ई", "ī" => "ई",
18
+ "U" => "उ", "u" => "उ",
19
+ "Ū" => "ऊ", "ū" => "ऊ",
20
+ "Ṛ" => "ऋ", "ṛ" => "ऋ",
21
+ "Ṝ" => "ॠ", "ṝ" => "ॠ",
22
+ "Ḷ" => "ऌ", "ḷ" => "ऌ",
23
+ "Ḹ" => "ॡ", "ḹ" => "ॡ",
24
+ "E" => "ए", "e" => "ए",
25
+ "Ai" => "ऐ", "ai" => "ऐ",
26
+ "O" => "ओ", "o" => "ओ",
27
+ "Au" => "औ", "au" => "औ",
28
+ "Ṃ" => "अं", "ṃ" => "अं",
29
+ "Ḥ" => "अः", "ḥ" => "अः",
30
+ "'" => "अऽ",
31
+
32
+ "K" => "क", "k" => "क",
33
+ "C" => "च", "c" => "च",
34
+ "Ṭ" => "ट", "ṭ" => "ट",
35
+ "T" => "त", "t" => "त",
36
+ "P" => "प", "p" => "प",
37
+ "Kh" => "ख", "kh" => "ख",
38
+ "Ch" => "छ", "ch" => "छ",
39
+ "Ṭh" => "ठ", "ṭh" => "ठ",
40
+ "Th" => "थ", "th" => "थ",
41
+ "Ph" => "फ", "ph" => "फ",
42
+ "G" => "ग", "g" => "ग",
43
+ "J" => "ज", "j" => "ज",
44
+ "Ḍ" => "ड", "ḍ" => "ड",
45
+ "D" => "द", "d" => "द",
46
+ "B" => "ब", "b" => "ब",
47
+ "Gh" => "घ", "gh" => "घ",
48
+ "Jh" => "झ", "jh" => "झ",
49
+ "Ḍh" => "ढ", "ḍh" => "ढ",
50
+ "Dh" => "ध", "dh" => "ध",
51
+ "Bh" => "भ", "bh" => "भ",
52
+ "Ṅ" => "ङ", "ṅ" => "ङ",
53
+ "Ñ" => "ञ", "ñ" => "ञ",
54
+ "Ṇ" => "ण", "ṇ" => "ण",
55
+ "N" => "न", "n" => "न",
56
+ "M" => "म", "m" => "म",
57
+ "H" => "ह", "h" => "ह",
58
+ "Y" => "य", "y" => "य",
59
+ "R" => "र", "r" => "र",
60
+ "L" => "ल", "l" => "ल",
61
+ "V" => "व", "v" => "व",
62
+ "Ś" => "श", "ś" => "श",
63
+ "Ṣ" => "ष", "ṣ" => "ष",
64
+ "S" => "स", "s" => "स"
65
+ }
66
+
67
+ _IAST_Part_II = {
68
+ "R̥" => "ऋ", "r̥" => "ऋ",
69
+ "R̥̄" => "ॠ", "r̥̄" => "ॠ",
70
+ "Ē" => "ए", "ē" => "ए",
71
+ "Ō" => "ओ", "ō" => "ओ",
72
+ "Ṁ" => "अं", "ṁ" => "अं"
73
+ }
74
+
75
+ #
76
+ # IAST: International Alphabet of Sanskrit Transliteration
77
+ #
78
+ IAST = {
79
+ 'hi' => _IAST_Part_I.merge(_IAST_Part_II)
80
+ }
81
+
82
+ #
83
+ # IASTR: International Alphabet of Sanskrit Transliteration - Reverse
84
+ #
85
+ IASTR = {
86
+ 'hi' => _IAST_Part_I.invert
87
+ }
88
+
89
+ end
90
+ end
@@ -1,746 +1,750 @@
1
- # -*- coding: utf-8 -*-
2
- =begin
3
- Copyright (C) 2011-2014 Takashi SUGA
4
-
5
- You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
- =end
7
-
8
- require 'when_exe/locales/encoding_conversion'
9
-
10
- module When
11
-
12
- #
13
- # Multilingualization(M17n) 対応モジュール
14
- #
15
- # When::BasicTypes::M17n の実装のうち When::BasicTypes 内部で
16
- # 定義すべきでない部分を切り出してモジュールとしている
17
- #
18
- module Locale
19
-
20
- # Locale 読み替えの初期設定
21
- DefaultAlias = {'alias'=>'ja', '日本語'=>'ja', '英語'=>'en'}
22
-
23
- # 省略時 Namespace
24
- DefaultNamespaces = Hash.new {|hash, key|
25
- hash[key] = "http://#{key}.wikipedia.org/wiki/"
26
- }.update({
27
- 'mailto' => false,
28
- 'https' => false,
29
- 'http' => false,
30
- 'ftp' => false
31
- })
32
-
33
- # 漢字の包摂
34
- DefaultUnification = {
35
- '煕'=>'熙', '廣'=>'広', '寶'=>'宝', '國'=>'国',
36
- '應'=>'応', '觀'=>'観', '龜'=>'亀', '齊'=>'斉',
37
- '靈'=>'霊', '攝'=>'摂', '壽'=>'寿', '萬'=>'万',
38
- '廢'=>'廃', '顯'=>'顕', '會'=>'会', '聰'=>'聡',
39
- '總'=>'総', '證'=>'証', '禮'=>'礼', '竜'=>'龍'
40
- }
41
-
42
- # Escape
43
- # @private
44
- Escape = {
45
- "\\\\" => "\\",
46
- "\\n" => "\n",
47
- "\\r" => "\r",
48
- "\\," => ","
49
- }
50
-
51
- # Wikipedia の URL の正規表現
52
- # @private
53
- Ref = /^http:\/\/(.+?)\.wikipedia\.org\/wiki\/([^#]+?)$/
54
-
55
- # Wikipedia の多言語リンクの正規表現
56
- # @private
57
- Link = /<li class="interlanguage-link interwiki-(.+?)"><a href="\/\/(.+?)\.wikipedia\.org\/wiki\/(.+?)" title="(.+?) – /
58
-
59
- class << self
60
-
61
- # Wikipedia の連続的な参照を抑制するための遅延時間/秒
62
- #
63
- # @return [Numeric]
64
- #
65
- attr_accessor :wikipedia_interval
66
-
67
- # When::Locale Module のグローバルな設定を行う
68
- #
69
- # @param [Hash] options 下記の通り
70
- # @option options [Hash] :alias Locale の読み替えパターンを Hash で指定する。
71
- # @option options [String] :namespaces 名前空間定義の省略時に名前空間生成に用いる書式
72
- # @option options [Hash] :unification 漢字の包摂パターンを Hash で指定する。
73
- # @option options [Numeric] :wikipedia_interval Wikipedia の連続的な参照を抑制するための遅延時間/秒
74
- #
75
- # @note
76
- # :alias の指定がない場合、aliases は DefaultAlias(モジュール定数)と解釈する。
77
- # :unification の指定がない場合、unifications は DefaultUnification(モジュール定数)と解釈する。
78
- #
79
- def _setup_(options={})
80
- @aliases = options[:alias] || DefaultAlias
81
- @namespaces = options[:namespaces] || DefaultNamespaces
82
- @unifications = options[:unification] || DefaultUnification
83
- @wikipedia_interval = options[:wikipedia_interval]
84
- end
85
-
86
- # 設定情報を取得する
87
- #
88
- # @return [Hash] 設定情報
89
- #
90
- def _setup_info
91
- {:alias => _alias,
92
- :namespaces => _namespaces,
93
- :unification => _unification,
94
- :wikipedia_interval => @wikipedia_interval}
95
- end
96
-
97
- # 特定 locale に対応した文字列の取得
98
- #
99
- # @param [String] source もとにする String または M17n
100
- #
101
- # @param[String] loc locale の指定 ( lang[-|_]country.encode )
102
- # [ lang - 言語 ]
103
- # [ country - 国(省略可) ]
104
- # [ encode - 文字コード(省略可) ]
105
- #
106
- # @return [String] loc に対応した文字列
107
- #
108
- # @note source が Hash や Array の場合、その構成要素を変換して返す
109
- # @note encode は通常大文字だが、大文字/小文字の変換は行わず指定されたまま使用している
110
- #
111
- def translate(source, loc='')
112
- return source unless loc
113
- case source
114
- when Hash
115
- result = {}
116
- source.each_pair do |key, value|
117
- result[translate(key, loc)] = translate(value, loc)
118
- end
119
- return result
120
- when Array
121
- return source.map {|value| translate(value, loc)}
122
- when Locale
123
- return source.translate(loc)
124
- when String
125
- return source.encode($1) if loc =~ /\.(.+)$/
126
- end
127
- source
128
- end
129
-
130
- # 包摂リストに登録されている文字を包摂する
131
- #
132
- # @param [When::Locale] source 文字を包摂しようとする国際化文字列
133
- # @param [String] source 文字を包摂しようとする文字列
134
- # @param [Regexp] source 文字を包摂しようとする正規表現
135
- # @param [Hash] pattern 包摂ルール
136
- #
137
- # @return [When::Locale] 文字を包摂した国際化文字列
138
- # @return [String] 文字を包摂した文字列
139
- # @return [Regexp] 文字を包摂した正規表現
140
- #
141
- def ideographic_unification(source, pattern=_unification)
142
- case source
143
- when When::Locale
144
- source.ideographic_unification(pattern)
145
- when Regexp
146
- Regexp.compile(ideographic_unification(source.source.encode('UTF-8'), pattern), source.options)
147
- when String
148
- source.gsub(/./) do |c|
149
- pattern[c] ? pattern[c] : c
150
- end
151
- else
152
- source
153
- end
154
- end
155
-
156
- # 文字列で表現された namespace 指定を Hash に変換する
157
- # @private
158
- def _namespace(source=nil)
159
- case source
160
- when Hash ; source
161
- when nil ; {}
162
- when String
163
- namespace = {}
164
- source = $1 if (source=~/\A\s*\[?(.+?)\]?\s*\z/m)
165
- source.split(/[\n\r,]+/).each do |v|
166
- v.strip!
167
- next if (v=~/^#/)
168
- pair = [''] + v.split(/\s*=\s*/, 2)
169
- namespace[pair[-2]] = pair[-1]
170
- end
171
- namespace
172
- when When::Parts::Resource::ContentLine
173
- source.object.names
174
- else ; raise TypeError, "Irregal Namespace Type: #{source.class}"
175
- end
176
- end
177
-
178
- # locale 指定を Array に変換する
179
- # @private
180
- def _locale(source=nil)
181
- # default の Locale
182
- return [[nil, '', nil]] unless source
183
-
184
- # source の配列化
185
- if source.kind_of?(String)
186
- source = $1 if (source=~/\A\s*\[?(.+?)\]?\s*\z/m)
187
- source = source.scan(/((?:[^\\\n\r,]|\\.)+)(?:[\n\r,]+(?!\z))?|[\n\r,]+/m).flatten.map {|token|
188
- (token||'').gsub(/\\./) {|escape| Escape[escape] || escape}
189
- }
190
- end
191
-
192
- # 各Localeの展開
193
- source.map {|v|
194
- if v.kind_of?(String)
195
- v = v.strip
196
- next if (v=~/^#/)
197
- (v =~ /^(\*)?(.*?)(?:\s*=\s*(.*))?$/) ? $~[1..3] : [[nil, '', nil]]
198
- else
199
- v
200
- end
201
- }.compact
202
- end
203
-
204
- # 文字列 [.., .., ..] を分割する
205
- # @private
206
- def _split(source)
207
- line = source.dup
208
- return [line] unless line =~ /,/
209
- list = []
210
- b = d = s = 0
211
- (source.length-1).downto(0) do |i|
212
- bs = 0
213
- (i-1).downto(0) do |k|
214
- break unless (line[k,1] == '\\')
215
- bs += 1
216
- end
217
- next if (bs[0] == 1)
218
- case line[i,1]
219
- when "'" ; s = 1-s if (d == 0)
220
- when '"' ; d = 1-d if (s == 0)
221
- when ']','}',')' ; b += 1 if (d+s == 0)
222
- when '[','{','(' ; b -= 1 if (d+s == 0 && b > 0)
223
- when ','
224
- if (b+d+s == 0)
225
- list.unshift(line[i+1..-1])
226
- line = i > 0 ? line[0..i-1] : ''
227
- end
228
- end
229
- end
230
- list.unshift(line)
231
- end
232
-
233
- # locale 指定を解析して Hash の値を取り出す
234
- # @private
235
- def _hash_value(hash, locale, defaults=['', 'en'])
236
- locale = locale.sub(/\..*/, '')
237
- return hash[locale] if hash[locale]
238
- return _hash_value(hash, _alias[locale], defaults) if _alias[locale]
239
- language = locale.sub(/-.*/, '')
240
- return hash[language] if hash[language]
241
- defaults.each do |default|
242
- return hash[default] if hash[default]
243
- end
244
- return nil
245
- end
246
-
247
- # 漢字の包摂パターン
248
- # @private
249
- def _unification
250
- @unifications ||= DefaultUnification
251
- end
252
-
253
- # @private
254
- def _get_locale(locale, access_key)
255
- return nil unless access_key
256
- access_key = access_key.split(/\//).map {|key| key =~ /^[0-9]+$/ ? key.to_i : key}
257
- locale = locale.sub(/\..*/, '')
258
- [locale, locale.sub(/-.*/, '')].each do |loc|
259
- symbol = ('Locale_' + loc.sub(/-/,'_')).to_sym
260
- return {loc=>access_key.inject(const_get(symbol)) {|hash, key| hash = hash[key]}} if const_defined?(symbol)
261
- end
262
- return nil
263
- end
264
-
265
- private
266
-
267
- # Locale の読み替えパターン
268
- def _alias
269
- @aliases ||= DefaultAlias
270
- end
271
-
272
- # 名前空間定義の省略時に名前空間生成に用いる書式
273
- def _namespaces
274
- @namespaces ||= DefaultNamespaces
275
- end
276
-
277
- # wikipedia オブジェクトの生成・参照
278
- def wikipedia_object(path, options={})
279
- query = options.delete(:query)
280
- interval = options.key?(:interval) ? options.delete(:interval) : @wikipedia_interval
281
- return nil unless Object.const_defined?(:JSON) && path =~ Ref
282
- _wikipedia_relation(_wikipedia_object(path, $~[1], $~[2], query, interval, options), path, query)
283
- end
284
-
285
- # wikipedia の読み込み
286
- def _wikipedia_object(path, locale, file, query, interval, options)
287
- # 採取済みデータ
288
- title = URI.decode(file.gsub('_', ' '))
289
- mode = "".respond_to?(:force_encoding) ? ':utf-8' : ''
290
- dir = When::Parts::Resource.root_dir + '/data/wikipedia/' + locale
291
- FileUtils.mkdir_p(dir) unless FileTest.exist?(dir)
292
-
293
- open("#{dir}/#{file}.json", 'r'+mode) do |source|
294
- json = JSON.parse(source.read)
295
- json.update(Hash[*query.split('&').map {|pair| pair.split('=')}.flatten]) if query
296
- json.key?('names') ?
297
- When::BasicTypes::M17n.new(json) :
298
- When::Coordinates::Spatial.new(json)
299
- end
300
-
301
- rescue => no_file_error
302
- # 新しいデータ
303
- case interval
304
- when 0
305
- raise no_file_error
306
- when Numeric
307
- if @wikipedia_last_access
308
- delay = (@wikipedia_last_access + interval.abs - Time.now.to_f).ceil
309
- sleep(delay) if delay > 0
310
- end
311
- end
312
- contents = nil
313
- begin
314
- OpenURI
315
- source = open(path, 'r'+mode)
316
- contents = source.read
317
- ensure
318
- @wikipedia_last_access = Time.now.to_f
319
- source.close if source
320
- end
321
-
322
- # wikipedia contents
323
- raise KeyError, 'Article not found: ' + title if contents =~ /<div class="noarticletext">/
324
-
325
- # word
326
- word = {
327
- :label => title,
328
- :names => {''=>title, locale=>title},
329
- :link => {''=>path, locale=>path }
330
- }
331
- contents.scan(Link) do |link|
332
- word[:names][$~[1]] = $~[4]
333
- word[:link ][$~[1]] = "http://#{$~[1]}.wikipedia.org/wiki/#{$~[3]}"
334
- end
335
- object = When::BasicTypes::M17n.new(word)
336
-
337
- # location
338
- if contents =~ /tools\.wmflabs\.org\/geohack\/geohack\.php\?.+?params=(.+?[NS])_(.+?[EW])/
339
- location = {
340
- :label => object
341
- }
342
- location[:lat], location[:long] = $~[1..2].map {|pos|
343
- pos.gsub(/_(\d)[._]/, '_0\1_').sub('.', '_').sub('_', '.').gsub('_', '')
344
- }
345
- object = When::Coordinates::Spatial.new(location)
346
- end
347
-
348
- # save data
349
- open("#{dir}/#{file}.json", 'w'+mode) do |source|
350
- source.write(JSON.dump(object.to_h({:method=>:to_h}).update(options)))
351
- end
352
- query ? _wikipedia_object(path, locale, file, query) : object
353
- end
354
-
355
- # wikipedia オブジェクトの関連付け
356
- def _wikipedia_relation(object, path, query)
357
- code_space = path.sub(/[^\/]+$/, '')
358
- if object.kind_of?(When::Coordinates::Spatial)
359
- object.label._pool['..'] = object
360
- object._pool[object.label.to_s] = object.label
361
- object.send(:child=, [object.label])
362
- object.label.send(:code_space=, code_space)
363
- else
364
- object.send(:code_space=, code_space)
365
- end
366
- object._pool['..'] = path
367
- object._pool['..'] += '?' + query if query
368
- object
369
- end
370
- end
371
-
372
- # ローケール指定時の文字列
373
- #
374
- # @return [Hash]
375
- attr_reader :names
376
-
377
- # 有効なローケール指定
378
- #
379
- # @return [Array<String>]
380
- attr_reader :keys
381
-
382
- # 有効な文字列 - additional attribute
383
- #
384
- # @return [Array<String>]
385
- attr_reader :values
386
-
387
- # 文字列の説明 - additional attribute
388
- #
389
- # @return [Hash] { anyURI }
390
- attr_reader :link
391
-
392
- # Rails 用 I18n 定義へのアクセス・キー
393
- #
394
- # @return [String]
395
- attr_reader :access_key
396
- protected :access_key
397
-
398
- # 特定 locale に対応した文字列の取得
399
- #
400
- # @param [String] loc locale の指定 ( lang[-|_]country.encode )
401
- # [ lang - 言語 ]
402
- # [ country - 国(省略可) ]
403
- # [ encode - 文字コード(省略可) ]
404
- #
405
- # @return [String] loc に対応した文字列
406
- #
407
- def translate(loc='')
408
- return to_s unless loc
409
- loc = loc.sub('_', '-')
410
- lang, code = loc.split(/\./)
411
- result = _label_value(loc)
412
- return result if !code || @names.member?(loc)
413
- return result.encode(code)
414
- end
415
- alias :/ :translate
416
-
417
- # 特定 locale に対応した reference URI の取得
418
- #
419
- # @param [String] loc locale の指定
420
- #
421
- # @return [String] loc に対応した reference URI
422
- #
423
- def reference(loc='')
424
- loc ||= ''
425
- return Locale._hash_value(@link, loc.sub('_', '-'))
426
- end
427
-
428
- # 部分文字列
429
- #
430
- # @param [Range] range String#[] と同様の指定方法で範囲を指定する
431
- #
432
- # @return [When::Locale] 指定範囲に対応した部分文字列
433
- #
434
- def [](range)
435
- dup._copy({
436
- :label => to_s[range],
437
- :names => @names.keys.inject({}) {|l,k|
438
- l[k] = @names[k][range]
439
- l
440
- }
441
- })
442
- end
443
-
444
- # 文字列の一致
445
- #
446
- # @param [String, Regexp] regexp マッチする正規表現
447
- #
448
- # @return [Integer] マッチした位置のindex(いずれかの locale でマッチが成功した場合)
449
- # @return [nil] すべての locale でマッチに失敗した場合
450
- #
451
- def =~(regexp)
452
- @keys.each do |key|
453
- index = (@names[key] =~ regexp)
454
- return index if index
455
- end
456
- return nil
457
- end
458
-
459
- # 部分文字列の位置
460
- #
461
- # @param [String] other 部分文字列
462
- #
463
- # @return [Integer] 部分文字列の先頭のindex(いずれかの locale で部分文字列を含んだ場合)
464
- # @return [nil] すべての locale で部分文字列を含まない場合
465
- #
466
- def index(other)
467
- @keys.each do |key|
468
- index = @names[key].index(Locale.translate(other, key))
469
- return index if index
470
- end
471
- return nil
472
- end
473
-
474
- # 文字列の連結
475
- #
476
- # @param [String, When::Toos::Locale] other 連結する文字列
477
- #
478
- # @return [When::Toos::Locale] 連結された文字列
479
- #
480
- def +(other)
481
- names = {}
482
- case other
483
- when Locale
484
- (@names.keys + other.names.keys).uniq.each do |key|
485
- names[key] = _label_value(key) + other._label_value(key)
486
- end
487
- links = other.link
488
- else
489
- @names.keys.each do |key|
490
- names[key] = _label_value(key) + other.to_s
491
- end
492
- links = {}
493
- end
494
- return dup._copy({:names=>names, :link=>links.merge(link), :label=>to_s + other.to_s})
495
- end
496
-
497
- # 書式指定による文字列化
498
- #
499
- # @param [Array<Object>] other 文字列化する Object の Array
500
- # @param [Array<String>] locale 文字列化を行う locale の指定(デフォルト : すべて)
501
- #
502
- # @return [When::Toos::Locale] 文字列化された Object
503
- #
504
- def _printf(other, locale=nil)
505
- # 処理する配列
506
- terms = other.kind_of?(Array) ? [self] + other : [self, other]
507
-
508
- # locale key の配列
509
- if locale == []
510
- keys = []
511
- else
512
- keys = terms.inject([]) {|k,t|
513
- k += t.keys if t.kind_of?(Locale)
514
- k
515
- }.uniq
516
- if locale
517
- locale = [locale] unless locale.kind_of?(Array)
518
- keys = locale | (locale & keys)
519
- end
520
- end
521
- keys << nil if keys.include?('')
522
-
523
- # names ハッシュ
524
- names = keys.inject({}) {|l,k|
525
- l[k] = When::Coordinates::Pair._format(
526
- (block_given? ? yield(k, *terms) : terms).map {|t|
527
- t.kind_of?(Locale) ? t.translate(k) : t
528
- }
529
- )
530
- l
531
- }
532
-
533
- # link ハッシュ
534
- links = terms.reverse.inject({}) {|h,t|
535
- h.update(t.link) if t.kind_of?(Locale)
536
- h
537
- }
538
-
539
- # 生成
540
- dup._copy({
541
- :label => keys.include?('') ? names.delete(nil) : (names[''] = names[keys[0]]),
542
- :names => names,
543
- :link => links
544
- })
545
- end
546
- alias :% :_printf
547
-
548
- # ローケールの更新
549
- #
550
- # @param [Hash] options 下記の通り
551
- # @option options [String] カントリーコード 表現文字列
552
- # @option options [Hash] :link { カントリーコード => 参照URL文字列 }
553
- # @option options [String] :code_space 規格や辞書を特定するコードスペースのURL文字列
554
- # @option options [String] :label 代表文字列
555
- # @note Hashキーはすべて Optional で、存在するもののみ更新します
556
- #
557
- # @return [self] 更新された Object
558
- #
559
- def update(options={})
560
- options = options.dup
561
- @link.update(options.delete(:link)) if (options.key?(:link))
562
- @code_space = options.delete(:code_space) if (options.key?(:code_space))
563
- self[0..-1] = options.delete(:label) if (options.key?(:label))
564
- unless (options.empty?)
565
- @names.update(options)
566
- @keys = @names.keys.sort
567
- @values = @names.values.sort.reverse
568
- end
569
- return self
570
- end
571
-
572
- # 包摂リストに登録されている文字を包摂する(自己破壊)
573
- #
574
- # @param [Hash] pattern 包摂ルール
575
- #
576
- # @return [When::Locale] self
577
- # @private
578
- def ideographic_unification!(pattern=_unification)
579
- names = {}
580
- @names.each_pair do |key, value|
581
- names[key] = Locale.ideographic_unification(value, pattern)
582
- end
583
- @names = names
584
- @values = @names.values.sort.reverse
585
- self[0..-1] = Locale.ideographic_unification(self.to_s[0..-1], pattern)
586
- return self
587
- end
588
- protected :ideographic_unification!
589
-
590
- # 包摂リストに登録されている文字を包摂する(自己保存)
591
- #
592
- # @param [Hash] pattern 包摂ルール
593
- #
594
- # @return [When::Locale] 包摂結果
595
- #
596
- def ideographic_unification(pattern=_unification)
597
- dup.ideographic_unification!(pattern)
598
- end
599
-
600
- # 閏の表記を扱うための書式付整形
601
- # @private
602
- def prefix(other, locale=nil)
603
- return self.dup unless other
604
- other = m17n(other) unless other.kind_of?(Locale)
605
- other._printf(self, locale) do |k, *t|
606
- t[0] = t[0].translate(k)
607
- t[0] += "%s" unless t[0] =~ /%[-+]?[.\d]*s/
608
- t
609
- end
610
- end
611
-
612
- protected
613
-
614
- # @private
615
- def _copy(options={})
616
- if options.key?('label') # for JSON
617
- opt = {}
618
- options.each_pair do |key, value|
619
- opt[key.to_sym] = value
620
- end
621
- else
622
- opt = options
623
- end
624
-
625
- self[0..-1] = opt[:label] if opt[:label]
626
- if opt[:names]
627
- @names = opt[:names]
628
- @keys = @names.keys.sort
629
- @values = @names.values.compact.sort.reverse
630
- end
631
- @label = opt[:label] if opt[:label]
632
- @link = opt[:link] if opt[:link]
633
- @access_key = opt[:access_key] if opt[:access_key]
634
- @code_space = opt[:code_space] if opt[:code_space]
635
- return self
636
- end
637
-
638
- # @private
639
- def _copy_all(other)
640
- _copy({:label => other.to_s,
641
- :names => other.names,
642
- :link => other.link,
643
- :access_key => other.access_key,
644
- :code_space => other.code_space
645
- })
646
- end
647
-
648
- # locale 指定を解析して @names の値を取り出す
649
- # @private
650
- def _label_value(locale)
651
- label = Locale._hash_value(@names, locale, [])
652
- return label if label
653
- foreign = Locale._get_locale(locale, @access_key)
654
- return @names[''] unless foreign
655
- english = @names['en'] || @names['']
656
- addition = english.dup.sub!(/^#{Locale._get_locale('en', @access_key)['en']}/, '')
657
- foreign[locale] += addition if addition
658
- update(foreign)
659
- return Locale._hash_value(@names, locale)
660
- end
661
-
662
- private
663
-
664
- def _names(names, namespace, default_locale)
665
-
666
- # names, link の組み立て
667
- @names = {}
668
- @link = {}
669
-
670
- if names.kind_of?(String)
671
- unless (names=~/\A\s*\[(.+?)\]\s*\z/m)
672
- names = names.strip
673
- @names[''] = names
674
- @keys = ['']
675
- @values = [names]
676
- return names
677
- end
678
- names = $1.split(/[\n\r,]+/)
679
- end
680
-
681
- mark = []
682
- asterisk = []
683
- default_locale = default_locale.dup
684
- names.each do |v|
685
- v.strip!
686
- case v
687
- when '', /^#/ ;
688
- when /^\/(.+)/; @access_key = $1
689
- when /^(\*)?(?:([^=%]*?)\s*:)?\s*(.+?)\s*(=\s*([^=]+?(\?.+)?)?)?$/
690
- asterisk[0], locale, name, assignment, ref = $~[1..5]
691
- asterisk[1], locale, default_ref = default_locale.shift unless locale
692
- locale ||= ''
693
- ref ||= default_ref unless (assignment)
694
- ref ||= ''
695
- mark[0] = locale if asterisk[0]
696
- mark[1] = locale if asterisk[1]
697
- mark[2] = locale unless mark[2]
698
- name = _replacement($1, locale, ($3 || @names['en'] || @names[''])) if name =~ /^_([A-Z_]+)_(\((.+)\))?$/
699
- @names[locale] = name
700
- if ref =~ /^(.+):/
701
- prefix = namespace[$1] || Locale.send(:_namespaces)[$1]
702
- ref.sub!(/^.+:/, prefix) if prefix
703
- end
704
- ref += '%%<' + name + '>' if ref =~ /[\/#:]$/
705
- @link[locale] = _encode(ref) unless ref == ''
706
- else ; raise ArgumentError, "Irregal locale format: " + v
707
- end
708
- end
709
- if Locale.wikipedia_interval && Locale.wikipedia_interval <= 0
710
- ['en', ''].each do |lc|
711
- if Locale::Ref =~ @link[lc] && $~[1] == 'en'
712
- object = Locale.send(:wikipedia_object, @link[lc])
713
- if object
714
- @names = object.names.merge(@names)
715
- @link = object.link.merge(@link)
716
- end
717
- break
718
- end
719
- end
720
- end
721
-
722
- # keys, values の準備
723
- @keys = @names.keys.sort
724
- @values = @names.values.sort.reverse
725
-
726
- # 代表名
727
- @names[mark[0] || mark[1] || mark[2]]
728
- end
729
-
730
- #
731
- # 英語表記を現地表記に置き換える
732
- #
733
- def _replacement(table, locale, name)
734
- Locale.const_get(table.split('_')[-1])[locale] ?
735
- Locale.send(table.downcase, name, locale) :
736
- name
737
- end
738
-
739
- # encode URI from patterns %%(...) or %.(...)
740
- def _encode(source)
741
- source.gsub(/%.<.+?>/) do |match|
742
- URI.encode(match[3..-2]).gsub('%', match[1..1])
743
- end
744
- end
745
- end
746
- end
1
+ # -*- coding: utf-8 -*-
2
+ =begin
3
+ Copyright (C) 2011-2014 Takashi SUGA
4
+
5
+ You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
+ =end
7
+
8
+ require 'when_exe/locales/encoding_conversion'
9
+
10
+ module When
11
+
12
+ #
13
+ # Multilingualization(M17n) 対応モジュール
14
+ #
15
+ # When::BasicTypes::M17n の実装のうち When::BasicTypes 内部で
16
+ # 定義すべきでない部分を切り出してモジュールとしている
17
+ #
18
+ module Locale
19
+
20
+ # Locale 読み替えの初期設定
21
+ DefaultAlias = {'alias'=>'ja', '日本語'=>'ja', '英語'=>'en'}
22
+
23
+ # 省略時 Namespace
24
+ DefaultNamespaces = Hash.new {|hash, key|
25
+ hash[key] = "http://#{key}.wikipedia.org/wiki/"
26
+ }.update({
27
+ 'mailto' => false,
28
+ 'https' => false,
29
+ 'http' => false,
30
+ 'ftp' => false
31
+ })
32
+
33
+ # 漢字の包摂
34
+ DefaultUnification = {
35
+ '煕'=>'熙', '廣'=>'広', '寶'=>'宝', '國'=>'国',
36
+ '應'=>'応', '觀'=>'観', '龜'=>'亀', '齊'=>'斉',
37
+ '靈'=>'霊', '攝'=>'摂', '壽'=>'寿', '萬'=>'万',
38
+ '廢'=>'廃', '顯'=>'顕', '會'=>'会', '聰'=>'聡',
39
+ '總'=>'総', '證'=>'証', '禮'=>'礼', '竜'=>'龍'
40
+ }
41
+
42
+ # Escape
43
+ # @private
44
+ Escape = {
45
+ "\\\\" => "\\",
46
+ "\\n" => "\n",
47
+ "\\r" => "\r",
48
+ "\\," => ","
49
+ }
50
+
51
+ # Wikipedia の URL の正規表現
52
+ # @private
53
+ Ref = /\Ahttp:\/\/(.+?)\.wikipedia\.org\/wiki\/([^#]+?)\z/
54
+
55
+ # Wikipedia の多言語リンクの正規表現
56
+ # @private
57
+ Link = /<li class="interlanguage-link interwiki-(.+?)"><a href="\/\/(.+?)\.wikipedia\.org\/wiki\/(.+?)" title="(.+?) – /
58
+
59
+ class << self
60
+
61
+ # Wikipedia の連続的な参照を抑制するための遅延時間/秒
62
+ #
63
+ # @return [Numeric]
64
+ #
65
+ attr_accessor :wikipedia_interval
66
+
67
+ # When::Locale Module のグローバルな設定を行う
68
+ #
69
+ # @param [Hash] options 下記の通り
70
+ # @option options [Hash] :alias Locale の読み替えパターンを Hash で指定する。
71
+ # @option options [String] :namespace_foramt 名前空間定義の省略時に名前空間生成に用いる書式
72
+ # @option options [Hash] :unification 漢字の包摂パターンを Hash で指定する。
73
+ # @option options [Numeric] :wikipedia_interval Wikipedia の連続的な参照を抑制するための遅延時間/秒
74
+ #
75
+ # @note
76
+ # :alias の指定がない場合、aliases は DefaultAlias(モジュール定数)と解釈する。
77
+ # :unification の指定がない場合、unifications は DefaultUnification(モジュール定数)と解釈する。
78
+ #
79
+ def _setup_(options={})
80
+ @aliases = options[:alias] || DefaultAlias
81
+ @namespaces = options[:namespace_foramt] || DefaultNamespaces
82
+ @unifications = options[:unification] || DefaultUnification
83
+ @wikipedia_interval = options[:wikipedia_interval]
84
+ end
85
+
86
+ # 設定情報を取得する
87
+ #
88
+ # @return [Hash] 設定情報
89
+ #
90
+ def _setup_info
91
+ {:alias => _alias,
92
+ :namespace_foramt => _namespaces,
93
+ :unification => _unification,
94
+ :wikipedia_interval => @wikipedia_interval}
95
+ end
96
+
97
+ # 特定 locale に対応した文字列の取得
98
+ #
99
+ # @param [String] source もとにする String または M17n
100
+ #
101
+ # @param[String] loc locale の指定 ( lang[-|_]country.encode )
102
+ # [ lang - 言語 ]
103
+ # [ country - 国(省略可) ]
104
+ # [ encode - 文字コード(省略可) ]
105
+ #
106
+ # @return [String] loc に対応した文字列
107
+ #
108
+ # @note source が Hash や Array の場合、その構成要素を変換して返す
109
+ # @note encode は通常大文字だが、大文字/小文字の変換は行わず指定されたまま使用している
110
+ #
111
+ def translate(source, loc='')
112
+ return source unless loc
113
+ case source
114
+ when Hash
115
+ result = {}
116
+ source.each_pair do |key, value|
117
+ result[translate(key, loc)] = translate(value, loc)
118
+ end
119
+ return result
120
+ when Array
121
+ return source.map {|value| translate(value, loc)}
122
+ when Locale
123
+ return source.translate(loc)
124
+ when String
125
+ return source.encode($1) if loc =~ /\.(.+)\z/
126
+ end
127
+ source
128
+ end
129
+
130
+ # 包摂リストに登録されている文字を包摂する
131
+ #
132
+ # @param [When::Locale] source 文字を包摂しようとする国際化文字列
133
+ # @param [String] source 文字を包摂しようとする文字列
134
+ # @param [Regexp] source 文字を包摂しようとする正規表現
135
+ # @param [Hash] pattern 包摂ルール
136
+ #
137
+ # @return [When::Locale] 文字を包摂した国際化文字列
138
+ # @return [String] 文字を包摂した文字列
139
+ # @return [Regexp] 文字を包摂した正規表現
140
+ #
141
+ def ideographic_unification(source, pattern=_unification)
142
+ case source
143
+ when When::Locale
144
+ source.ideographic_unification(pattern)
145
+ when Regexp
146
+ Regexp.compile(ideographic_unification(source.source.encode('UTF-8'), pattern), source.options)
147
+ when String
148
+ source.gsub(/./) do |c|
149
+ pattern[c] ? pattern[c] : c
150
+ end
151
+ else
152
+ source
153
+ end
154
+ end
155
+
156
+ # 文字列で表現された namespace 指定を Hash に変換する
157
+ # @private
158
+ def _namespace(source=nil)
159
+ case source
160
+ when Hash ; source
161
+ when nil ; {}
162
+ when String
163
+ namespace = {}
164
+ source = $1 if (source=~/\A\s*\[?(.+?)\]?\s*\z/m)
165
+ source.split(/[\n\r,]+/).each do |v|
166
+ v.strip!
167
+ next if (v=~/\A#/)
168
+ pair = [''] + v.split(/\s*=\s*/, 2)
169
+ namespace[pair[-2]] = pair[-1]
170
+ end
171
+ namespace
172
+ when When::Parts::Resource::ContentLine
173
+ source.object.names
174
+ else ; raise TypeError, "Irregal Namespace Type: #{source.class}"
175
+ end
176
+ end
177
+
178
+ # locale 指定を Array に変換する
179
+ # @private
180
+ def _locale(source=nil)
181
+ # default の Locale
182
+ return [[nil, '', nil]] unless source
183
+
184
+ # source の配列化
185
+ if source.kind_of?(String)
186
+ source = $1 if (source=~/\A\s*\[?(.+?)\]?\s*\z/m)
187
+ source = source.scan(/((?:[^\\\n\r,]|\\.)+)(?:[\n\r,]+(?!\z))?|[\n\r,]+/m).flatten.map {|token|
188
+ (token||'').gsub(/\\./) {|escape| Escape[escape] || escape}
189
+ }
190
+ end
191
+
192
+ # 各Localeの展開
193
+ source.map {|v|
194
+ if v.kind_of?(String)
195
+ v = v.strip
196
+ next if (v=~/\A#/)
197
+ (v =~ /\A(\*)?(.*?)(?:\s*=\s*(.*))?\z/) ? $~[1..3] : [[nil, '', nil]]
198
+ else
199
+ v
200
+ end
201
+ }.compact
202
+ end
203
+
204
+ # 文字列 [.., .., ..] を分割する
205
+ # @private
206
+ def _split(source)
207
+ line = source.dup
208
+ return [line] unless line =~ /,/
209
+ list = []
210
+ b = d = s = 0
211
+ (source.length-1).downto(0) do |i|
212
+ bs = 0
213
+ (i-1).downto(0) do |k|
214
+ break unless (line[k,1] == '\\')
215
+ bs += 1
216
+ end
217
+ next if (bs[0] == 1)
218
+ case line[i,1]
219
+ when "'" ; s = 1-s if (d == 0)
220
+ when '"' ; d = 1-d if (s == 0)
221
+ when ']','}',')' ; b += 1 if (d+s == 0)
222
+ when '[','{','(' ; b -= 1 if (d+s == 0 && b > 0)
223
+ when ','
224
+ if (b+d+s == 0)
225
+ list.unshift(line[i+1..-1])
226
+ line = i > 0 ? line[0..i-1] : ''
227
+ end
228
+ end
229
+ end
230
+ list.unshift(line)
231
+ end
232
+
233
+ # locale 指定を解析して Hash の値を取り出す
234
+ # @private
235
+ def _hash_value(hash, locale, defaults=['', 'en'])
236
+ locale = locale.sub(/\..*/, '')
237
+ return hash[locale] if hash[locale]
238
+ return _hash_value(hash, _alias[locale], defaults) if _alias[locale]
239
+ language = locale.sub(/-.*/, '')
240
+ return hash[language] if hash[language]
241
+ defaults.each do |default|
242
+ return hash[default] if hash[default]
243
+ end
244
+ return nil
245
+ end
246
+
247
+ # 漢字の包摂パターン
248
+ # @private
249
+ def _unification
250
+ @unifications ||= DefaultUnification
251
+ end
252
+
253
+ # @private
254
+ def _get_locale(locale, access_key)
255
+ return nil unless access_key
256
+ access_key = access_key.split(/\//).map {|key| key =~ /\A[0-9]+\z/ ? key.to_i : key}
257
+ locale = locale.sub(/\..*/, '')
258
+ [locale, locale.sub(/-.*/, '')].each do |loc|
259
+ symbol = ('Locale_' + loc.sub(/-/,'_')).to_sym
260
+ return {locale=>access_key.inject(const_get(symbol)) {|hash, key| hash = hash[key]}} if const_defined?(symbol)
261
+ end
262
+ return nil
263
+ end
264
+
265
+ private
266
+
267
+ # Locale の読み替えパターン
268
+ def _alias
269
+ @aliases ||= DefaultAlias
270
+ end
271
+
272
+ # 名前空間定義の省略時に名前空間生成に用いる書式
273
+ def _namespaces
274
+ @namespaces ||= DefaultNamespaces
275
+ end
276
+
277
+ # wikipedia オブジェクトの生成・参照
278
+ def wikipedia_object(path, options={})
279
+ query = options.delete(:query)
280
+ interval = options.key?(:interval) ? options.delete(:interval) : @wikipedia_interval
281
+ return nil unless Object.const_defined?(:JSON) && path =~ Ref
282
+ _wikipedia_relation(_wikipedia_object(path, $1, $2, query, interval, options), path, query)
283
+ end
284
+
285
+ # wikipedia の読み込み
286
+ def _wikipedia_object(path, locale, file, query, interval, options)
287
+ # 採取済みデータ
288
+ title = URI.decode(file.gsub('_', ' '))
289
+ mode = "".respond_to?(:force_encoding) ? ':utf-8' : ''
290
+ dir = When::Parts::Resource.root_dir + '/data/wikipedia/' + locale
291
+ FileUtils.mkdir_p(dir) unless FileTest.exist?(dir)
292
+
293
+ open("#{dir}/#{file}.json", 'r'+mode) do |source|
294
+ json = JSON.parse(source.read)
295
+ json.update(Hash[*query.split('&').map {|pair| pair.split('=')}.flatten]) if query
296
+ json.key?('names') ?
297
+ When::BasicTypes::M17n.new(json) :
298
+ When::Coordinates::Spatial.new(json)
299
+ end
300
+
301
+ rescue => no_file_error
302
+ # 新しいデータ
303
+ case interval
304
+ when 0
305
+ raise no_file_error
306
+ when Numeric
307
+ if @wikipedia_last_access
308
+ delay = (@wikipedia_last_access + interval.abs - Time.now.to_f).ceil
309
+ sleep(delay) if delay > 0
310
+ end
311
+ end
312
+ contents = nil
313
+ begin
314
+ OpenURI
315
+ source = open(path, 'r'+mode)
316
+ contents = source.read
317
+ ensure
318
+ @wikipedia_last_access = Time.now.to_f
319
+ source.close if source
320
+ end
321
+
322
+ # wikipedia contents
323
+ raise KeyError, 'Article not found: ' + title if contents =~ /<div class="noarticletext">/
324
+
325
+ # word
326
+ word = {
327
+ :label => title,
328
+ :names => {''=>title, locale=>title},
329
+ :link => {''=>path, locale=>path }
330
+ }
331
+ contents.scan(Link) do |link|
332
+ word[:names][$1] = $4
333
+ word[:link ][$1] = "http://#{$1}.wikipedia.org/wiki/#{$3}"
334
+ end
335
+ object = When::BasicTypes::M17n.new(word)
336
+
337
+ # location
338
+ if contents =~ /tools\.wmflabs\.org\/geohack\/geohack\.php\?.+?params=(.+?[NS])_(.+?[EW])/
339
+ location = {
340
+ :label => object
341
+ }
342
+ location[:lat], location[:long] = $~[1..2].map {|pos|
343
+ pos.gsub(/_(\d)[._]/, '_0\1_').sub('.', '_').sub('_', '.').gsub('_', '')
344
+ }
345
+ object = When::Coordinates::Spatial.new(location)
346
+ end
347
+
348
+ # save data
349
+ open("#{dir}/#{file}.json", 'w'+mode) do |source|
350
+ source.write(JSON.dump(object.to_h({:method=>:to_h}).update(options)))
351
+ end
352
+ query ? _wikipedia_object(path, locale, file, query) : object
353
+ end
354
+
355
+ # wikipedia オブジェクトの関連付け
356
+ def _wikipedia_relation(object, path, query)
357
+ code_space = path.sub(/[^\/]+\z/, '')
358
+ if object.kind_of?(When::Coordinates::Spatial)
359
+ object.label._pool['..'] = object
360
+ object._pool[object.label.to_s] = object.label
361
+ object.send(:child=, [object.label])
362
+ object.label.send(:code_space=, code_space)
363
+ else
364
+ object.send(:code_space=, code_space)
365
+ end
366
+ object._pool['..'] = path
367
+ object._pool['..'] += '?' + query if query
368
+ object
369
+ end
370
+ end
371
+
372
+ # ローケール指定時の文字列
373
+ #
374
+ # @return [Hash]
375
+ attr_reader :names
376
+
377
+ # 有効なローケール指定
378
+ #
379
+ # @return [Array<String>]
380
+ attr_reader :keys
381
+
382
+ # 有効な文字列 - additional attribute
383
+ #
384
+ # @return [Array<String>]
385
+ attr_reader :values
386
+
387
+ # 文字列の説明 - additional attribute
388
+ #
389
+ # @return [Hash] { anyURI }
390
+ attr_reader :link
391
+
392
+ # Rails 用 I18n 定義へのアクセス・キー
393
+ #
394
+ # @return [String]
395
+ attr_reader :access_key
396
+ protected :access_key
397
+
398
+ # 特定 locale に対応した文字列の取得
399
+ #
400
+ # @param [String] loc locale の指定 ( lang[-|_]country.encode )
401
+ # [ lang - 言語 ]
402
+ # [ country - 国(省略可) ]
403
+ # [ encode - 文字コード(省略可) ]
404
+ #
405
+ # @return [String] loc に対応した文字列
406
+ #
407
+ def translate(loc='')
408
+ return to_s unless loc
409
+ loc = loc.sub('_', '-')
410
+ lang, code = loc.split(/\./)
411
+ result = _label_value(loc)
412
+ return result if !code || @names.member?(loc)
413
+ return result.encode(code)
414
+ end
415
+ alias :/ :translate
416
+
417
+ # 特定 locale に対応した reference URI の取得
418
+ #
419
+ # @param [String] loc locale の指定
420
+ #
421
+ # @return [String] loc に対応した reference URI
422
+ #
423
+ def reference(loc='')
424
+ loc ||= ''
425
+ return Locale._hash_value(@link, loc.sub('_', '-'))
426
+ end
427
+
428
+ # 部分文字列
429
+ #
430
+ # @param [Range] range String#[] と同様の指定方法で範囲を指定する
431
+ #
432
+ # @return [When::Locale] 指定範囲に対応した部分文字列
433
+ #
434
+ def [](range)
435
+ dup._copy({
436
+ :label => to_s[range],
437
+ :names => @names.keys.inject({}) {|l,k|
438
+ l[k] = @names[k][range]
439
+ l
440
+ }
441
+ })
442
+ end
443
+
444
+ # 文字列の一致
445
+ #
446
+ # @param [String, Regexp] regexp マッチする正規表現
447
+ #
448
+ # @return [Integer] マッチした位置のindex(いずれかの locale でマッチが成功した場合)
449
+ # @return [nil] すべての locale でマッチに失敗した場合
450
+ #
451
+ def =~(regexp)
452
+ @keys.each do |key|
453
+ index = (@names[key] =~ regexp)
454
+ return index if index
455
+ end
456
+ return nil
457
+ end
458
+
459
+ # 部分文字列の位置
460
+ #
461
+ # @param [String] other 部分文字列
462
+ #
463
+ # @return [Integer] 部分文字列の先頭のindex(いずれかの locale で部分文字列を含んだ場合)
464
+ # @return [nil] すべての locale で部分文字列を含まない場合
465
+ #
466
+ def index(other)
467
+ @keys.each do |key|
468
+ index = @names[key].index(Locale.translate(other, key))
469
+ return index if index
470
+ end
471
+ return nil
472
+ end
473
+
474
+ # 文字列の連結
475
+ #
476
+ # @param [String, When::Toos::Locale] other 連結する文字列
477
+ #
478
+ # @return [When::Toos::Locale] 連結された文字列
479
+ #
480
+ def +(other)
481
+ names = {}
482
+ case other
483
+ when Locale
484
+ (@names.keys + other.names.keys).uniq.each do |key|
485
+ names[key] = _label_value(key) + other._label_value(key)
486
+ end
487
+ links = other.link
488
+ else
489
+ @names.keys.each do |key|
490
+ names[key] = _label_value(key) + other.to_s
491
+ end
492
+ links = {}
493
+ end
494
+ return dup._copy({:names=>names, :link=>links.merge(link), :label=>to_s + other.to_s})
495
+ end
496
+
497
+ # 書式指定による文字列化
498
+ #
499
+ # @param [Array<Object>] other 文字列化する Object の Array
500
+ # @param [Array<String>] locale 文字列化を行う locale の指定(デフォルト : すべて)
501
+ #
502
+ # @return [When::Toos::Locale] 文字列化された Object
503
+ #
504
+ def _printf(other, locale=nil)
505
+ # 処理する配列
506
+ terms = other.kind_of?(Array) ? [self] + other : [self, other]
507
+
508
+ # locale key の配列
509
+ if locale == []
510
+ keys = []
511
+ else
512
+ keys = terms.inject([]) {|k,t|
513
+ k += t.keys if t.kind_of?(Locale)
514
+ k
515
+ }.uniq
516
+ if locale
517
+ locale = [locale] unless locale.kind_of?(Array)
518
+ keys = locale | (locale & keys)
519
+ end
520
+ end
521
+ keys << nil if keys.include?('')
522
+
523
+ # names ハッシュ
524
+ names = keys.inject({}) {|l,k|
525
+ l[k] = When::Coordinates::Pair._format(
526
+ (block_given? ? yield(k, *terms) : terms).map {|t|
527
+ t.kind_of?(Locale) ? t.translate(k) : t
528
+ }
529
+ )
530
+ l
531
+ }
532
+
533
+ # link ハッシュ
534
+ links = terms.reverse.inject({}) {|h,t|
535
+ h.update(t.link) if t.kind_of?(Locale)
536
+ h
537
+ }
538
+
539
+ # 生成
540
+ dup._copy({
541
+ :label => keys.include?('') ? names.delete(nil) : (names[''] = names[keys[0]]),
542
+ :names => names,
543
+ :link => links
544
+ })
545
+ end
546
+ alias :% :_printf
547
+
548
+ # ローケールの更新
549
+ #
550
+ # @param [Hash] options 下記の通り
551
+ # @option options [String] カントリーコード 表現文字列
552
+ # @option options [Hash] :link { カントリーコード => 参照URL文字列 }
553
+ # @option options [String] :code_space 規格や辞書を特定するコードスペースのURL文字列
554
+ # @option options [String] :label 代表文字列
555
+ # @note Hashキーはすべて Optional で、存在するもののみ更新します
556
+ #
557
+ # @return [self] 更新された Object
558
+ #
559
+ def update(options={})
560
+ options = options.dup
561
+ @link.update(options.delete(:link)) if (options.key?(:link))
562
+ @code_space = options.delete(:code_space) if (options.key?(:code_space))
563
+ self[0..-1] = options.delete(:label) if (options.key?(:label))
564
+ unless (options.empty?)
565
+ @names.update(options)
566
+ @keys = @names.keys.sort
567
+ @values = @names.values.sort.reverse
568
+ end
569
+ return self
570
+ end
571
+
572
+ # 包摂リストに登録されている文字を包摂する(自己破壊)
573
+ #
574
+ # @param [Hash] pattern 包摂ルール
575
+ #
576
+ # @return [When::Locale] self
577
+ # @private
578
+ def ideographic_unification!(pattern=_unification)
579
+ names = {}
580
+ @names.each_pair do |key, value|
581
+ names[key] = Locale.ideographic_unification(value, pattern)
582
+ end
583
+ @names = names
584
+ @values = @names.values.sort.reverse
585
+ self[0..-1] = Locale.ideographic_unification(self.to_s[0..-1], pattern)
586
+ return self
587
+ end
588
+ protected :ideographic_unification!
589
+
590
+ # 包摂リストに登録されている文字を包摂する(自己保存)
591
+ #
592
+ # @param [Hash] pattern 包摂ルール
593
+ #
594
+ # @return [When::Locale] 包摂結果
595
+ #
596
+ def ideographic_unification(pattern=_unification)
597
+ dup.ideographic_unification!(pattern)
598
+ end
599
+
600
+ # 閏の表記を扱うための書式付整形
601
+ # @private
602
+ def prefix(other, locale=nil)
603
+ return self.dup unless other
604
+ other = m17n(other) unless other.kind_of?(Locale)
605
+ other._printf(self, locale) do |k, *t|
606
+ t[0] = t[0].translate(k)
607
+ t[0] += "%s" unless t[0] =~ /%[-+]?[.\d]*s/
608
+ t
609
+ end
610
+ end
611
+
612
+ protected
613
+
614
+ # @private
615
+ def _copy(options={})
616
+ if options.key?('label') # for JSON
617
+ opt = {}
618
+ options.each_pair do |key, value|
619
+ opt[key.to_sym] = value
620
+ end
621
+ else
622
+ opt = options
623
+ end
624
+
625
+ self[0..-1] = opt[:label] if opt[:label]
626
+ if opt[:names]
627
+ @names = opt[:names]
628
+ @keys = @names.keys.sort
629
+ @values = @names.values.compact.sort.reverse
630
+ end
631
+ @label = opt[:label] if opt[:label]
632
+ @link = opt[:link] if opt[:link]
633
+ @access_key = opt[:access_key] if opt[:access_key]
634
+ @code_space = opt[:code_space] if opt[:code_space]
635
+ return self
636
+ end
637
+
638
+ # @private
639
+ def _copy_all(other)
640
+ _copy({:label => other.to_s,
641
+ :names => other.names,
642
+ :link => other.link,
643
+ :access_key => other.access_key,
644
+ :code_space => other.code_space
645
+ })
646
+ end
647
+
648
+ # locale 指定を解析して @names の値を取り出す
649
+ # @private
650
+ def _label_value(locale)
651
+ label = Locale._hash_value(@names, locale, [])
652
+ return label if label
653
+ foreign = Locale._get_locale(locale, @access_key)
654
+ return @names[''] unless foreign
655
+ english = @names['en'] || @names['']
656
+ addition = english.dup.sub!(/\A#{Locale._get_locale('en', @access_key)['en']}/, '')
657
+ foreign[locale] += addition if addition
658
+ update(foreign)
659
+ return Locale._hash_value(@names, locale)
660
+ end
661
+
662
+ private
663
+
664
+ def _names(names, namespace, default_locale)
665
+
666
+ # names, link の組み立て
667
+ @names = {}
668
+ @link = {}
669
+
670
+ if names.kind_of?(String)
671
+ unless (names=~/\A\s*\[(.+?)\]\s*\z/m)
672
+ names = names.strip
673
+ @names[''] = names
674
+ @keys = ['']
675
+ @values = [names]
676
+ return names
677
+ end
678
+ names = $1.split(/[\n\r,]+/)
679
+ end
680
+
681
+ mark = []
682
+ asterisk = []
683
+ default_locale = default_locale.dup
684
+ names.each do |v|
685
+ v.strip!
686
+ case v
687
+ when '', /\A#/ ;
688
+ when /\A\/(.+)/; @access_key = $1
689
+ when /\A(\*)?(?:([^=%]*?)\s*:)?\s*(.+?)\s*(=\s*([^=]+?(\?.+)?)?)?\z/
690
+ asterisk[0], locale, name, assignment, ref = $~[1..5]
691
+ asterisk[1], locale, default_ref = default_locale.shift unless locale
692
+ locale ||= ''
693
+ ref ||= default_ref unless (assignment)
694
+ ref ||= ''
695
+ mark[0] = locale if asterisk[0]
696
+ mark[1] = locale if asterisk[1]
697
+ mark[2] = locale unless mark[2]
698
+ name = _replacement($1, locale, ($3 || @names['en'] || @names[''])) if name =~ /\A_([A-Z_]+)_(\((.+)\))?\z/
699
+ name.gsub!(/<[0-9A-F]{2}>/i) {|code| code[1..2].to_i(16).chr}
700
+ @names[locale] = name
701
+ if ref =~ /\A(.+):/
702
+ prefix = namespace[$1] || Locale.send(:_namespaces)[$1]
703
+ ref.sub!(/\A.+:/, prefix) if prefix
704
+ end
705
+ ref += '%%<' + name + '>' if ref =~ /[\/#:]\z/
706
+ unless ref == ''
707
+ @link[locale] = _encode(ref)
708
+ # When.logger.info("%s[%s]->%s" % [@names[locale], locale, @link[locale]]) if When.logger
709
+ end
710
+ else ; raise ArgumentError, "Irregal locale format: " + v
711
+ end
712
+ end
713
+ if Locale.wikipedia_interval && Locale.wikipedia_interval <= 0
714
+ ['en', ''].each do |lc|
715
+ if Locale::Ref =~ @link[lc] && $1 == 'en'
716
+ object = Locale.send(:wikipedia_object, @link[lc])
717
+ if object
718
+ @names = object.names.merge(@names)
719
+ @link = object.link.merge(@link)
720
+ end
721
+ break
722
+ end
723
+ end
724
+ end
725
+
726
+ # keys, values の準備
727
+ @keys = @names.keys.sort
728
+ @values = @names.values.sort.reverse
729
+
730
+ # 代表名
731
+ @names[mark[0] || mark[1] || mark[2]]
732
+ end
733
+
734
+ #
735
+ # 英語表記を現地表記に置き換える
736
+ #
737
+ def _replacement(table, locale, name)
738
+ Locale.const_get(table.split('_')[-1])[locale] ?
739
+ Locale.send(table.downcase, name, locale) :
740
+ name
741
+ end
742
+
743
+ # encode URI from patterns %%(...) or %.(...)
744
+ def _encode(source)
745
+ source.gsub(/%.<.+?>/) do |match|
746
+ URI.encode(match[3..-2]).gsub('%', match[1..1])
747
+ end
748
+ end
749
+ end
750
+ end