]> Git — Sourcephile - julm/worksheets.git/blob - tests/Rosetta/WritingSpec.hs
update
[julm/worksheets.git] / tests / Rosetta / WritingSpec.hs
1 {-# LANGUAGE OverloadedLists #-}
2
3 module Rosetta.WritingSpec where
4
5 import Data.GenValidity.Map ()
6 import Data.GenValidity.Sequence ()
7 import Data.GenValidity.Set ()
8 import Data.GenValidity.Text ()
9 import Data.List qualified as List
10 import Data.Map.Strict qualified as Map
11 import Data.Text qualified as Text
12 import Data.Validity.Map ()
13 import Data.Validity.Set ()
14 import Data.Validity.Text ()
15 import System.FilePath (joinPath, pathSeparator, (<.>), (</>))
16 import Test.Syd
17
18 import Language
19 import Language.Chinese qualified as Chinese
20 import Language.Pronunciation qualified as Pron
21 import Rosetta.Reading qualified as Reading
22 import Rosetta.Writing
23 import Worksheets.Utils.Char qualified as Char
24 import Worksheets.Utils.HTML (cm)
25 import Worksheets.Utils.HTML qualified as HTML
26 import Worksheets.Utils.Prelude
27
28 runPages :: String -> Pages -> TestDefM (Chinese.ChineseDict : outers) () ()
29 runPages title pages_ = do
30 descrPath <- getTestDescriptionPath
31 let dirPath =
32 List.reverse descrPath
33 <&> Text.unpack
34 . Text.replace
35 (Text.pack ".")
36 (Text.singleton pathSeparator)
37 & joinPath
38 let outPath = "tests" </> dirPath </> title </> "rosetta" <.> "html"
39 itWithOuter title \dict -> do
40 goldenByteStringBuilderFile outPath $
41 pagesHTML dict (Text.pack title) pages_
42
43 spec :: HasCallStack => Spec
44 spec = aroundAll readDict do
45 -- runPage "Avion" avion
46 -- runPage "Bateau" bateau
47 -- runPage "Chocolat" chocolat
48 -- runPage "Pistache" pistache
49 -- runPage "Egg" egg
50 -- runPage "Pluie" pluie
51 -- runPage "TarteAuxPommes" tarteAuxPommesDanniversaire
52 -- runPage "ChatChevalVélo" chatChevalVélo
53 -- runPage "chevauxDormirDebout" chevauxDormirDebout
54 forM_ (rosettas & Map.toList) \(name, pages) ->
55 runPages name pages
56 where
57 readDict :: (Chinese.ChineseDict -> IO ()) -> IO ()
58 -- readDict k = k mempty
59 readDict = (Chinese.readChineseDict >>=)
60
61 {-
62 chocolat =
63 mempty
64 { pageParts =
65 [ PagePart
66 { partPicture = "Plantes/Cacao/Fruit-cacao-tree-source-cocoa-chocolate-plant.avif"
67 , partDescription = ""
68 , partLangue = LangueFrançais
69 , partText = "Le chocolat contient du cacao"
70 }
71 , PagePart
72 { partPicture = "Plantes/Cacao/42f651_95f537d693fb48068880a02efa662822~mv2.avif"
73 , partDescription = ""
74 , partLangue = LangueAnglais
75 , partText = "Chocolate contains cocoa"
76 }
77 , PagePart
78 { partPicture = "Plantes/Cacao/Chocolate-Ingredients_520x500_c496776e-df9b-4348-a662-5ff65279f5ca.avif"
79 , partDescription = ""
80 , partLangue = LangueMandarin
81 , partText = "巧克力 含有 可可"
82 }
83 ]
84 }
85 pistache =
86 mempty
87 { pageParts =
88 [ PagePart
89 { partPicture = "Plantes/Pistache/581614a479ee6b4df250c4caddc04bca.avif"
90 , partDescription = ""
91 , partLangue = LangueFrançais
92 , partText = "La glace à la pistache est délicieuse"
93 }
94 , PagePart
95 { partPicture = "Plantes/Pistache/pistachios.avif"
96 , partDescription = ""
97 , partLangue = LangueAnglais
98 , partText = "Pistachio ice cream is delicious"
99 }
100 , PagePart
101 { partPicture = "Plantes/Pistache/No-Churn-Vegan-Pistachio-Ice-Cream-3-e1502503524224.avif"
102 , partDescription = ""
103 , partLangue = LangueMandarin
104 , partText = "开心果 冰淇淋 很 好吃"
105 }
106 ]
107 }
108 avion =
109 mempty
110 { pageParts =
111 [ PagePart
112 { partPicture = "Avion/sound-barrier.avif"
113 , partDescription = ""
114 , partLangue = LangueFrançais
115 , partText = "Avion dans le ciel"
116 }
117 , PagePart
118 { partPicture = "Avion/mustang.avif"
119 , partDescription = ""
120 , partLangue = LangueAnglais
121 , partText = "Airoplane in the sky"
122 }
123 , PagePart
124 { partPicture = "Avion/cockpit.avif"
125 , partDescription = ""
126 , partLangue = LangueMandarin
127 , partText = "天空 中 有 一 架 飞机"
128 }
129 ]
130 }
131 egg =
132 mempty
133 { pageParts =
134 [ PagePart
135 { partPicture = "Egg/R.avif"
136 , partDescription = ""
137 , partLangue = LangueFrançais
138 , partText = "Les poules pondent des œufs"
139 }
140 , PagePart
141 { partPicture = "Egg/everything-you-ever-wanted-to-know-about-chicken-eggs.avif"
142 , partDescription = ""
143 , partLangue = LangueAnglais
144 , partText = "Hens lay eggs"
145 }
146 , PagePart
147 { partPicture = "Egg/OIP.avif"
148 , partDescription = ""
149 , partLangue = LangueMandarin
150 , partText = "母鸡 下蛋"
151 }
152 ]
153 }
154 pluie =
155 mempty
156 { pageParts =
157 [ PagePart
158 { partPicture = "Pluie/R.avif"
159 , partDescription = ""
160 , partLangue = LangueFrançais
161 , partText = "L'eau de pluie retourne à l'océan"
162 }
163 , PagePart
164 { partPicture = "Pluie/OIP2.avif"
165 , partDescription = ""
166 , partLangue = LangueAnglais
167 , partText = "Rainwater returns to the ocean"
168 }
169 , PagePart
170 { partPicture = "Pluie/c1b4767475208de5a389045b7ad856a0.avif"
171 , partDescription = ""
172 , partLangue = LangueMandarin
173 , partText = "雨水 回归 海洋"
174 }
175 ]
176 }
177 tarteAuxPommesDanniversaire =
178 mempty
179 { pageParts =
180 [ PagePart
181 { partPicture = "TarteAuxPommesDanniversaire/IMG_20250605_180725.avif"
182 , partDescription = ""
183 , partLangue = LangueFrançais
184 , partText = "Délicieuse tarte aux pommes d'anniversaire"
185 }
186 , PagePart
187 { partPicture = "TarteAuxPommesDanniversaire/VID_20250605_214924.mp4.00-01-40-421.avif"
188 , partDescription = ""
189 , partLangue = LangueAnglais
190 , partText = "Delicious birthday apple pie"
191 }
192 , PagePart
193 { partPicture = "TarteAuxPommesDanniversaire/VID_20250605_214924.mp4.00-01-47-284.avif"
194 , partDescription = ""
195 , partLangue = LangueMandarin
196 , partText = "美味 的 生日 苹果派"
197 }
198 ]
199 }
200 chatChevalVélo =
201 mempty
202 { pageParts =
203 [ PagePart
204 { partPicture = "Chat/IMG_20250605_194233_truffe.avif"
205 , partDescription = ""
206 , partLangue = LangueFrançais
207 , partText = "chat cheval vélo"
208 }
209 , PagePart
210 { partPicture = "Cheval/IMG_20250602_170549_himalaya.avif"
211 , partDescription = ""
212 , partLangue = LangueAnglais
213 , partText = "cat horse bicycle"
214 }
215 , PagePart
216 { partPicture = "Vélo/IMG_20250602_155624.fav.vélos.avif"
217 , partDescription = ""
218 , partLangue = LangueMandarin
219 , partText = "猫 马 自行车"
220 }
221 ]
222 }
223 -}
224
225 pages :: Pages
226 pages =
227 typeDefault
228 { pagesDifficulties =
229 langues & Map.fromSet \_lang ->
230 Char.unicodeBlocks & Map.fromSet difficulty
231 -- <&> (\v -> v{difficultyHiddenPatterns = True})
232 -- & Map.mapWithKey (\k v -> v{difficultyReading = v & difficultyReading & })
233 }
234 page :: Page
235 page = typeDefault
236
237 difficulty :: Char.UnicodeBlock -> Difficulty
238 difficulty ub = case ub of
239 Char.UnicodeBlockLatin{} ->
240 Difficulty
241 { difficultyModel = True
242 , difficultyHiddenPatterns = True
243 , difficultyReading =
244 Reading.Difficulty
245 { Reading.difficultyCharWidth = 1 & cm
246 , Reading.difficultyCharHeight = 1 & cm
247 , Reading.difficultyWordSpacing = 0.5 & cm
248 , Reading.difficultyFontSize = 0.7 & cm
249 }
250 }
251 Char.UnicodeBlockCJK{} ->
252 Difficulty
253 { difficultyModel = False
254 , difficultyHiddenPatterns = False
255 , difficultyReading =
256 Reading.Difficulty
257 { Reading.difficultyCharWidth = 1.5 & cm
258 , Reading.difficultyCharHeight = 1.5 & cm
259 , Reading.difficultyWordSpacing = 0.5 & cm
260 , Reading.difficultyFontSize = 1.20 & cm
261 }
262 }
263 Char.UnicodeBlockHalfwidth_and_Fullwidth_Forms{} ->
264 Difficulty
265 { difficultyModel = True
266 , difficultyHiddenPatterns = False
267 , difficultyReading =
268 Reading.Difficulty
269 { Reading.difficultyCharWidth = 1.35 & cm
270 , Reading.difficultyCharHeight = 1.35 & cm
271 , Reading.difficultyWordSpacing = 0.5 & cm
272 , Reading.difficultyFontSize = 1.10 & cm
273 }
274 }
275 Char.UnicodeBlockMiscellaneous_Technical{} ->
276 difficulty $ Char.UnicodeBlockLatin Char.UnicodeBlockLatin_Basic
277 _ -> typeDefault
278
279 rosettas :: Map String Pages
280 rosettas =
281 []
282
283 {- "bateau"
284 := page
285 { pageParts =
286 [ typeDefault
287 { partPicture = "Bateau/pirate-boat.avif"
288 , partPictureCSS =
289 HTML.cssBlockObjectFitCover
290 <> ["object-position" := "center -1.2cm"]
291 , partDescription = ""
292 , partLangue = LangueFrançais
293 , partText = "Un bateau flotte si moins dense que l’eau"
294 }
295 , typeDefault
296 { partPicture = "Bateau/tanker.avif"
297 , partPictureCSS =
298 HTML.cssBlockObjectFitCover
299 <> ["object-position" := "center -2.5cm"]
300 , partDescription = ""
301 , partLangue = LangueAnglais
302 , partText = "A boat floats if less dense than water"
303 }
304 , typeDefault
305 { partPicture = "Bateau/catamaran.avif"
306 , partPictureCSS =
307 HTML.cssBlockObjectFitCover
308 <> ["object-position" := "center -0.8cm"]
309 , partDescription = ""
310 , partLangue = LangueMandarin
311 , partText = "船 漂浮 如果 小 密度 于 水"
312 }
313 ]
314 }
315 & pagePortrait
316 , "chocolat"
317 := page
318 { pageParts =
319 [ typeDefault
320 { partPicture = "Plantes/Cacao/Fruit-cacao-tree-source-cocoa-chocolate-plant.avif"
321 , partDescription = ""
322 , partLangue = LangueFrançais
323 , partText = "Le chocolat contient du cacao"
324 }
325 , typeDefault
326 { partPicture = "Plantes/Cacao/42f651_95f537d693fb48068880a02efa662822~mv2.avif"
327 , partDescription = ""
328 , partLangue = LangueAnglais
329 , partText = "Chocolate contains cocoa"
330 }
331 , typeDefault
332 { partPicture = "Plantes/Cacao/Chocolate-Ingredients_520x500_c496776e-df9b-4348-a662-5ff65279f5ca.avif"
333 , partDescription = ""
334 , partLangue = LangueMandarin
335 , partText = "巧克力 含有 可可"
336 }
337 ]
338 }
339 & pageLandscape
340 , "chevauxDormirDebout"
341 := page
342 { pageParts =
343 [ typeDefault
344 { partPicture = "Cheval/R5.avif"
345 , partDescription = ""
346 , partLangue = LangueFrançais
347 , partText = "Les chevaux peuvent dormir debout"
348 }
349 , typeDefault
350 { partPicture = "Cheval/Do-Horses-Lay-Down-to-Sleep.avif"
351 , partDescription = ""
352 , partLangue = LangueAnglais
353 , partText = "Horses can sleep standing up"
354 }
355 , typeDefault
356 { partPicture = "Cheval/3YVGNyR45fw5NwHQxvJ8P6.avif"
357 , partDescription = ""
358 , partLangue = LangueMandarin
359 , partText = "马 可以 站 着 睡觉"
360 }
361 ]
362 }
363 & pageLandscape
364 , "ponies"
365 := page
366 { pageParts =
367 [ typeDefault
368 { partPicture = "Poney/Horse-and-pony2.avif"
369 , partPictureCSS = HTML.cssBlockObjectFitCover
370 , partDescription = ""
371 , partLangue = LangueFrançais
372 , partText = "Les poneys sont petits mais costauds"
373 }
374 , typeDefault
375 { partPicture = "Poney/A-girl-equestrian-athlete-jumps-on-a-horse-high-barrier-ss230301-768x448.jpg.avif"
376 , partPictureCSS = HTML.cssBlockObjectFitCover
377 , partDescription = ""
378 , partLangue = LangueAnglais
379 , partText = "Ponies are small but strong"
380 }
381 , typeDefault
382 { partPicture = "Poney/horse-pull.avif"
383 , partPictureCSS = HTML.cssBlockObjectFitCover
384 , partDescription = ""
385 , partLangue = LangueMandarin
386 , partText = "小马 虽 小 但 很 强壮"
387 }
388 ]
389 }
390 & pageLandscape
391 , "poniesRaces1"
392 := page
393 { pageParts =
394 [ typeDefault
395 { partPicture = "Poney/Shetland/Canva-Ponies-of-the-New-Forest-scaled.avif"
396 , partPictureCSS = HTML.cssBlockObjectFitCover
397 , partDescription = "Shetland Pony"
398 , partLangue = LangueFrançais
399 , partText = "Il existe environ 159 races de poneys"
400 }
401 , typeDefault
402 { partPicture = "Poney/PoneyFrançaisDeSelle/pho11-1441004372-ulk-modele1.avif"
403 , partPictureCSS = HTML.cssBlockObjectFitCover
404 , partDescription = "Poney Français de Selle"
405 , partLangue = LangueAnglais
406 , partText = "There are approximately 159 pony breeds"
407 }
408 , typeDefault
409 { partPicture = "Poney/NorwegianFjord/shutterstock_2092896190-1024x683.avif"
410 , partPictureCSS = HTML.cssBlockObjectFitCover
411 , partDescription = "Norwegian Fjord Pony"
412 , partLangue = LangueMandarin
413 , partText = "有 大约 159 个 小马 品种"
414 }
415 ]
416 }
417 & pageLandscape
418 , "poniesRaces2"
419 := page
420 { pageParts =
421 [ typeDefault
422 { partPicture = "Poney/Haflinger/GettyImages-546441489-3087a0a3f3a0486f96e7e6d7eb0b6bc1.avif"
423 , partPictureCSS = HTML.cssBlockObjectFitCover
424 , partDescription = "Haflinger Pony"
425 , partLangue = LangueFrançais
426 , partText = "Il existe environ 159 races de poneys"
427 }
428 , typeDefault
429 { partPicture = "Poney/Dartmoor/GettyImages-149824058-ee7fd8a5e9984f5a9dc73c5916a238aa.avif"
430 , partPictureCSS = HTML.cssBlockObjectFitCover
431 , partDescription = "Dartmoor Pony"
432 , partLangue = LangueAnglais
433 , partText = "There are approximately 159 pony breeds"
434 }
435 , typeDefault
436 { partPicture = "Poney/Connemara/eaa17d54a2978f5962edc405f0beabb7.avif"
437 , partPictureCSS = HTML.cssBlockObjectFitCover
438 , partDescription = "Connemara Pony"
439 , partLangue = LangueMandarin
440 , partText = "有 大约 159 个 小马 品种"
441 }
442 ]
443 }
444 & pageLandscape
445 , "poniesRaces3"
446 := page
447 { pageParts =
448 [ typeDefault
449 { partPicture = "Poney/AmericanQuarter/American-Quarter-Horse-stallion-1024x614.avif"
450 , partPictureCSS = HTML.cssBlockObjectFitCover
451 , partDescription = "American Quarter Pony"
452 , partLangue = LangueFrançais
453 , partText = "Il existe environ 159 races de poneys"
454 }
455 , typeDefault
456 { partPicture = "Poney/Welsh/GettyImages-1318833798-1024x768.avif"
457 , partPictureCSS = HTML.cssBlockObjectFitCover
458 , partDescription = "Welsh Pony"
459 , partLangue = LangueAnglais
460 , partText = "There are approximately 159 pony breeds"
461 }
462 , typeDefault
463 { partPicture = "Poney/PonyOfTheAmericas/GettyImages-519556294-1024x683.avif"
464 , partPictureCSS = HTML.cssBlockObjectFitCover
465 , partDescription = "Pony of the Americas"
466 , partLangue = LangueMandarin
467 , partText = "有 大约 159 个 小马 品种"
468 }
469 ]
470 }
471 & pageLandscape
472 , "poniesRaces4"
473 := page
474 { pageParts =
475 [ typeDefault
476 { partPicture = "Poney/Haflinger/041221-haflinger-3.avif"
477 , partPictureCSS = HTML.cssBlockObjectFitCover
478 , partDescription = "Haflinger Pony"
479 , partLangue = LangueFrançais
480 , partText = "Il existe environ 159 races de poneys"
481 }
482 , typeDefault
483 { partPicture = "Poney/Eriskay/shutterstock-2214350479-huge-licensed-scaled.avif"
484 , partPictureCSS = HTML.cssBlockObjectFitCover
485 , partDescription = "Eriskay Pony"
486 , partLangue = LangueAnglais
487 , partText = "There are approximately 159 pony breeds"
488 }
489 , typeDefault
490 { partPicture = "Poney/BritishRiding/GettyImages-175411286-1024x683.avif"
491 , partPictureCSS = HTML.cssBlockObjectFitCover
492 , partDescription = "British Riding Pony"
493 , partLangue = LangueMandarin
494 , partText = "有 大约 159 个 小马 品种"
495 }
496 ]
497 }
498 & pageLandscape
499 , "Culicoides"
500 := page
501 { pageParts =
502 [ typeDefault
503 { partPicture = "Culicoides/Blood-Feeding-Culicoides-Midges.avif"
504 , partPictureCSS = HTML.cssBlockObjectFitCover
505 , partLangue = LangueFrançais
506 , partText = "Les moucherons culicoides sont des vampires infectieuses"
507 }
508 , typeDefault
509 { partPicture = "Culicoides/Mosquito_(Ochlerotatus_annulipes)_and_Midge_(Culicoides_impunctatus)_biting_human_(me).avif"
510 , partPictureCSS = HTML.cssBlockObjectFitCover
511 , partLangue = LangueAnglais
512 , partText = "Culicoides midges are infectious vampires"
513 }
514 , typeDefault
515 { partPicture = "Culicoides/CSIRO_ScienceImage_1791_SEM_of_a_biting_midge_Culicoides_brevitarsis.avif"
516 , partPictureCSS = HTML.cssBlockObjectFitCover
517 , partLangue = LangueMandarin
518 , partText = "库蠓属 具有 传染性 的 吸血鬼"
519 }
520 ]
521 }
522 & pageLandscape
523 , "Fraise"
524 := page
525 { pageParts =
526 [ typeDefault
527 { partPicture = "Fraise/96caabc77f79887c4bbcb2383092707b.avif"
528 , partLangue = LangueFrançais
529 , partText = "Les fruits de la fraise sont les akènes"
530 }
531 , typeDefault
532 { partPicture = "Fraise/OIP.avif"
533 , partPictureCSS = HTML.cssBlockObjectFitCover
534 , partLangue = LangueAnglais
535 , partText = "Strawberry's fruits are the achenes"
536 }
537 , typeDefault
538 { partPicture = "Fraise/Coupe_d'une_fraise_dont_les_akènes_ont_germés.avif"
539 , partLangue = LangueMandarin
540 , partText = "草莓 的 果实 是 瘦果"
541 }
542 ]
543 }
544 & pageLandscape
545 , "poupéeArielle"
546 := page
547 { pageParts =
548 [ typeDefault
549 { partPicture = "ArielleLaPetiteSirène/3aff97d2a3c36b307c12e7ea36e2000b.avif"
550 , partLangue = LangueFrançais
551 , partText = "Arielle la poupée et Merlin le garçon"
552 }
553 , typeDefault
554 { partPicture = "ArielleLaPetiteSirène/halle-bailey-as-ariel-in-the-little-mermaid-zk-1280x2120.small.avif"
555 , partLangue = LangueAnglais
556 , partText = "Ariel the doll and Merlin the boy"
557 }
558 , typeDefault
559 { partPicture = "Poupée/IMG_20250613_111606.avif"
560 , partLangue = LangueMandarin
561 , partText = "娃娃 Arielle 和 男孩 梅林"
562 }
563 ]
564 }
565 & pageLandscape
566 , "poupéeBella"
567 := page
568 { pageParts =
569 [ typeDefault
570 { partPicture = "LaBelleEtLaBête/batbjpg-fe2293_1280w.avif"
571 , partLangue = LangueFrançais
572 , partText = "Bella la poupée et Maya la fille"
573 }
574 , typeDefault
575 { partPicture = "LaBelleEtLaBête/disney-live-action-02.avif"
576 , partPictureCSS = HTML.cssBlockObjectFitCover
577 , partLangue = LangueAnglais
578 , partText = "Bella the doll and Maya the girl"
579 }
580 , typeDefault
581 { partPicture = "Poupée/IMG_20250613_111730.avif"
582 , partLangue = LangueMandarin
583 , partText = "娃娃 Bella 和 女孩 马雅" -- 玛雅
584 }
585 ]
586 }
587 & pagePortrait
588 , "Mûre"
589 := page
590 { pageParts =
591 [ typeDefault
592 { partPicture = "Mûre/Bee-Feeding-on-Blackberry-Blossom.avif"
593 , partPictureCSS = HTML.cssBlockObjectFitCover
594 , partLangue = LangueFrançais
595 , partText = "Les fruits de la mûre sont des drupéoles"
596 }
597 , typeDefault
598 { partPicture = "Mûre/blackberry-anatomy.avif"
599 , partLangue = LangueAnglais
600 , partText = "Blackberry's fruits are drupelets"
601 }
602 , typeDefault
603 { partPicture = "Mûre/berryblack.avif"
604 , partPictureCSS = HTML.cssBlockObjectFitCover
605 , partLangue = LangueMandarin
606 , partText = "黑莓 的 果实 是 小 核果"
607 }
608 ]
609 }
610 & pageLandscape
611 , "Framboise"
612 := page
613 { pageParts =
614 [ typeDefault
615 { partPicture = "Framboise/ghows-SR-6c5aadd8-13b2-7679-e053-0100007f79b5-ad44228b.avif"
616 , partPictureCSS =
617 HTML.cssBlockObjectFitCover
618 <> ["object-position" := "left center"]
619 , partLangue = LangueFrançais
620 , partText = "Le réceptacle de la framboise reste accroché au buisson"
621 }
622 , typeDefault
623 { partPicture = "Framboise/framboise-schema-fr.avif"
624 , partLangue = LangueAnglais
625 , partText = "Raspberry's receptacle clings to the bush"
626 }
627 , typeDefault
628 { partPicture = "Framboise/OIP.avif"
629 , partPictureCSS =
630 HTML.cssBlockObjectFitCover
631 <> ["object-position" := "right bottom"]
632 , partLangue = LangueMandarin
633 , partText = "山莓 的 花托 紧贴 灌木丛"
634 }
635 ]
636 }
637 & pageLandscape
638 , "Mustang"
639 := page
640 { pageParts =
641 [ typeDefault
642 { partPicture = "Cheval/Mustang/2.avif"
643 , partPictureCSS =
644 HTML.cssBlockObjectFitCover
645 <> ["object-position" := "left center"]
646 , partLangue = LangueFrançais
647 , partText = "La plupart des chevaux mustangs sont sauvages"
648 }
649 , typeDefault
650 { partPicture = "Cheval/Mustang/10.avif"
651 , partPictureCSS =
652 HTML.cssBlockObjectFitCover
653 <> ["object-position" := "left center"]
654 , partLangue = LangueAnglais
655 , partText = "Most mustang horses are wild"
656 }
657 , typeDefault
658 { partPicture = "Cheval/Mustang/6.avif"
659 , partPictureCSS =
660 HTML.cssBlockObjectFitCover
661 , partLangue = LangueMandarin
662 , partText = "大多数 美洲野马 是 野马"
663 }
664 ]
665 }
666 & pageLandscape
667 , "TortueDeMerMigration"
668 := page
669 { pageParts =
670 [ typeDefault
671 { partPicture = "Tortue/tumblr_mxnwydKTfm1qm9k25o1_1280.avif"
672 , partPictureCSS =
673 HTML.cssBlockObjectFitCover
674 <> ["object-position" := "left center"]
675 , partLangue = LangueFrançais
676 , partText = "Les tortues de mer peuvent traverser un océan à la nage"
677 }
678 , typeDefault
679 { partPicture = "Tortue/SWOT_XV_Global_Loggerhead_V3_20200220.crop.avif"
680 , partPictureCSS =
681 [ "object-fit" := "contain"
682 , "object-position" := "center center"
683 ]
684 , partLangue = LangueAnglais
685 , partText = "Sea turtles can swim across an ocean"
686 }
687 , typeDefault
688 { partPicture = "Tortue/sea-turtle8.avif"
689 , partPictureCSS = HTML.cssBlockObjectFitCover
690 , partLangue = LangueMandarin
691 , partText = "海龟 可以 游泳 横穿 海洋"
692 }
693 ]
694 }
695 & pageLandscape
696 , "LoupsHurlent"
697 := page
698 { pageParts =
699 [ typeDefault
700 { partPicture = "Loup/197922.avif"
701 , partPictureCSS =
702 HTML.cssBlockObjectFitCover
703 , partLangue = LangueFrançais
704 , partText = "Les loups hurlent pour se rassembler ou pour alerter"
705 }
706 , typeDefault
707 { partPicture = "Loup/portrait-of-arctic-wolf-free-photo.avif"
708 , partPictureCSS =
709 HTML.cssBlockObjectFitCover
710 , partLangue = LangueAnglais
711 , partText = "Wolves howl to reassemble or to alert"
712 }
713 , typeDefault
714 { partPicture = "Loup/R.avif"
715 , partPictureCSS =
716 HTML.cssBlockObjectFitCover
717 , partLangue = LangueMandarin
718 , partText = "狼 嚎 以 团结 在一起 或 警告"
719 }
720 ]
721 }
722 & pageLandscape
723 , "PapillonCitron"
724 := page
725 { pageParts =
726 [ typeDefault
727 { partPicture = "Papillon/Brimstone/t0109e2365f058fa5bb.avif"
728 , partPictureCSS =
729 [ "object-fit" := "cover"
730 , "object-position" := "left center"
731 ]
732 , partLangue = LangueFrançais
733 , partText = "Le papillon citron peut survivre à l'hiver"
734 }
735 , typeDefault
736 { partPicture = "Papillon/Brimstone/brimstone_life_cycle_l.avif"
737 , partPictureCSS =
738 [ "object-fit" := "contain"
739 ]
740 , partLangue = LangueAnglais
741 , partText = "The brimstone butterfly can survive the winter"
742 }
743 , typeDefault
744 { partPicture = "Papillon/Brimstone/brimstone_characteristics_l.avif"
745 , partPictureCSS =
746 [ "object-fit" := "contain"
747 ]
748 , partLangue = LangueMandarin
749 , partText = "钩粉蝶 可以 度过 冬天"
750 }
751 ]
752 }
753 & pageLandscape
754 , "Seasons"
755 := page
756 { pageParts =
757 [ typeDefault
758 { partPicture = "Seasons/canadian-seasons-mircea-costina.jpg"
759 , partPictureCSS =
760 [ "object-fit" := "cover"
761 , "object-position" := "center center"
762 ]
763 , partLangue = LangueFrançais
764 , partText = "L'été, le soleil chauffe longtemps et frontalement"
765 }
766 , typeDefault
767 { partPicture = "Seasons/summer.avif"
768 , partPictureCSS =
769 [ "object-fit" := "cover"
770 ]
771 , partLangue = LangueAnglais
772 , partText = "In summer, sun's warming is longest and most frontal"
773 }
774 , typeDefault
775 { partPicture = "Seasons/winter.avif"
776 , partPictureCSS =
777 [ "object-fit" := "cover"
778 ]
779 , partLangue = LangueMandarin
780 , partText = "夏季, 太阳 的 加热 最 长 且 最 正面"
781 }
782 ]
783 }
784 & pageLandscape
785 , "Christmas"
786 := page
787 { pageParts =
788 [ typeDefault
789 { partPicture = "Christmas/Cici-Fang-Christmas-Consumerism-1-pdf.avif"
790 , partPictureCSS =
791 [ "object-fit" := "cover"
792 --, "object-position" := "center center"
793 ]
794 , partLangue = LangueFrançais
795 , partText = "Noël est une fête de la consommation et de la fantaisie"
796 }
797 , typeDefault
798 { partPicture = "Christmas/l_etrange_noel_de_monsieur_jack.avif"
799 , partPictureCSS =
800 [ "object-fit" := "cover"
801 ]
802 , partLangue = LangueAnglais
803 , partText = "Christmas celebrates consumption and fantasy"
804 }
805 , typeDefault
806 { partPicture = "Christmas/Olafs.Frozen.Adventure.2017.720p.BluRay.x264.AAC-[YTS.MX].mp4.00-09-29-527.avif"
807 , partPictureCSS =
808 [ "object-fit" := "cover"
809 , "object-position" := "-1.75cm center"
810 ]
811 , partLangue = LangueMandarin
812 , partText = "圣诞节 庆祝会 消费量 和 幻想"
813 }
814 ]
815 }
816 & pageLandscape
817 , "LoupsEtCorbeaux"
818 := page
819 { pageParts =
820 [ typeDefault
821 { partPicture = "Loup/wolf-raven.avif"
822 , partPictureCSS =
823 HTML.cssBlockObjectFitCover
824 , partLangue = LangueFrançais
825 , partText = [Right "Loups et Corbeaux jouent et chassent souvent ensemble"]
826 }
827 , typeDefault
828 { partPicture = "Loup/Screen Shot 2013-08-19 at 10.38.26 PM.avif"
829 , partPictureCSS =
830 HTML.cssBlockObjectFitCover
831 , partLangue = LangueAnglais
832 , partText = [Right "Wolves and ravens often play and hunt together"]
833 }
834 , typeDefault
835 { partPicture = "Loup/NPS_WolfMagpiesRavens_NOV16_HerbertNeal.avif"
836 , partPictureCSS =
837 HTML.cssBlockObjectFitCover
838 , partLangue = LangueMandarin
839 , partText = [Right "狼 和 乌鸦 经常 玩耍 和 狩猎 一起"]
840 }
841 ]
842 }
843 & pageLandscape
844 , "Crocodile"
845 := page
846 { pageParts =
847 [ typeDefault
848 { partPicture = "Crocodile/1562781.avif"
849 , partPictureCSS =
850 HTML.cssBlockObjectFitCover
851 , partLangue = LangueFrançais
852 , partText = "Les crocodiles versent des larmes en mangeant"
853 }
854 , typeDefault
855 { partPicture = "Crocodile/Morelet's_Crocodile_(Crocodylus_moreletii)_big_male_attracting_Julia_Butterflies_(Dryas_iulia)_-_Rio_Usumacintla_Chiapas_2020.avif"
856 , partPictureCSS =
857 HTML.cssBlockObjectFitCover
858 , partLangue = LangueAnglais
859 , partText = "Crocodiles shed tears when eating"
860 }
861 , typeDefault
862 { partPicture = "Crocodile/sn-crocodiletears.avif"
863 , partPictureCSS =
864 HTML.cssBlockObjectFitCover
865 , partLangue = LangueMandarin
866 , partText = "鳄鱼 流泪 吃 时"
867 }
868 ]
869 }
870 & pageLandscape
871 , "FourmiIngénieurs"
872 -- https://www.nationalgeographic.com/animals/article/european-red-wood-ants-impact
873 := page
874 { pageParts =
875 [ typeDefault
876 { partPicture = "Fourmi/Ingo_Arndt_MM10190_045-1.avif"
877 , partPictureCSS =
878 HTML.cssBlockObjectFitCover
879 , partLangue = LangueFrançais
880 , partText = "Les fourmis rousses des bois sont des ingénieures"
881 }
882 , typeDefault
883 { partPicture = "Fourmi/STOCKPKG_MM10190_230605_206.avif"
884 , partPictureCSS =
885 HTML.cssBlockObjectFitCover
886 , partLangue = LangueAnglais
887 , partText = "Red wood ants are forest engineers"
888 }
889 , typeDefault
890 { partPicture = "Fourmi/STOCKPKG_MM10190_230515_192.avif"
891 , partPictureCSS =
892 HTML.cssBlockObjectFitCover
893 , partLangue = LangueMandarin
894 -- 紅褐山蟻
895 , partText = "红木 蚂蚁 是 森林 工程师"
896 }
897 ]
898 }
899 & pageLandscape
900 , "HayBales"
901 := page
902 { pageParts =
903 [ typeDefault
904 { partPicture = "HayBales/30-33-Lead-Image.avif"
905 , partPictureCSS =
906 [ "object-fit" := "cover"
907 ]
908 , partLangue = LangueFrançais
909 , partText = "Les balles de foin sont plastifiées pour fermenter"
910 }
911 , typeDefault
912 { partPicture = "HayBales/_DSC3737_0.avif"
913 , partPictureCSS =
914 [ "object-fit" := "cover"
915 , "object-position" := "-0.7cm center"
916 ]
917 , partLangue = LangueAnglais
918 , partText = "Hay bales are wrapped in plastic to ferment"
919 }
920 , typeDefault
921 { partPicture = "HayBales/Figure-2-200-Heifers-feeding-from-multiple-bags.avif"
922 , partPictureCSS =
923 [ "object-fit" := "cover"
924 ]
925 , partLangue = LangueMandarin
926 , partText = "干草 包裹 塑料 以便 发酵"
927 }
928 ]
929 }
930 & pageLandscape
931 , "StarTrails1"
932 := page
933 { pageParts =
934 [ typeDefault
935 { partPicture = "Étoiles/SavudrijaSTARTRAILS_Nadj1024.avif"
936 , partPictureCSS =
937 [ "object-fit" := "cover"
938 , "object-position" := "left top"
939 ]
940 , partLangue = LangueFrançais
941 , partText = "La Terre tourne chaque jour autour d'un axe stable"
942 }
943 , typeDefault
944 { partPicture = "Étoiles/trails-geminids.avif"
945 , partPictureCSS =
946 [ "object-fit" := "cover"
947 , "object-position" := "left top"
948 ]
949 , partLangue = LangueAnglais
950 , partText = "Earth spins each day around a stable axis"
951 }
952 , typeDefault
953 { partPicture = "Étoiles/Earth_precession.svg.avif"
954 , partPictureCSS =
955 [ "object-fit" := "contain"
956 , "object-position" := "right center"
957 ]
958 , partLangue = LangueMandarin
959 , partText = "地球 围绕 每天 稳定 轴旋转"
960 }
961 ]
962 }
963 & pageLandscape
964 , "StarTrails2"
965 := page
966 { pageParts =
967 [ typeDefault
968 { partPicture = "Étoiles/Iotw2246a_-_Beginning_to_End_of_a_Total_Lunar_Eclipse.avif"
969 , partPictureCSS =
970 [ "object-fit" := "cover"
971 , "object-position" := "left top"
972 ]
973 , partLangue = LangueFrançais
974 , partText = "La Terre tourne chaque jour autour d'un axe stable"
975 }
976 , typeDefault
977 { partPicture = "Étoiles/Star-trail-of-planets1067.avif"
978 , partPictureCSS =
979 [ "object-fit" := "cover"
980 , "object-position" := "left top"
981 ]
982 , partLangue = LangueAnglais
983 , partText = "Earth spins each day around a stable axis"
984 }
985 , typeDefault
986 { partPicture = "Étoiles/shows-precession-of-earth-which-cause-repetitions-of-climate-patterns-for-a-period-of.avif"
987 , partPictureCSS =
988 [ "object-fit" := "contain"
989 , "object-position" := "center center"
990 ]
991 , partLangue = LangueMandarin
992 -- 旋转
993 , partText = "地球 围绕 每天 稳定 轴旋转"
994 }
995 ]
996 }
997 & pageLandscape
998 , "WateringCan"
999 := page
1000 { pageParts =
1001 [ typeDefault
1002 { partPicture = "Arrosoir/OIP.avif"
1003 , partPictureCSS =
1004 [ "object-fit" := "cover"
1005 ]
1006 , partLangue = LangueFrançais
1007 , partText = "Utiliser un arrosoir est une corvée technique"
1008 }
1009 , typeDefault
1010 { partPicture = "Arrosoir/sub-buzz-1301-1687548112-1.avif"
1011 , partPictureCSS =
1012 [ "object-fit" := "contain"
1013 ]
1014 , partLangue = LangueAnglais
1015 , partText = "Using a watering can is a technical chore"
1016 }
1017 , typeDefault
1018 { partPicture = "Arrosoir/Watering-seedlings-with-a-pop-bottle-watering-can-1024x768.avif"
1019 , partPictureCSS =
1020 [ "object-fit" := "cover"
1021 ]
1022 , partLangue = LangueMandarin
1023 , partText = "使用 浇水 壶 是 技术 例行 工作"
1024 }
1025 ]
1026 }
1027 & pageLandscape
1028 , "Fireworks1"
1029 := page
1030 { pageParts =
1031 [ typeDefault
1032 { partPicture = "Fireworks/brian_titone_53841_1_262503.avif"
1033 , partPictureCSS =
1034 [ "object-fit" := "cover"
1035 , "object-position" := "center top"
1036 ]
1037 , partLangue = LangueFrançais
1038 , partText = "Un feu d'artifice pollue l'air, l'eau et le sol"
1039 }
1040 , typeDefault
1041 { partPicture = "Fireworks/The+Hidden+Science+of+Fireworks+-+Veritasium.avif"
1042 , partPictureCSS =
1043 [ "object-fit" := "contain"
1044 , "object-position" := "center center"
1045 ]
1046 , partLangue = LangueAnglais
1047 , partText = "Fireworks are bombs polluting the air, water and soil"
1048 }
1049 , typeDefault
1050 { partPicture = "Fireworks/2023-07-07 - The Hidden Science of Fireworks.lfkjm2YRG-Q.398+251.webm.00-20-58-624.avif"
1051 , partPictureCSS =
1052 [ "object-fit" := "cover"
1053 , "object-position" := "center center"
1054 ]
1055 , partLangue = LangueMandarin
1056 , partText = "烟花 是 炸弹 污染 空气、水 和 土壤"
1057 }
1058 ]
1059 }
1060 & pageLandscape
1061 , "Renard"
1062 := pages
1063 { pagesList =
1064 [ page
1065 { pageParts =
1066 [ typeDefault
1067 { partPicture = "Renard/ArticFox/200512612-001-56a006345f9b58eba4ae8b10.avif"
1068 , partPictureCSS =
1069 [ "object-fit" := "cover"
1070 ]
1071 , partDescription = "Artic Fox"
1072 , partLangue = LangueFrançais
1073 , partText = [Right "Il y a 12 espèces et 45 sous-espèces de renards"]
1074 }
1075 , typeDefault
1076 { partPicture = "Renard/SwiftFox/shutterstock-46600522.avif"
1077 , partDescription = "Swift Fox"
1078 , partPictureCSS = [ "object-fit" := "cover" ]
1079 , partLangue = LangueAnglais
1080 , partText = [Right "There are at least 12 species and 45 subspecies of foxes"]
1081 }
1082 , typeDefault
1083 { partPicture = "Renard/RedFox/v2.avif"
1084 , partDescription = "Red Fox"
1085 , partPictureCSS =
1086 [ "object-fit" := "cover"
1087 ]
1088 , partLangue = LangueMandarin
1089 , partText = [Right "有 至少 12 种 和 45 亚种 狐狸"]
1090 }
1091 ]
1092 }
1093 & pageLandscape
1094 , page
1095 { pageParts =
1096 [ typeDefault
1097 { partPicture = "Renard/CorsacFox/029f945789fcc419f8f637a93917278b.avif"
1098 , partPictureCSS =
1099 [ "object-fit" := "cover"
1100 , "object-position" := "0 -0.1cm"
1101 ]
1102 , partDescription = "Corsac Fox"
1103 , partLangue = LangueFrançais
1104 , partText = [Right "Il y a 12 espèces et 45 sous-espèces de renards"]
1105 }
1106 , typeDefault
1107 { partPicture = "Renard/BlandfordFox/2-blanfords-fox-vulpes-cana-eyal-bartov.avif"
1108 , partPictureCSS =
1109 [ "object-fit" := "cover"
1110 ]
1111 , partDescription = "Blandford's Fox"
1112 , partLangue = LangueAnglais
1113 , partText = [Right "There are at least 12 species and 45 subspecies of foxes"]
1114 }
1115 , typeDefault
1116 { partPicture = "Renard/CapeFox/shutterstock-220059658.avif"
1117 , partPictureCSS =
1118 [ "object-fit" := "cover"
1119 ]
1120 , partDescription = "Cape Fox"
1121 , partLangue = LangueMandarin
1122 , partText = [Right "有 至少 12 种 和 45 亚种 狐狸"]
1123 }
1124 ]
1125 }
1126 & pageLandscape
1127 ]
1128 }
1129 , "Fireworks2"
1130 := page
1131 { pageParts =
1132 [ typeDefault
1133 { partPicture = "Fireworks/skyrocket-collage-background-571127103-8430996ece5d423da30046df82620b4f.avif"
1134 , partPictureCSS =
1135 [ "object-fit" := "cover"
1136 , "object-position" := "center top"
1137 ]
1138 , partLangue = LangueFrançais
1139 , partText = [Right "Un feu d'artifice pollue l'air, l'eau et le sol"]
1140 }
1141 , typeDefault
1142 { partPicture = "Fireworks/The+Hidden+Science+of+Fireworks+-+Veritasium.avif"
1143 , partPictureCSS =
1144 [ "object-fit" := "contain"
1145 , "object-position" := "center center"
1146 ]
1147 , partLangue = LangueAnglais
1148 , partText = [Right "Fireworks are bombs polluting", Left (" the ", LexemePron "ðiː" []), Right "air, water and soil"]
1149 }
1150 , typeDefault
1151 { partPicture = "Fireworks/2023-07-07 - The Hidden Science of Fireworks.lfkjm2YRG-Q.398+251.webm.00-21-12-705.avif"
1152 , partPictureCSS =
1153 [ "object-fit" := "cover"
1154 , "object-position" := "center center"
1155 ]
1156 , partLangue = LangueMandarin
1157 , partText = [Right "烟花 是 炸弹 污染 空气、水 和 土壤"]
1158 }
1159 ]
1160 }
1161 & pageLandscape
1162 , "Arbre1"
1163 := page
1164 { pageParts =
1165 [ typeDefault
1166 { partPicture = "Arbre/R3.avif"
1167 , partPictureCSS =
1168 [ "object-fit" := "cover"
1169 , "object-position" := "center bottom"
1170 ]
1171 , partLangue = LangueFrançais
1172 , partText = [Right "Un pommier contre-attaque en changeant d'odeur"]
1173 }
1174 , typeDefault
1175 { partPicture = "Arbre/_14250.avif"
1176 , partPictureCSS =
1177 [ "object-fit" := "cover"
1178 , "object-position" := "center center"
1179 ]
1180 , partLangue = LangueAnglais
1181 , partText = [Right "An apple tree strikes back by changing its smell"]
1182 }
1183 , typeDefault
1184 { partPicture = "Arbre/5485248248_7e7244f769_b.crop.avif"
1185 , partPictureCSS =
1186 [ "object-fit" := "cover"
1187 , "object-position" := "left center"
1188 ]
1189 , partLangue = LangueMandarin
1190 , partText = [Right "苹果 树 变 味 为了 反击"]
1191 }
1192 ]
1193 }
1194 & pageLandscape
1195 , "Pression"
1196 := page
1197 { pageParts =
1198 [ typeDefault
1199 { partPicture = ""
1200 , partPictureCSS =
1201 [ "object-fit" := "cover"
1202 , "object-position" := "center bottom"
1203 ]
1204 , partLangue = LangueFrançais
1205 , partText = [Right ""]
1206 }
1207 , typeDefault
1208 { partPicture = ""
1209 , partPictureCSS =
1210 [ "object-fit" := "cover"
1211 , "object-position" := "center center"
1212 ]
1213 , partLangue = LangueAnglais
1214 , partText = [Right ""]
1215 }
1216 , typeDefault
1217 { partPicture = ""
1218 , partPictureCSS =
1219 [ "object-fit" := "cover"
1220 , "object-position" := "left center"
1221 ]
1222 , partLangue = LangueMandarin
1223 , partText = [Right ""]
1224 }
1225 ]
1226 }
1227 & pageLandscape
1228 "MistyMountains" :=
1229 pages
1230 { pagesList =
1231 [ page
1232 { pageParts =
1233 [ typeDefault
1234 { partPicture = "LOTR/TheHobbit/bilbo-baggins-dwarves-gandalf.avif"
1235 , partPictureCSS =
1236 [ "object-fit" := "cover"
1237 , "object-position" := "center -5.3cm"
1238 ]
1239 , partLangue = LangueAnglais
1240 , partText = [Right "Far over the Misty Mountains cold"]
1241 }
1242 , typeDefault
1243 { partPicture = "LOTR/TheHobbit/Una_tertulia_inesperada_3.avif"
1244 , partPictureCSS =
1245 [ "object-fit" := "cover"
1246 , "object-position" := "center -0.4cm"
1247 ]
1248 , partLangue = LangueAnglais
1249 , partText = [Right "To dungeons deep and caverns old"]
1250 }
1251 , typeDefault
1252 { partPicture = "LOTR/TheHobbit/bilbo-baggins11.avif"
1253 , partPictureCSS =
1254 [ "object-fit" := "cover"
1255 , "object-position" := "center center"
1256 ]
1257 , partLangue = LangueAnglais
1258 , partText = [Right "We must away, ere break of day"]
1259 }
1260 , typeDefault
1261 { partPicture = "LOTR/TheHobbit/b8e91bf011890c7602faa4d6c2e00275.avif"
1262 , partPictureCSS =
1263 [ "object-fit" := "cover"
1264 , "object-position" := "center center"
1265 ]
1266 , partLangue = LangueAnglais
1267 , partText = [Right "To seek our pale enchanted gold"]
1268 }
1269 ]
1270 }
1271 & pageLandscape
1272 ]
1273 }
1274 -}