en.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. import formatTimeToString from '../utils/formatTimeToString'
  2. const general = {
  3. timeFormats: {
  4. days: {
  5. 1: () => `day`,
  6. 2: () => `days`,
  7. },
  8. hours: {
  9. 1: () => `hour`,
  10. 2: () => `hours`,
  11. },
  12. minutes: {
  13. 1: () => `minute`,
  14. 2: () => `minutes`,
  15. },
  16. seconds: {
  17. 1: () => `second`,
  18. 2: () => `seconds`,
  19. },
  20. },
  21. dateFormats: {
  22. months: {
  23. [`01`]: () => `January`,
  24. [`02`]: () => `February`,
  25. [`03`]: () => `March`,
  26. [`04`]: () => `April`,
  27. [`05`]: () => `May`,
  28. [`06`]: () => `June`,
  29. [`07`]: () => `July`,
  30. [`08`]: () => `August`,
  31. [`09`]: () => `September`,
  32. [`10`]: () => `October`,
  33. [`11`]: () => `November`,
  34. [`12`]: () => `December`,
  35. }
  36. },
  37. functionWords: {
  38. and: () => `and`,
  39. },
  40. errors: {
  41. turnstile: {
  42. unavailable: () => `cannot connect to Turnstile. please try again.`,
  43. noToken: () => `Turnstile token was not provided. please try again.`,
  44. invalidResponse: () => `invalid Turnstile response. please try again.`,
  45. keyUsedOrExpired: () => `Turnstile key already used or expired. please try again.`
  46. },
  47. },
  48. adjectives: () => [
  49. "adorable", "adventurous", "agreeable", "alert", "alive", "amused",
  50. "angry", "annoyed", "annoying", "anxious", "arrogant", "ashamed",
  51. "attractive", "average", "awful", "bad", "beautiful", "better",
  52. "bewildered", "black", "blue", "blue-eyed", "blushing", "bored",
  53. "brainy", "brave", "breakable", "bright", "busy", "calm", "careful",
  54. "cautious", "charming", "cheerful", "clean", "clear", "clever",
  55. "cloudy", "clumsy", "colorful", "combative", "comfortable", "concerned",
  56. "condemned", "confused", "cooperative", "courageous", "crazy", "creepy",
  57. "crowded", "curious", "cute", "dangerous", "dark", "dazzling",
  58. "deadpan", "delightful", "difficult", "distinct", "disturbed", "dizzy",
  59. "doubtful", "drab", "dull", "eager", "easy", "elated", "elegant",
  60. "embarrassed", "enchanting", "encouraging", "energetic", "enthusiastic",
  61. "envious", "excited", "expensive", "exuberant", "fair", "faithful",
  62. "famous", "fancy", "fantastic", "fast", "filthy", "fine", "foolish",
  63. "fragile", "frail", "frantic", "friendly", "frightened", "funny",
  64. "gentle", "gifted", "glamorous", "gleaming", "glorious", "good",
  65. "gorgeous", "graceful", "grieved", "grotesque", "grumpy", "handsome",
  66. "happy", "healthy", "helpful", "helpless", "hilarious", "homely",
  67. "horrible", "hungry", "hurt", "ill", "important", "impossible",
  68. "inexpensive", "innocent", "inquisitive", "intelligent", "interested",
  69. "itchy", "jealous", "jittery", "jolly", "joyous", "kind", "lazy",
  70. "light", "lively", "lonely", "long", "lovely", "lucky", "magnificent",
  71. "misty", "modern", "motionless", "muddy", "mushy", "mysterious",
  72. "nasty", "naughty", "nervous", "nice", "nutty", "obedient", "obnoxious",
  73. "odd", "open", "outrageous", "outstanding", "panicky", "perfect",
  74. "plain", "pleasant", "poised", "polite", "powerful", "precious",
  75. "prickly", "proud", "puzzled", "quaint", "real", "relieved", "repulsive",
  76. "rich", "scary", "selfish", "shiny", "shy", "silly", "sleepy", "smiling",
  77. "smoggy", "sore", "sparkling", "splendid", "spotless", "stormy",
  78. "strange", "stupid", "successful", "super", "talented", "tame", "tender",
  79. "tense", "terrible", "thankful", "thoughtful", "thoughtless", "tired",
  80. "tough", "troubled", "uninterested", "unsightly", "unusual", "upset",
  81. "uptight", "vast", "victorious", "vivacious", "wandering", "weary",
  82. "wicked", "wide-eyed", "wild", "witty", "worried", "worrisome", "wrong",
  83. "zany", "zealous"
  84. ],
  85. nouns: () => [
  86. "actor", "airplane", "airport", "alarm", "alligator", "alphabet",
  87. "ambulance", "animal", "answer", "ant", "apple", "appliance",
  88. "apron", "arch", "arm", "army", "arrow", "ashtray", "asteroid",
  89. "author", "avocado", "baby", "back", "balloon", "banana", "band",
  90. "bank", "barber", "base", "basket", "basketball", "bat", "bath",
  91. "beach", "bear", "beard", "bed", "bee", "beef", "beetle", "bell",
  92. "belt", "bench", "beret", "berry", "bicycle", "bike", "bird",
  93. "birthday", "bite", "block", "boat", "book", "boot", "border",
  94. "bottle", "boundary", "box", "boy", "brake", "bread", "bridge",
  95. "bronco", "brother", "brush", "bubble", "bucket", "building",
  96. "bulb", "bunny", "bus", "butterfly", "button", "cabbage", "cactus",
  97. "cake", "calculator", "calendar", "camel", "camera", "camp", "candle",
  98. "canoe", "canvas", "cap", "caption", "car", "card", "carpenter",
  99. "carriage", "carrot", "cart", "castle", "cat", "cattle", "celery",
  100. "cello", "cement", "chain", "chair", "chalk", "channel", "cheese",
  101. "cherry", "chess", "chicken", "children", "chimpanzee", "chin",
  102. "church", "city", "clam", "clock", "cloth", "cloud", "clover",
  103. "club", "coach", "coal", "coast", "coat", "cobweb", "coil", "collar",
  104. "color", "comet", "compass", "computer", "conditioner", "cord",
  105. "cork", "corn", "couch", "country", "cow", "crab", "crack", "crate",
  106. "crayon", "cricket", "crocodile", "crow", "crown", "crust", "cup",
  107. "curtain", "cushion", "cylinder", "dog", "donkey", "door", "dragon",
  108. "drain", "drawer", "dress", "drop", "duck", "dust", "eagle", "ear",
  109. "earth", "egg", "eggplant", "elbow", "elephant", "engine", "eye",
  110. "face", "factory", "fairy", "family", "fan", "farm", "feather",
  111. "feast", "fence", "field", "flag", "flower", "flute", "fly", "fog",
  112. "forest", "fork", "fountain", "frog", "fruit", "furniture", "garage",
  113. "garden", "gate", "gemstone", "ghost", "giraffe", "glass", "glove",
  114. "goat", "gold", "goose", "gorilla", "grape", "grass", "guitar",
  115. "hair", "hall", "hat", "helicopter", "helmet", "honey", "horn",
  116. "horse", "hospital", "house", "island", "jacket", "jar", "jellyfish",
  117. "kangaroo", "kettle", "key", "keyboard", "king", "kitchen", "kite",
  118. "kitten", "lamp", "leaf", "library", "lighthouse", "lion", "lizard",
  119. "lock", "lunch", "magnet", "map", "mask", "melon", "monkey", "moon",
  120. "mountain", "mouse", "mouth", "nail", "necklace", "needle", "nest",
  121. "nose", "notebook", "ocean", "orange", "owl", "paint", "pants",
  122. "paper", "parrot", "pencil", "piano", "pillow", "pizza", "planet",
  123. "plant", "pocket", "potato", "prison", "pumpkin", "rabbit", "rain",
  124. "rainbow", "ring", "river", "robot", "rocket", "root", "rope",
  125. "sail", "school", "scissors", "sea", "shoe", "sky", "snail", "snake",
  126. "snow", "soap", "sock", "spoon", "star", "sun", "table", "tiger",
  127. "tomato", "tooth", "train", "tree", "umbrella", "valley", "vase",
  128. "wagon", "wall", "whale", "wheel", "window", "wing", "wolf", "worm",
  129. "zebra", "zoo"
  130. ],
  131. generateName: () => {
  132. const adjectives = general.adjectives()
  133. const nouns = general.nouns()
  134. const randomAdjective = adjectives[Math.floor(Math.random() * adjectives.length)];
  135. const randomNoun = nouns[Math.floor(Math.random() * nouns.length)];
  136. // Capitalize first letters and return
  137. const cappedAdjective = randomAdjective.charAt(0).toUpperCase() + randomAdjective.slice(1);
  138. const cappedNoun = randomNoun.charAt(0).toUpperCase() + randomNoun.slice(1);
  139. return `${cappedAdjective} ${cappedNoun}`;
  140. }
  141. }
  142. const icons = {
  143. tempIcon: () => `
  144. <svg class="icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
  145. <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 4v10.54a4 4 0 1 1-4 0V4a2 2 0 0 1 4 0" />
  146. </svg>
  147. `,
  148. pressureIcon: () => `
  149. <svg class="icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
  150. <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m12 14l4-4M3.34 19a10 10 0 1 1 17.32 0" />
  151. </svg>
  152. `,
  153. humidityIcon: () => `
  154. <svg class="icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
  155. <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 22a7 7 0 0 0 7-7c0-2-1-3.9-3-5.5s-3.5-4-4-6.5c-.5 2.5-2 4.9-4 6.5S5 13 5 15a7 7 0 0 0 7 7" />
  156. </svg>
  157. `,
  158. bluetoothConnectionIcon: () => `
  159. <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
  160. <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m7 7l10 10l-5 5V2l5 5L7 17m11-5h3M3 12h3" />
  161. </svg>
  162. `
  163. }
  164. export default {
  165. general,
  166. icons,
  167. emails: {
  168. auth: {
  169. subject: () => `login link`,
  170. text: (details) => `
  171. hi!
  172. you can login using the following code: ${details?.code}
  173. or the following link: ${details?.link}
  174. if you did not request this email, feel free to ignore it.
  175. ${process.env.APP_NAME}
  176. `,
  177. },
  178. stations: {
  179. warningAdded: {
  180. subject: () => `new warnings!`,
  181. text: (details) => `
  182. hi,
  183. new warnings have been activated on your station ${details.stationName}:
  184. ${details.warnings.join('\n')}
  185. you can monitor them using this link: ${details.stationLink}
  186. ${process.env.APP_NAME} ${new Date().getFullYear()}
  187. `,
  188. },
  189. warningRemoved: {
  190. subject: () => `warnings removed`,
  191. text: (details) => `
  192. hi,
  193. the following warnings have been removed from your station ${details.stationName}:
  194. ${details.warnings.join('\n')}
  195. you can monitor them using this link: ${details.stationLink}
  196. ${process.env.APP_NAME} ${new Date().getFullYear()}
  197. `,
  198. }
  199. }
  200. },
  201. auth: {
  202. errors: {
  203. invalidEmail: () => `you need to provide a valid email.`,
  204. noVerificationToken: () => `verification token was not provided. please try again.`,
  205. verificationTokenUsedOrExpired: () => `verification token already used or expired. please try again.`,
  206. invalidVerificationCode: () => `invalid verification code. please try again.`,
  207. loginNeeded: () => `please log in first.`,
  208. ratelimits: {
  209. email: (details) => {
  210. if (!Number.parseInt(details?.duration)) return `too many requests for this email. try again later.`
  211. return `too many requests for this email. try again in ${formatTimeToString(general.timeFormats, general.functionWords.and(), details?.duration * 1000)}.`
  212. },
  213. ip: (details) => {
  214. if (!Number.parseInt(details?.duration)) return `you made too many requests. try again later.`
  215. return `you made too many requests. try again in ${formatTimeToString(general.timeFormats, general.functionWords.and(), details?.duration * 1000)}.`
  216. },
  217. code: () => `you entered too many wrong codes. you need to request a new verification.`,
  218. },
  219. turnstile: general.errors.turnstile,
  220. },
  221. },
  222. settings: {
  223. errors: {
  224. invalidEmail: () => `you need to provide a valid email.`,
  225. emailTaken: (details) => `a user with the provided email (${details?.newEmail}) already exists.`,
  226. turnstile: general.errors.turnstile,
  227. },
  228. },
  229. stations: {
  230. errors: {
  231. noName: () => `you need to provide a name.`,
  232. invalidOwner: () => `you need to provide a valid owner email.`,
  233. ownerUserNotFound: (details) => `no user with the provided email (${details?.newOwnerEmail}) exists.`,
  234. invalidSubowner: () => `one (or more) of the subowner emails is invalid.`,
  235. subownerUserNotFound: (details) => `no user with the provided email (${details?.subownerEmail}) exists.`,
  236. turnstile: general.errors.turnstile,
  237. },
  238. warnings: {
  239. highIndoorTemp: () => `High indoor temperature detected!`,
  240. highIndoorPressure: () => `High indoor pressure detected!`,
  241. highIndoorHumidity: () => `High indoor humidity detected!`,
  242. lowIndoorTemp: () => `Low indoor temperature detected!`,
  243. lowIndoorPressure: () => `Low indoor pressure detected!`,
  244. lowIndoorHumidity: () => `Low indoor humidity detected!`,
  245. highOutdoorTemp: () => `High outdoor temperature detected!`,
  246. highOutdoorPressure: () => `High outdoor pressure detected!`,
  247. highOutdoorHumidity: () => `High outdoor humidity detected!`,
  248. lowOutdoorTemp: () => `Low outdoor temperature detected!`,
  249. lowOutdoorPressure: () => `Low outdoor pressure detected!`,
  250. lowOutdoorHumidity: () => `Low outdoor humidity detected!`,
  251. },
  252. history: {
  253. properties: {
  254. indoorTemp: () => `${icons.tempIcon()} indoor temperature`,
  255. indoorPressure: () => `${icons.pressureIcon()} indoor pressure`,
  256. indoorHumidity: () => `${icons.humidityIcon()} indoor humidity`,
  257. outdoorConnected: () => `${icons.bluetoothConnectionIcon()} external unit connection`,
  258. outdoorTemp: () => `${icons.tempIcon()} outdoor temperature`,
  259. outdoorPressure: () => `${icons.pressureIcon()} outdoor pressure`,
  260. outdoorHumidity: () => `${icons.humidityIcon()} outdoor humidity`,
  261. },
  262. },
  263. },
  264. websocket: {
  265. keepalive: () => `free ferris`,
  266. dataSaved: (details) => `successfully saved data for ${details?.meteostanica?.name}`,
  267. errors: {
  268. missingFields: () => `missing required fields: indoorTemp, indoorPressure, indoorHumidity, indoorAltitude, outdoorConnected, outdoorTemp, outdoorPressure, outdoorHumidity, outdoorAltitude`,
  269. invalidKey: (details) => `invalid station websocket key (${details.key}) provided`,
  270. },
  271. }
  272. }