compony 0.11.13 → 0.11.14

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 (109) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/CLAUDE.md +1 -0
  4. data/Gemfile.lock +1 -1
  5. data/VERSION +1 -1
  6. data/compony.gemspec +3 -3
  7. data/doc/ComponentGenerator.html +1 -1
  8. data/doc/Components.html +1 -1
  9. data/doc/ComponentsGenerator.html +1 -1
  10. data/doc/Compony/Component.html +1 -1
  11. data/doc/Compony/ComponentMixins/Default/Labelling.html +1 -1
  12. data/doc/Compony/ComponentMixins/Default/Standalone/ResourcefulVerbDsl.html +1 -1
  13. data/doc/Compony/ComponentMixins/Default/Standalone/StandaloneDsl.html +1 -1
  14. data/doc/Compony/ComponentMixins/Default/Standalone/VerbDsl.html +1 -1
  15. data/doc/Compony/ComponentMixins/Default/Standalone.html +1 -1
  16. data/doc/Compony/ComponentMixins/Default.html +1 -1
  17. data/doc/Compony/ComponentMixins/Resourceful.html +1 -1
  18. data/doc/Compony/ComponentMixins.html +1 -1
  19. data/doc/Compony/Components/Buttons/CssButton.html +1 -1
  20. data/doc/Compony/Components/Buttons/Link.html +1 -1
  21. data/doc/Compony/Components/Buttons.html +1 -1
  22. data/doc/Compony/Components/Destroy.html +1 -1
  23. data/doc/Compony/Components/Edit.html +1 -1
  24. data/doc/Compony/Components/Form.html +41 -41
  25. data/doc/Compony/Components/Index.html +1 -1
  26. data/doc/Compony/Components/List.html +1 -1
  27. data/doc/Compony/Components/New.html +1 -1
  28. data/doc/Compony/Components/Show.html +1 -1
  29. data/doc/Compony/Components/WithForm.html +1 -1
  30. data/doc/Compony/Components.html +1 -1
  31. data/doc/Compony/ControllerMixin.html +1 -1
  32. data/doc/Compony/Engine.html +1 -1
  33. data/doc/Compony/Intent.html +1 -1
  34. data/doc/Compony/ManageIntentsDsl.html +1 -1
  35. data/doc/Compony/MethodAccessibleHash.html +1 -1
  36. data/doc/Compony/ModelFields/Anchormodel.html +1 -1
  37. data/doc/Compony/ModelFields/Association.html +1 -1
  38. data/doc/Compony/ModelFields/Attachment.html +1 -1
  39. data/doc/Compony/ModelFields/Base.html +1 -1
  40. data/doc/Compony/ModelFields/Boolean.html +1 -1
  41. data/doc/Compony/ModelFields/Color.html +1 -1
  42. data/doc/Compony/ModelFields/Currency.html +1 -1
  43. data/doc/Compony/ModelFields/Date.html +1 -1
  44. data/doc/Compony/ModelFields/Datetime.html +1 -1
  45. data/doc/Compony/ModelFields/Decimal.html +1 -1
  46. data/doc/Compony/ModelFields/Email.html +1 -1
  47. data/doc/Compony/ModelFields/Float.html +1 -1
  48. data/doc/Compony/ModelFields/Integer.html +1 -1
  49. data/doc/Compony/ModelFields/Percentage.html +1 -1
  50. data/doc/Compony/ModelFields/Phone.html +1 -1
  51. data/doc/Compony/ModelFields/RichText.html +1 -1
  52. data/doc/Compony/ModelFields/String.html +1 -1
  53. data/doc/Compony/ModelFields/Text.html +1 -1
  54. data/doc/Compony/ModelFields/Time.html +1 -1
  55. data/doc/Compony/ModelFields/Url.html +1 -1
  56. data/doc/Compony/ModelFields.html +1 -1
  57. data/doc/Compony/ModelMixin.html +13 -13
  58. data/doc/Compony/NaturalOrdering.html +1 -1
  59. data/doc/Compony/RequestContext.html +1 -1
  60. data/doc/Compony/Version.html +1 -1
  61. data/doc/Compony/ViewHelpers.html +1 -1
  62. data/doc/Compony/VirtualModel.html +1 -1
  63. data/doc/Compony.html +276 -92
  64. data/doc/ComponyController.html +1 -1
  65. data/doc/_index.html +1 -1
  66. data/doc/file.CHANGELOG.html +6 -1
  67. data/doc/file.README.html +1 -1
  68. data/doc/file.basic_component.html +1 -1
  69. data/doc/file.cookbook.html +1 -1
  70. data/doc/file.destroy.html +1 -1
  71. data/doc/file.dsl_reference.html +1 -1
  72. data/doc/file.edit.html +1 -1
  73. data/doc/file.example.html +1 -1
  74. data/doc/file.example_advanced.html +1 -1
  75. data/doc/file.feasibility.html +1 -1
  76. data/doc/file.form.html +14 -2
  77. data/doc/file.generators.html +1 -1
  78. data/doc/file.glossary.html +1 -1
  79. data/doc/file.gotchas.html +1 -1
  80. data/doc/file.index.html +1 -1
  81. data/doc/file.inheritance.html +1 -1
  82. data/doc/file.installation.html +1 -1
  83. data/doc/file.integrations.html +1 -1
  84. data/doc/file.intents.html +1 -1
  85. data/doc/file.internal_datastructures.html +1 -1
  86. data/doc/file.list.html +1 -1
  87. data/doc/file.maintaining.html +1 -1
  88. data/doc/file.model_fields.html +1 -1
  89. data/doc/file.nesting.html +1 -1
  90. data/doc/file.new.html +1 -1
  91. data/doc/file.ownership.html +1 -1
  92. data/doc/file.patterns.html +1 -1
  93. data/doc/file.pre_built_components.html +1 -1
  94. data/doc/file.resourceful.html +1 -1
  95. data/doc/file.show.html +1 -1
  96. data/doc/file.standalone.html +1 -1
  97. data/doc/file.virtual_models.html +1 -1
  98. data/doc/file.with_form.html +1 -1
  99. data/doc/guide/pre_built_components/form.md +21 -2
  100. data/doc/index.html +1 -1
  101. data/doc/method_list.html +16 -0
  102. data/doc/top-level-namespace.html +1 -1
  103. data/lib/compony/components/form.rb +5 -4
  104. data/lib/compony/model_mixin.rb +3 -2
  105. data/lib/compony.rb +19 -0
  106. data/spec/compony/components/form_spec.rb +31 -0
  107. data/spec/compony/compony_spec.rb +28 -0
  108. data/spec/compony/model_mixin_spec.rb +28 -0
  109. metadata +2 -1
@@ -247,7 +247,7 @@
247
247
  </div></div>
248
248
 
249
249
  <div id="footer">
250
- Generated on Tue Aug 18 14:36:33 2026 by
250
+ Generated on Wed Oct 7 10:48:17 2026 by
251
251
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
252
252
  0.9.34 (ruby-3.4.9).
253
253
  </div>
@@ -105,7 +105,7 @@
105
105
  </div></div>
106
106
 
107
107
  <div id="footer">
108
- Generated on Tue Aug 18 14:36:34 2026 by
108
+ Generated on Wed Oct 7 10:48:18 2026 by
109
109
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
110
110
  0.9.34 (ruby-3.4.9).
111
111
  </div>
data/doc/file.form.html CHANGED
@@ -159,7 +159,7 @@
159
159
  <pre class="code ruby"><code class="ruby"><span class='kw'>class</span> <span class='const'>Foo</span> <span class='op'>&lt;</span> <span class='const'>ApplicationRecord</span>
160
160
  <span class='comment'># No need to write:
161
161
  </span> <span class='id identifier rubyid_field'>field</span> <span class='symbol'>:label</span><span class='comma'>,</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>virtual:</span> <span class='kw'>true</span>
162
- <span class='const'>I18n</span><span class='period'>.</span><span class='id identifier rubyid_available_locales'>available_locales</span><span class='period'>.</span><span class='id identifier rubyid_each'>each</span> <span class='kw'>do</span> <span class='op'>|</span><span class='id identifier rubyid_locale'>locale</span><span class='op'>|</span>
162
+ <span class='const'><span class='object_link'><a href="Compony.html" title="Compony (module)">Compony</a></span></span><span class='period'>.</span><span class='id identifier rubyid_content_locales'><span class='object_link'><a href="Compony.html#content_locales-class_method" title="Compony.content_locales (method)">content_locales</a></span></span><span class='period'>.</span><span class='id identifier rubyid_each'>each</span> <span class='kw'>do</span> <span class='op'>|</span><span class='id identifier rubyid_locale'>locale</span><span class='op'>|</span>
163
163
  <span class='id identifier rubyid_field'>field</span> <span class='symbol'>:&quot;label_</span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_locale'>locale</span><span class='embexpr_end'>}</span><span class='tstring_end'>&quot;</span></span><span class='comma'>,</span> <span class='symbol'>:string</span>
164
164
  <span class='kw'>end</span>
165
165
 
@@ -182,10 +182,22 @@
182
182
  <span class='kw'>end</span>
183
183
  <span class='kw'>end</span>
184
184
  </code></pre>
185
+
186
+ <h3 id="content-locales">Content locales</h3>
187
+
188
+ <p>By default, <code>multilang: true</code> generates one field per locale in <code>I18n.available_locales</code>. If your app’s locales differ from the languages your content is stored in, for instance because it uses regional locales such as <code>:&quot;de-CH&quot;</code> and <code>:&quot;de-DE&quot;</code> while content is stored per language, configure the content locales in an initializer:</p>
189
+
190
+ <pre class="code ruby"><code class="ruby"><span class='comment'># config/initializers/compony.rb
191
+ </span><span class='const'><span class='object_link'><a href="Compony.html" title="Compony (module)">Compony</a></span></span><span class='period'>.</span><span class='id identifier rubyid_content_locales'><span class='object_link'><a href="Compony.html#content_locales-class_method" title="Compony.content_locales (method)">content_locales</a></span></span> <span class='op'>=</span> <span class='qsymbols_beg'>%i[</span><span class='tstring_content'>de</span><span class='words_sep'> </span><span class='tstring_content'>en</span><span class='words_sep'> </span><span class='tstring_content'>fr</span><span class='tstring_end'>]</span></span>
192
+ </code></pre>
193
+
194
+ <p>With <code>I18n.available_locales = %i[de de-CH en fr]</code>, <code>field :label, :string, multilang: true</code> then generates <code>label</code> (virtual), <code>label_de</code>, <code>label_en</code> and <code>label_fr</code>, without a <code>label_de-CH</code>. The form’s <code>field</code> and <code>schema_field</code> follow the same setting.</p>
195
+
196
+ <p>Model fields are generated when the model class loads, so the setting must be in place before any model loads. An initializer guarantees that. If the locales are only known later, pass a callable instead, which is evaluated every time the content locales are needed: <code>Compony.content_locales = -&gt; { MyApp.content_locales }</code>.</p>
185
197
  </div></div>
186
198
 
187
199
  <div id="footer">
188
- Generated on Tue Aug 18 14:36:34 2026 by
200
+ Generated on Wed Oct 7 10:48:18 2026 by
189
201
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
190
202
  0.9.34 (ruby-3.4.9).
191
203
  </div>
@@ -79,7 +79,7 @@
79
79
  </div></div>
80
80
 
81
81
  <div id="footer">
82
- Generated on Tue Aug 18 14:36:34 2026 by
82
+ Generated on Wed Oct 7 10:48:18 2026 by
83
83
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
84
84
  0.9.34 (ruby-3.4.9).
85
85
  </div>
@@ -207,7 +207,7 @@
207
207
  </div></div>
208
208
 
209
209
  <div id="footer">
210
- Generated on Tue Aug 18 14:36:35 2026 by
210
+ Generated on Wed Oct 7 10:48:19 2026 by
211
211
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
212
212
  0.9.34 (ruby-3.4.9).
213
213
  </div>
@@ -212,7 +212,7 @@
212
212
  </div></div>
213
213
 
214
214
  <div id="footer">
215
- Generated on Tue Aug 18 14:36:35 2026 by
215
+ Generated on Wed Oct 7 10:48:19 2026 by
216
216
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
217
217
  0.9.34 (ruby-3.4.9).
218
218
  </div>
data/doc/file.index.html CHANGED
@@ -125,7 +125,7 @@
125
125
  </div></div>
126
126
 
127
127
  <div id="footer">
128
- Generated on Tue Aug 18 14:36:34 2026 by
128
+ Generated on Wed Oct 7 10:48:18 2026 by
129
129
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
130
130
  0.9.34 (ruby-3.4.9).
131
131
  </div>
@@ -126,7 +126,7 @@
126
126
  </div></div>
127
127
 
128
128
  <div id="footer">
129
- Generated on Tue Aug 18 14:36:33 2026 by
129
+ Generated on Wed Oct 7 10:48:17 2026 by
130
130
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
131
131
  0.9.34 (ruby-3.4.9).
132
132
  </div>
@@ -105,7 +105,7 @@
105
105
  </div></div>
106
106
 
107
107
  <div id="footer">
108
- Generated on Tue Aug 18 14:36:33 2026 by
108
+ Generated on Wed Oct 7 10:48:17 2026 by
109
109
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
110
110
  0.9.34 (ruby-3.4.9).
111
111
  </div>
@@ -208,7 +208,7 @@
208
208
  </div></div>
209
209
 
210
210
  <div id="footer">
211
- Generated on Tue Aug 18 14:36:35 2026 by
211
+ Generated on Wed Oct 7 10:48:19 2026 by
212
212
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
213
213
  0.9.34 (ruby-3.4.9).
214
214
  </div>
@@ -255,7 +255,7 @@ end
255
255
  </div></div>
256
256
 
257
257
  <div id="footer">
258
- Generated on Tue Aug 18 14:36:34 2026 by
258
+ Generated on Wed Oct 7 10:48:18 2026 by
259
259
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
260
260
  0.9.34 (ruby-3.4.9).
261
261
  </div>
@@ -119,7 +119,7 @@
119
119
  </div></div>
120
120
 
121
121
  <div id="footer">
122
- Generated on Tue Aug 18 14:36:34 2026 by
122
+ Generated on Wed Oct 7 10:48:18 2026 by
123
123
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
124
124
  0.9.34 (ruby-3.4.9).
125
125
  </div>
data/doc/file.list.html CHANGED
@@ -243,7 +243,7 @@
243
243
  </div></div>
244
244
 
245
245
  <div id="footer">
246
- Generated on Tue Aug 18 14:36:34 2026 by
246
+ Generated on Wed Oct 7 10:48:18 2026 by
247
247
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
248
248
  0.9.34 (ruby-3.4.9).
249
249
  </div>
@@ -117,7 +117,7 @@
117
117
  </div></div>
118
118
 
119
119
  <div id="footer">
120
- Generated on Tue Aug 18 14:36:35 2026 by
120
+ Generated on Wed Oct 7 10:48:19 2026 by
121
121
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
122
122
  0.9.34 (ruby-3.4.9).
123
123
  </div>
@@ -127,7 +127,7 @@
127
127
  </div></div>
128
128
 
129
129
  <div id="footer">
130
- Generated on Tue Aug 18 14:36:34 2026 by
130
+ Generated on Wed Oct 7 10:48:18 2026 by
131
131
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
132
132
  0.9.34 (ruby-3.4.9).
133
133
  </div>
@@ -227,7 +227,7 @@ The number 8 has the binary form 1000. Enter a number and press ENTER: [8]
227
227
  </div></div>
228
228
 
229
229
  <div id="footer">
230
- Generated on Tue Aug 18 14:36:33 2026 by
230
+ Generated on Wed Oct 7 10:48:17 2026 by
231
231
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
232
232
  0.9.34 (ruby-3.4.9).
233
233
  </div>
data/doc/file.new.html CHANGED
@@ -99,7 +99,7 @@
99
99
  </div></div>
100
100
 
101
101
  <div id="footer">
102
- Generated on Tue Aug 18 14:36:34 2026 by
102
+ Generated on Wed Oct 7 10:48:18 2026 by
103
103
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
104
104
  0.9.34 (ruby-3.4.9).
105
105
  </div>
@@ -88,7 +88,7 @@
88
88
  </div></div>
89
89
 
90
90
  <div id="footer">
91
- Generated on Tue Aug 18 14:36:34 2026 by
91
+ Generated on Wed Oct 7 10:48:18 2026 by
92
92
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
93
93
  0.9.34 (ruby-3.4.9).
94
94
  </div>
@@ -659,7 +659,7 @@
659
659
  </div></div>
660
660
 
661
661
  <div id="footer">
662
- Generated on Tue Aug 18 14:36:35 2026 by
662
+ Generated on Wed Oct 7 10:48:19 2026 by
663
663
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
664
664
  0.9.34 (ruby-3.4.9).
665
665
  </div>
@@ -89,7 +89,7 @@
89
89
  </div></div>
90
90
 
91
91
  <div id="footer">
92
- Generated on Tue Aug 18 14:36:34 2026 by
92
+ Generated on Wed Oct 7 10:48:18 2026 by
93
93
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
94
94
  0.9.34 (ruby-3.4.9).
95
95
  </div>
@@ -171,7 +171,7 @@
171
171
  </div></div>
172
172
 
173
173
  <div id="footer">
174
- Generated on Tue Aug 18 14:36:33 2026 by
174
+ Generated on Wed Oct 7 10:48:17 2026 by
175
175
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
176
176
  0.9.34 (ruby-3.4.9).
177
177
  </div>
data/doc/file.show.html CHANGED
@@ -148,7 +148,7 @@
148
148
  </div></div>
149
149
 
150
150
  <div id="footer">
151
- Generated on Tue Aug 18 14:36:34 2026 by
151
+ Generated on Wed Oct 7 10:48:18 2026 by
152
152
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
153
153
  0.9.34 (ruby-3.4.9).
154
154
  </div>
@@ -223,7 +223,7 @@
223
223
  </div></div>
224
224
 
225
225
  <div id="footer">
226
- Generated on Tue Aug 18 14:36:33 2026 by
226
+ Generated on Wed Oct 7 10:48:17 2026 by
227
227
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
228
228
  0.9.34 (ruby-3.4.9).
229
229
  </div>
@@ -107,7 +107,7 @@
107
107
  </div></div>
108
108
 
109
109
  <div id="footer">
110
- Generated on Tue Aug 18 14:36:34 2026 by
110
+ Generated on Wed Oct 7 10:48:18 2026 by
111
111
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
112
112
  0.9.34 (ruby-3.4.9).
113
113
  </div>
@@ -147,7 +147,7 @@
147
147
  </div></div>
148
148
 
149
149
  <div id="footer">
150
- Generated on Tue Aug 18 14:36:34 2026 by
150
+ Generated on Wed Oct 7 10:48:18 2026 by
151
151
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
152
152
  0.9.34 (ruby-3.4.9).
153
153
  </div>
@@ -91,7 +91,7 @@ In the model:
91
91
  class Foo < ApplicationRecord
92
92
  # No need to write:
93
93
  field :label, :string, virtual: true
94
- I18n.available_locales.each do |locale|
94
+ Compony.content_locales.each do |locale|
95
95
  field :"label_#{locale}", :string
96
96
  end
97
97
 
@@ -114,4 +114,23 @@ class Components::Foos::Form < Compony::Components::Form
114
114
  schema_field :label, multilang: true
115
115
  end
116
116
  end
117
- ```
117
+ ```
118
+
119
+ ### Content locales
120
+
121
+ By default, `multilang: true` generates one field per locale in `I18n.available_locales`. If your app's locales differ
122
+ from the languages your content is stored in, for instance because it uses regional locales such as `:"de-CH"` and
123
+ `:"de-DE"` while content is stored per language, configure the content locales in an initializer:
124
+
125
+ ```ruby
126
+ # config/initializers/compony.rb
127
+ Compony.content_locales = %i[de en fr]
128
+ ```
129
+
130
+ With `I18n.available_locales = %i[de de-CH en fr]`, `field :label, :string, multilang: true` then generates `label`
131
+ (virtual), `label_de`, `label_en` and `label_fr`, without a `label_de-CH`. The form's `field` and `schema_field` follow
132
+ the same setting.
133
+
134
+ Model fields are generated when the model class loads, so the setting must be in place before any model loads. An
135
+ initializer guarantees that. If the locales are only known later, pass a callable instead, which is evaluated every time
136
+ the content locales are needed: `Compony.content_locales = -> { MyApp.content_locales }`.
data/doc/index.html CHANGED
@@ -230,7 +230,7 @@
230
230
  </div></div>
231
231
 
232
232
  <div id="footer">
233
- Generated on Tue Aug 18 14:36:32 2026 by
233
+ Generated on Wed Oct 7 10:48:16 2026 by
234
234
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
235
235
  0.9.34 (ruby-3.4.9).
236
236
  </div>
data/doc/method_list.html CHANGED
@@ -364,6 +364,22 @@
364
364
  </li>
365
365
 
366
366
 
367
+ <li class="odd ">
368
+ <div class="item">
369
+ <span class='object_link'><a href="Compony.html#content_locales-class_method" title="Compony.content_locales (method)">content_locales</a></span>
370
+ <small>Compony</small>
371
+ </div>
372
+ </li>
373
+
374
+
375
+ <li class="even ">
376
+ <div class="item">
377
+ <span class='object_link'><a href="Compony.html#content_locales=-class_method" title="Compony.content_locales= (method)">content_locales=</a></span>
378
+ <small>Compony</small>
379
+ </div>
380
+ </li>
381
+
382
+
367
383
  <li class="odd ">
368
384
  <div class="item">
369
385
  <span class='object_link'><a href="Compony/RequestContext.html#controller-instance_method" title="Compony::RequestContext#controller (method)">#controller</a></span>
@@ -102,7 +102,7 @@
102
102
  </div>
103
103
 
104
104
  <div id="footer">
105
- Generated on Tue Aug 18 14:36:35 2026 by
105
+ Generated on Wed Oct 7 10:48:19 2026 by
106
106
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
107
107
  0.9.34 (ruby-3.4.9).
108
108
  </div>
@@ -106,7 +106,8 @@ module Compony
106
106
  # DSL method (inside `form_fields`). Renders a simple_form input inferred from the model field `name`.
107
107
  # Respects per-field CanCanCan authorization; skipped fields render nothing.
108
108
  # @param name [Symbol,String] The model field (use the association name, not the `_id`, for associations).
109
- # @param multilang [Boolean] If true, generates one suffixed input per available locale and returns the array (useful with the "mobility" gem).
109
+ # @param multilang [Boolean] If true, generates one suffixed input per content locale and returns the array (useful with the "mobility" gem).
110
+ # See {Compony.content_locales}.
110
111
  # @param input_opts [Hash] Passed to simple_form. Notable keys: `as:` (input type), `hidden: true`, `autofocus:`.
111
112
  # @return [String,Array<String>] The input HTML (array when `multilang`).
112
113
  # @api public
@@ -114,7 +115,7 @@ module Compony
114
115
  fail("The `field` method may only be called inside `form_fields` for #{inspect}.") unless @simpleform
115
116
 
116
117
  if multilang
117
- I18n.available_locales.map { |locale| field("#{name}_#{locale}", **input_opts) }
118
+ Compony.content_locales.map { |locale| field("#{name}_#{locale}", **input_opts) }
118
119
  else
119
120
  name = name.to_sym
120
121
 
@@ -215,12 +216,12 @@ module Compony
215
216
  # DSL method, whitelists a single field of `data_class` in the param schema, auto-generating the correct schema line.
216
217
  # Respects per-field CanCanCan authorization.
217
218
  # @param field_name [Symbol,String] The model field (association name, not `_id`, for associations).
218
- # @param multilang [Boolean] If true, whitelists one suffixed field per available locale (useful with the "mobility" gem).
219
+ # @param multilang [Boolean] If true, whitelists one suffixed field per content locale, see {Compony.content_locales} (useful with the "mobility" gem).
219
220
  # @return [void]
220
221
  # @api public
221
222
  def schema_field(field_name, multilang: false)
222
223
  if multilang
223
- I18n.available_locales.each { |locale| schema_field("#{field_name}_#{locale}") }
224
+ Compony.content_locales.each { |locale| schema_field("#{field_name}_#{locale}") }
224
225
  else
225
226
  # This runs upon component setup.
226
227
  @schema_lines_for_data << proc do |data, controller|
@@ -19,11 +19,12 @@ module Compony
19
19
  end
20
20
 
21
21
  # DSL method, defines a new field which will be translated and can be added to field groups
22
- # If multilang is true, a suffixed field is generated for every available locale, along with a non-suffixed virtual field (useful with gem "mobility")
22
+ # If multilang is true, a suffixed field is generated for every content locale, along with a non-suffixed virtual field (useful with gem "mobility").
23
+ # See Compony.content_locales.
23
24
  def field(name, type, multilang: false, **extra_attrs)
24
25
  if multilang
25
26
  field(name, type, virtual: true, **extra_attrs)
26
- I18n.available_locales.each { |locale| field("#{name}_#{locale}", type, **extra_attrs) }
27
+ Compony.content_locales.each { |locale| field("#{name}_#{locale}", type, **extra_attrs) }
27
28
  else
28
29
  name = name.to_sym
29
30
  self.fields = fields.dup
data/lib/compony.rb CHANGED
@@ -35,6 +35,17 @@ module Compony
35
35
  @model_field_namespaces = model_field_namespaces
36
36
  end
37
37
 
38
+ # Setter for the content locales, i.e. the languages in which `multilang: true` fields exist (useful with gem "mobility").
39
+ # Set this when your app's `I18n.available_locales` differ from the languages your content is stored in, e.g. when
40
+ # using regional locales such as `:"de-CH"` while content is stored per language (`label_de`, `label_en`, ...).
41
+ # Model fields are generated when the model class loads, so set this in an initializer, before any model is loaded.
42
+ # Alternatively, pass a callable, which is evaluated every time the content locales are needed.
43
+ # @param content_locales [Array<Symbol,String>,#call] The content locales, or a callable returning them. Defaults to `I18n.available_locales`.
44
+ # @see {Compony#content_locales}
45
+ def self.content_locales=(content_locales)
46
+ @content_locales = content_locales
47
+ end
48
+
38
49
  # Setter for the name of the Rails `before_action` that should be called to
39
50
  # ensure that users are authenticated before accessing the component. For
40
51
  # instance, implement a method `def enforce_authentication` in your
@@ -99,6 +110,14 @@ module Compony
99
110
  return @model_field_namespaces ||= ['Compony::ModelFields']
100
111
  end
101
112
 
113
+ # Getter for the content locales, defaults to `I18n.available_locales`.
114
+ # @return [Array<Symbol>] The locales for which `multilang: true` fields generate a suffixed field.
115
+ # @see Compony#content_locales= Explanation of content_locales (documented in the corresponding setter)
116
+ def self.content_locales
117
+ content_locales = @content_locales.respond_to?(:call) ? @content_locales.call : @content_locales
118
+ return (content_locales || I18n.available_locales).map(&:to_sym)
119
+ end
120
+
102
121
  # Getter for the name of the Rails `before_action` that enforces authentication.
103
122
  # @see Compony#authentication_before_action= Explanation of authentication_before_action (documented in the corresponding setter)
104
123
  def self.authentication_before_action
@@ -0,0 +1,31 @@
1
+ RSpec.describe Compony::Components::Form do
2
+ describe 'multilang' do
3
+ around do |example|
4
+ original_available_locales = I18n.available_locales
5
+ I18n.available_locales = %i[en de de-CH fr es]
6
+ Compony.content_locales = %i[de en fr es]
7
+ example.run
8
+ ensure
9
+ I18n.available_locales = original_available_locales
10
+ Compony.content_locales = nil
11
+ end
12
+
13
+ let(:form) { described_class.new }
14
+
15
+ it 'renders one field per content locale' do
16
+ form.instance_variable_set(:@simpleform, Object.new) # `field` refuses to run outside `form_fields`
17
+ allow(form).to receive(:field).and_call_original
18
+ allow(form).to receive(:field).with(a_string_starting_with('label_')) { |name| name }
19
+ expect(form.field(:label, multilang: true)).to eq(%w[label_de label_en label_fr label_es])
20
+ end
21
+
22
+ it 'whitelists one schema field per content locale' do
23
+ allow(form).to receive(:schema_field).and_call_original
24
+ form.send(:schema_field, :label, multilang: true) # DSL method, protected
25
+ %w[label_de label_en label_fr label_es].each do |name|
26
+ expect(form).to have_received(:schema_field).with(name)
27
+ end
28
+ expect(form).not_to have_received(:schema_field).with('label_de-CH')
29
+ end
30
+ end
31
+ end
@@ -99,4 +99,32 @@ RSpec.describe Compony do
99
99
  expect(described_class.model_field_namespaces).to eq(['Compony::ModelFields'])
100
100
  end
101
101
  end
102
+
103
+ describe '.content_locales' do
104
+ around do |example|
105
+ original_available_locales = I18n.available_locales
106
+ example.run
107
+ ensure
108
+ I18n.available_locales = original_available_locales
109
+ described_class.content_locales = nil
110
+ end
111
+
112
+ it 'defaults to I18n.available_locales' do
113
+ I18n.available_locales = %i[en de]
114
+ expect(described_class.content_locales).to eq(%i[en de])
115
+ end
116
+
117
+ it 'returns the configured locales as symbols' do
118
+ described_class.content_locales = %w[de en]
119
+ expect(described_class.content_locales).to eq(%i[de en])
120
+ end
121
+
122
+ it 'evaluates a callable every time' do
123
+ locales = %i[de]
124
+ described_class.content_locales = -> { locales }
125
+ expect(described_class.content_locales).to eq(%i[de])
126
+ locales = %i[de fr]
127
+ expect(described_class.content_locales).to eq(%i[de fr])
128
+ end
129
+ end
102
130
  end
@@ -30,6 +30,34 @@ RSpec.describe Compony::ModelMixin do
30
30
  expect(subclass.fields).to have_key(:extra)
31
31
  expect(User.fields).not_to have_key(:extra)
32
32
  end
33
+
34
+ context 'with multilang: true' do
35
+ around do |example|
36
+ original_available_locales = I18n.available_locales
37
+ I18n.available_locales = %i[en de de-CH fr es]
38
+ example.run
39
+ ensure
40
+ I18n.available_locales = original_available_locales
41
+ Compony.content_locales = nil
42
+ end
43
+
44
+ def multilang_model
45
+ Class.new(User) do
46
+ def self.name = 'MultilangUser'
47
+ field :label, :string, multilang: true
48
+ end
49
+ end
50
+
51
+ it 'generates a virtual field plus one suffixed field per available locale by default' do
52
+ expect(multilang_model.fields.keys - User.fields.keys).to eq(%i[label label_en label_de label_de-CH label_fr label_es])
53
+ expect(multilang_model.fields[:label].extra_attrs).to eq(virtual: true)
54
+ end
55
+
56
+ it 'generates one suffixed field per content locale when configured' do
57
+ Compony.content_locales = %i[de en fr es]
58
+ expect(multilang_model.fields.keys - User.fields.keys).to eq(%i[label label_de label_en label_fr label_es])
59
+ end
60
+ end
33
61
  end
34
62
 
35
63
  describe 'feasibility' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: compony
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.13
4
+ version: 0.11.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sandro Kalbermatter
@@ -427,6 +427,7 @@ files:
427
427
  - logo.svg
428
428
  - spec/README.md
429
429
  - spec/compony/component_spec.rb
430
+ - spec/compony/components/form_spec.rb
430
431
  - spec/compony/compony_spec.rb
431
432
  - spec/compony/intent_spec.rb
432
433
  - spec/compony/method_accessible_hash_spec.rb