@jjlmoya/utils-nature 1.2.0 → 1.4.0

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 (59) hide show
  1. package/package.json +2 -1
  2. package/src/index.ts +4 -4
  3. package/src/tests/i18n_coverage.test.ts +36 -0
  4. package/src/tests/slug_uniqueness.test.ts +81 -0
  5. package/src/tests/tool_validation.test.ts +1 -2
  6. package/src/tool/cricketThermometer/i18n/de.ts +181 -0
  7. package/src/tool/cricketThermometer/i18n/id.ts +181 -0
  8. package/src/tool/cricketThermometer/i18n/it.ts +181 -0
  9. package/src/tool/cricketThermometer/i18n/ja.ts +181 -0
  10. package/src/tool/cricketThermometer/i18n/ko.ts +181 -0
  11. package/src/tool/cricketThermometer/i18n/nl.ts +181 -0
  12. package/src/tool/cricketThermometer/i18n/pl.ts +181 -0
  13. package/src/tool/cricketThermometer/i18n/pt.ts +181 -0
  14. package/src/tool/cricketThermometer/i18n/ru.ts +181 -0
  15. package/src/tool/cricketThermometer/i18n/sv.ts +181 -0
  16. package/src/tool/cricketThermometer/i18n/tr.ts +181 -0
  17. package/src/tool/cricketThermometer/i18n/zh.ts +181 -0
  18. package/src/tool/cricketThermometer/index.ts +15 -7
  19. package/src/tool/digitalCarbon/i18n/de.ts +235 -0
  20. package/src/tool/digitalCarbon/i18n/id.ts +235 -0
  21. package/src/tool/digitalCarbon/i18n/it.ts +235 -0
  22. package/src/tool/digitalCarbon/i18n/ja.ts +235 -0
  23. package/src/tool/digitalCarbon/i18n/ko.ts +235 -0
  24. package/src/tool/digitalCarbon/i18n/nl.ts +235 -0
  25. package/src/tool/digitalCarbon/i18n/pl.ts +235 -0
  26. package/src/tool/digitalCarbon/i18n/pt.ts +235 -0
  27. package/src/tool/digitalCarbon/i18n/ru.ts +235 -0
  28. package/src/tool/digitalCarbon/i18n/sv.ts +235 -0
  29. package/src/tool/digitalCarbon/i18n/tr.ts +235 -0
  30. package/src/tool/digitalCarbon/i18n/zh.ts +235 -0
  31. package/src/tool/digitalCarbon/index.ts +15 -7
  32. package/src/tool/digitalCarbon/seo.astro +4 -3
  33. package/src/tool/rainHarvester/i18n/de.ts +185 -0
  34. package/src/tool/rainHarvester/i18n/id.ts +185 -0
  35. package/src/tool/rainHarvester/i18n/it.ts +185 -0
  36. package/src/tool/rainHarvester/i18n/ja.ts +185 -0
  37. package/src/tool/rainHarvester/i18n/ko.ts +185 -0
  38. package/src/tool/rainHarvester/i18n/nl.ts +185 -0
  39. package/src/tool/rainHarvester/i18n/pl.ts +185 -0
  40. package/src/tool/rainHarvester/i18n/pt.ts +185 -0
  41. package/src/tool/rainHarvester/i18n/ru.ts +185 -0
  42. package/src/tool/rainHarvester/i18n/sv.ts +185 -0
  43. package/src/tool/rainHarvester/i18n/tr.ts +185 -0
  44. package/src/tool/rainHarvester/i18n/zh.ts +185 -0
  45. package/src/tool/rainHarvester/index.ts +15 -7
  46. package/src/tool/rainHarvester/seo.astro +4 -3
  47. package/src/tool/seedCalculator/i18n/de.ts +213 -0
  48. package/src/tool/seedCalculator/i18n/id.ts +213 -0
  49. package/src/tool/seedCalculator/i18n/it.ts +213 -0
  50. package/src/tool/seedCalculator/i18n/ja.ts +213 -0
  51. package/src/tool/seedCalculator/i18n/ko.ts +213 -0
  52. package/src/tool/seedCalculator/i18n/nl.ts +213 -0
  53. package/src/tool/seedCalculator/i18n/pl.ts +213 -0
  54. package/src/tool/seedCalculator/i18n/pt.ts +213 -0
  55. package/src/tool/seedCalculator/i18n/ru.ts +213 -0
  56. package/src/tool/seedCalculator/i18n/sv.ts +213 -0
  57. package/src/tool/seedCalculator/i18n/tr.ts +213 -0
  58. package/src/tool/seedCalculator/i18n/zh.ts +213 -0
  59. package/src/tool/seedCalculator/index.ts +15 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-nature",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -37,6 +37,7 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "@iconify-json/mdi": "^1.2.3",
40
+ "@jjlmoya/prompagate": "^1.1.0",
40
41
  "@jjlmoya/utils-shared": "1.2.0",
41
42
  "astro": "^6.1.2",
42
43
  "astro-icon": "^1.1.0"
package/src/index.ts CHANGED
@@ -18,13 +18,13 @@ export type {
18
18
  export { ALL_TOOLS } from './tools';
19
19
 
20
20
  export { CricketThermometerComponent, CricketThermometerSEO, CricketThermometerBibliography } from './tool/cricketThermometer';
21
- export { CRICKET_THERMOMETER_TOOL } from './tool/cricketThermometer/index';
21
+ export { CRICKET_THERMOMETER_TOOL, cricketThermometer } from './tool/cricketThermometer/index';
22
22
 
23
23
  export { SeedCalculatorComponent, SeedCalculatorSEO, SeedCalculatorBibliography } from './tool/seedCalculator';
24
- export { SEED_CALCULATOR_TOOL } from './tool/seedCalculator/index';
24
+ export { SEED_CALCULATOR_TOOL, seedCalculator } from './tool/seedCalculator/index';
25
25
 
26
26
  export { RainHarvesterComponent, RainHarvesterSEO, RainHarvesterBibliography } from './tool/rainHarvester';
27
- export { RAIN_HARVESTER_TOOL } from './tool/rainHarvester/index';
27
+ export { RAIN_HARVESTER_TOOL, rainHarvester } from './tool/rainHarvester/index';
28
28
 
29
29
  export { DigitalCarbonComponent, DigitalCarbonSEO, DigitalCarbonBibliography } from './tool/digitalCarbon';
30
- export { DIGITAL_CARBON_TOOL } from './tool/digitalCarbon/index';
30
+ export { DIGITAL_CARBON_TOOL, digitalCarbon } from './tool/digitalCarbon/index';
@@ -0,0 +1,36 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { ALL_TOOLS } from '../tools';
3
+
4
+ const EXPECTED_LOCALES = [
5
+ 'de', 'en', 'es', 'fr', 'id', 'it', 'ja', 'ko', 'nl', 'pl', 'pt', 'ru', 'sv', 'tr', 'zh'
6
+ ];
7
+
8
+ describe('I18n Coverage Validation', () => {
9
+ it('all tools should be registered', () => {
10
+ expect(ALL_TOOLS.length).toBeGreaterThan(0);
11
+ });
12
+
13
+ ALL_TOOLS.forEach(({ entry }: { entry: any }) => {
14
+ describe(`Tool: ${entry.id}`, () => {
15
+ it('should have all 15 required locales', () => {
16
+ const registeredLocales = Object.keys(entry.i18n);
17
+ EXPECTED_LOCALES.forEach((locale) => {
18
+ expect(
19
+ registeredLocales,
20
+ `Tool "${entry.id}" is missing locale "${locale}"`,
21
+ ).toContain(locale);
22
+ });
23
+ });
24
+
25
+ it('all locale loaders should be functions', () => {
26
+ EXPECTED_LOCALES.forEach((locale) => {
27
+ const loader = entry.i18n[locale as keyof typeof entry.i18n];
28
+ expect(
29
+ typeof loader,
30
+ `Tool "${entry.id}" locale "${locale}" loader is not a function`,
31
+ ).toBe('function');
32
+ });
33
+ });
34
+ });
35
+ });
36
+ });
@@ -0,0 +1,81 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { ALL_TOOLS } from '../tools';
3
+ import type { ToolLocaleContent } from '../types';
4
+
5
+ const sharingLocales = ['ja', 'ko', 'zh'];
6
+
7
+ interface ValidateParams {
8
+ toolId: string;
9
+ locale: string;
10
+ content: ToolLocaleContent;
11
+ enSlug: string;
12
+ slugs: Map<string, string>;
13
+ }
14
+
15
+ const validateLocaleSlug = ({
16
+ toolId,
17
+ locale,
18
+ content,
19
+ enSlug,
20
+ slugs,
21
+ }: ValidateParams) => {
22
+ expect(
23
+ content.slug,
24
+ `Tool "${toolId}" locale "${locale}" has an invalid slug ("${content.slug}"). Slugs must be transliterated (only a-z, 0-9, and -).`,
25
+ ).toMatch(/^[a-z0-9-]+$/);
26
+
27
+ if (locale === 'en') {
28
+ return;
29
+ }
30
+
31
+ if (sharingLocales.includes(locale)) {
32
+ expect(
33
+ content.slug,
34
+ `Tool "${toolId}" locale "${locale}" must use the same slug as "en" ("${enSlug}").`,
35
+ ).toBe(enSlug);
36
+ } else {
37
+ expect(
38
+ content.slug,
39
+ `Tool "${toolId}" locale "${locale}" has the same slug as "en" ("${enSlug}"). Cada slug tiene que estar en su propia idioma`,
40
+ ).not.toBe(enSlug);
41
+
42
+ if (slugs.has(content.slug)) {
43
+ const previousLocale = slugs.get(content.slug);
44
+ expect(
45
+ false,
46
+ `Tool "${toolId}" locales "${locale}" and "${previousLocale}" share the same slug ("${content.slug}"). Cada slug tiene que estar en su propia idioma`,
47
+ ).toBe(true);
48
+ }
49
+ slugs.set(content.slug, locale);
50
+ }
51
+ };
52
+
53
+ describe('Slug Localization and Uniqueness Validation', () => {
54
+ ALL_TOOLS.forEach((tool) => {
55
+ describe(`Tool: ${tool.entry.id}`, () => {
56
+ it('every locale should have a unique, translated slug', async () => {
57
+ const slugs = new Map<string, string>();
58
+ const locales = Object.keys(tool.entry.i18n);
59
+
60
+ let enSlug = '';
61
+ if (locales.includes('en')) {
62
+ const enLoader = tool.entry.i18n['en' as keyof typeof tool.entry.i18n];
63
+ const enContent = (await enLoader?.()) as ToolLocaleContent;
64
+ enSlug = enContent.slug;
65
+ }
66
+
67
+ for (const locale of locales) {
68
+ const loader = tool.entry.i18n[locale as keyof typeof tool.entry.i18n];
69
+ const content = (await loader?.()) as ToolLocaleContent;
70
+ validateLocaleSlug({
71
+ toolId: tool.entry.id,
72
+ locale,
73
+ content,
74
+ enSlug,
75
+ slugs,
76
+ });
77
+ }
78
+ });
79
+ });
80
+ });
81
+ });
@@ -1,6 +1,5 @@
1
1
  import { describe, it, expect } from 'vitest';
2
- import { ALL_TOOLS } from '../tools';
3
- import { natureCategory } from '../data';
2
+ import { ALL_TOOLS, natureCategory } from '../index';
4
3
 
5
4
  describe('Tool Validation Suite', () => {
6
5
  describe('Library Registration', () => {
@@ -0,0 +1,181 @@
1
+ import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { CricketThermometerUI } from '../ui';
4
+
5
+ const slug = 'grillen-thermometer';
6
+ const title = 'Grillen Thermometer – Dolbearsches Gesetz Temperaturrechner';
7
+ const description =
8
+ 'Kein Thermometer zur Hand? Hören Sie den Grillen zu. Berechnen Sie die exakte Temperatur, indem Sie das Zirpen mit unserem Dolbearsches Gesetz Rechner zählen.';
9
+
10
+ const faqData = [
11
+ {
12
+ question: 'Was ist das Dolbearsche Gesetz?',
13
+ answer:
14
+ 'Es wurde 1897 von Amos Dolbear formuliert und ist eine wissenschaftliche Beobachtung, die eine lineare Korrelation zwischen der Zirp-Rate von Grillen und der Umgebungslufttemperatur feststellte.',
15
+ },
16
+ {
17
+ question: 'Warum zirpen Grillen bei Hitze schneller?',
18
+ answer:
19
+ 'Grillen sind wechselwarme Tiere (Ektothermen). Die Geschwindigkeit ihrer Stoffwechselprozesse und Muskelkontraktionen hängt von der Außentemperatur ab; je wärmer es ist, desto mehr Energie haben sie, um Geräusche schnell hintereinander zu erzeugen.',
20
+ },
21
+ {
22
+ question: 'Ist diese Messung genau?',
23
+ answer:
24
+ 'Sie ist überraschend genau für Arten wie die Schneegrille (Oecanthus fultoni), mit einer Fehlermarge von etwa 0,5°C bei korrekter Zählung. Faktoren wie Luftfeuchtigkeit oder Wind können das Ergebnis jedoch beeinflussen.',
25
+ },
26
+ {
27
+ question: 'Welche Grille sollte ich für die Berechnung nutzen?',
28
+ answer:
29
+ 'Die ursprüngliche Formel basiert auf der Schneegrille. Für die gewöhnliche Feldgrille ist das Verhältnis ähnlich, aber die Rate tendiert dazu, etwas langsamer zu sein.',
30
+ },
31
+ ];
32
+
33
+ const howToData = [
34
+ {
35
+ name: 'Finden Sie eine einsame Grille',
36
+ text: 'Suchen Sie sich nachts einen ruhigen Ort, an dem Sie das Zirpen einer einzelnen Grille deutlich hören können, um die Rhythmen nicht zu verwechseln.',
37
+ },
38
+ {
39
+ name: 'Zählen Sie das Zirpen für 15 Sekunden',
40
+ text: 'Nutzen Sie eine Stoppuhr und zählen Sie, wie viele Stridulationen das Insekt in genau 15 Sekunden von sich gibt.',
41
+ },
42
+ {
43
+ name: 'Geben Sie den Wert ein',
44
+ text: 'Tippen Sie einige Sekunden lang im Rhythmus des Zirpens auf die TAP-Schaltfläche, damit der Rechner automatisch die BPM berechnet.',
45
+ },
46
+ {
47
+ name: 'Überprüfen Sie die Temperatur',
48
+ text: 'Das System wendet die Formel T(°C) = 10 + (N - 40) / 7 an, um Ihnen eine Schätzung der Umgebungswärme in Grad Celsius zu geben.',
49
+ },
50
+ ];
51
+
52
+ const faqSchema: WithContext<FAQPage> = {
53
+ '@context': 'https://schema.org',
54
+ '@type': 'FAQPage',
55
+ mainEntity: faqData.map((item) => ({
56
+ '@type': 'Question',
57
+ name: item.question,
58
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
59
+ })),
60
+ };
61
+
62
+ const howToSchema: WithContext<HowToThing> = {
63
+ '@context': 'https://schema.org',
64
+ '@type': 'HowTo',
65
+ name: title,
66
+ description,
67
+ step: howToData.map((step, i) => ({
68
+ '@type': 'HowToStep',
69
+ position: i + 1,
70
+ name: step.name,
71
+ text: step.text,
72
+ })),
73
+ };
74
+
75
+ const appSchema: WithContext<SoftwareApplication> = {
76
+ '@context': 'https://schema.org',
77
+ '@type': 'SoftwareApplication',
78
+ name: title,
79
+ description,
80
+ applicationCategory: 'UtilityApplication',
81
+ operatingSystem: 'All',
82
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
83
+ inLanguage: 'de',
84
+ };
85
+
86
+ export const content: ToolLocaleContent<CricketThermometerUI> = {
87
+ slug,
88
+ title,
89
+ description,
90
+ faqTitle: 'Häufig gestellte Fragen',
91
+ faq: faqData,
92
+ bibliographyTitle: 'Wissenschaftliche Referenzen',
93
+ bibliography: [
94
+ {
95
+ name: 'The American Naturalist - Die Grille als Thermometer',
96
+ url: 'https://www.jstor.org/stable/2453256',
97
+ },
98
+ {
99
+ name: 'Wikipedia - Dolbearsches Gesetz',
100
+ url: 'https://de.wikipedia.org/wiki/Dolbearsches_Gesetz',
101
+ },
102
+ ],
103
+ howTo: howToData,
104
+ schemas: [faqSchema, howToSchema, appSchema],
105
+ seo: [
106
+ {
107
+ type: 'title',
108
+ text: 'Vollständiger Leitfaden: So nutzen Sie das Dolbearsche Gesetz zur Temperaturberechnung',
109
+ level: 2,
110
+ },
111
+ {
112
+ type: 'paragraph',
113
+ html: 'Wussten Sie, dass Sie die exakte Temperatur allein durch das Zuhören in der Natur bestimmen können? 1897 entdeckte der Physiker Amos Dolbear einen präzisen mathematischen Zusammenhang zwischen der Zirp-Rate von Grillen und der Umgebungswärme. Dieses Tool digitalisiert diese Entdeckung, um Ihr Smartphone in ein natürliches Thermometer zu verwandeln.',
114
+ },
115
+ {
116
+ type: 'tip',
117
+ title: 'Warum singen Grillen?',
118
+ html: '<p>Der „Gesang“ der Grille, auch <strong>Stridulation</strong> genannt, ist eigentlich ein Paarungsruf. Die Männchen reiben ihre Flügel (nicht ihre Beine) aneinander, um diesen Laut zu erzeugen. Faszinierenderweise hängt die Geschwindigkeit dieses Reibens direkt von der Wärmeenergie der Luft ab, da Grillen wechselwarme Tiere (Ektothermen) sind.</p>',
119
+ },
120
+ {
121
+ type: 'title',
122
+ text: 'Die Wissenschaft: Ektothermie und Stoffwechsel',
123
+ level: 3,
124
+ },
125
+ {
126
+ type: 'paragraph',
127
+ html: 'Im Gegensatz zu Säugetieren, die eine konstante Körpertemperatur aufrechterhalten, sind Insekten von äußerer Wärme abhängig. Ihre biochemischen Reaktionen folgen der <strong>Arrhenius-Gleichung</strong>: Je mehr Wärme, desto schneller die Reaktion.',
128
+ },
129
+ {
130
+ type: 'paragraph',
131
+ html: 'Das bedeutet, dass die Grillenmuskeln für die Kontraktion und das Reiben der Flügel enzymatische Reaktionen benötigen. Wenn es kalt ist, sind diese Reaktionen langsam und das Zirpen ist träge. Wenn es warm ist, beschleunigt sich der Stoffwechsel und der Gesang wird zu einem hektischen Triller.',
132
+ },
133
+ {
134
+ type: 'title',
135
+ text: 'Die Dolbear-Formel',
136
+ level: 3,
137
+ },
138
+ {
139
+ type: 'paragraph',
140
+ html: 'Obwohl es Variationen für verschiedene Arten gibt, ist die bekannteste Formel die für die Schneegrille (<em>Oecanthus fultoni</em>). Um die Temperatur in Grad Celsius zu erhalten:',
141
+ },
142
+ {
143
+ type: 'code',
144
+ code: 'T(°C) = 10 + (N - 40) / 7\n\nMit N = Anzahl der Zirps pro Minute.',
145
+ ariaLabel: 'Dolbearsche Formel zur Berechnung der Temperatur aus dem Grillenzirpen',
146
+ },
147
+ {
148
+ type: 'paragraph',
149
+ html: 'Unser Tool erledigt das automatisch: Es misst die Zeit zwischen Ihren Taps, berechnet die Zirps pro Minute (BPM) und wendet die Formel sofort an.',
150
+ },
151
+ {
152
+ type: 'title',
153
+ text: 'Faszinierende Fakten',
154
+ level: 3,
155
+ },
156
+ {
157
+ type: 'list',
158
+ items: [
159
+ '<strong>Thermometer der Liebe:</strong> Einige Theorien besagen, dass Weibchen Männchen bevorzugen, die in der „korrekten“ Frequenz für die aktuelle Temperatur singen, da dies darauf hindeutet, dass das Männchen gesund ist und einen starken Stoffwechsel hat.',
160
+ '<strong>Kältegrenze:</strong> Unterhalb von 10°C (50°F) hören die meisten Grillen auf zu singen, da ihr Stoffwechsel zu langsam ist, um die muskuläre Anstrengung aufrechtzuerhalten.',
161
+ '<strong>Synchronisation:</strong> In warmen Nächten können tausende Grillen ihr Zirpen synchronisieren und so einen beeindruckenden „Wellen“-Klangeffekt erzeugen.',
162
+ ],
163
+ },
164
+ {
165
+ type: 'tip',
166
+ title: 'Hinweis zur Genauigkeit',
167
+ html: '<p>Die Genauigkeit hängt von der Grillenart ab. Dieses Tool ist für die gewöhnliche Feldgrille und die Baumgrille kalibriert. Faktoren wie Luftfeuchtigkeit oder Wind können das Ergebnis um ±0,5°C verändern.</p>',
168
+ },
169
+ ],
170
+ ui: {
171
+ labelWaiting: 'Warten...',
172
+ labelTapping: 'Weiter tippen...',
173
+ tapInstruction: 'Jedes Mal, wenn Sie ein Zirpen hören',
174
+ btnReset: 'Zurücksetzen',
175
+ btnSoundOn: 'Ton: Ein',
176
+ btnSoundOff: 'Ton: Aus',
177
+ unitChirpsMin: 'Zirp/Min',
178
+ faqTitle: 'Häufig gestellte Fragen',
179
+ bibliographyTitle: 'Wissenschaftliche Referenzen',
180
+ },
181
+ };
@@ -0,0 +1,181 @@
1
+ import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { CricketThermometerUI } from '../ui';
4
+
5
+ const slug = 'termometer-jangkrik';
6
+ const title = 'Termometer Jangkrik – Kalkulator Suhu Hukum Dolbear';
7
+ const description =
8
+ 'Tidak ada termometer? Dengarkan jangkrik. Hitung suhu tepat dengan menghitung kerikan menggunakan kalkulator Hukum Dolbear kami.';
9
+
10
+ const faqData = [
11
+ {
12
+ question: 'Apa itu Hukum Dolbear?',
13
+ answer:
14
+ 'Dirumuskan pada tahun 1897 oleh Amos Dolbear, ini adalah observasi ilmiah yang menemukan korelasi linier antara laju kerikan jangkrik dan suhu udara sekitar.',
15
+ },
16
+ {
17
+ question: 'Mengapa jangkrik mengerik lebih cepat saat panas?',
18
+ answer:
19
+ 'Jangkrik adalah hewan berdarah dingin (ektoterm). Kecepatan proses metabolisme dan kontraksi otot mereka bergantung pada suhu eksternal; semakin hangat, semakin banyak energi yang mereka miliki untuk mengeluarkan suara dengan cepat.',
20
+ },
21
+ {
22
+ question: 'Apakah pengukuran ini akurat?',
23
+ answer:
24
+ 'Sangat akurat untuk spesies seperti jangkrik pohon salju (Oecanthus fultoni), dengan ambang batas kesalahan sekitar 0,5°C jika dihitung dengan benar. Namun, faktor seperti kelembapan atau angin dapat mengubah hasilnya.',
25
+ },
26
+ {
27
+ question: 'Jangkrik mana yang harus saya gunakan untuk perhitungan?',
28
+ answer:
29
+ 'Formula aslinya didasarkan pada jangkrik pohon salju. Untuk jangkrik lapangan biasa, hubungannya serupa tetapi lajunya cenderung sedikit lebih lambat.',
30
+ },
31
+ ];
32
+
33
+ const howToData = [
34
+ {
35
+ name: 'Temukan jangkrik yang menyendiri',
36
+ text: 'Cari tempat yang tenang di malam hari di mana Anda dapat dengan jelas mendengar kerikan satu jangkrik untuk menghindari kebingungan ritme.',
37
+ },
38
+ {
39
+ name: 'Hitung kerikan selama 15 detik',
40
+ text: 'Gunakan stopwatch dan hitung berapa banyak stridulasi yang dikeluarkan serangga tersebut dalam tepat 15 detik.',
41
+ },
42
+ {
43
+ name: 'Masukkan nilai',
44
+ text: 'Ketuk tombol KETUK (TAP) sesuai irama kerikan selama beberapa detik sehingga kalkulator secara otomatis menghitung BPM.',
45
+ },
46
+ {
47
+ name: 'Verifikasi suhu',
48
+ text: 'Sistem akan menerapkan rumus T(°C) = 10 + (N - 40) / 7 untuk memberi Anda perkiraan panas sekitar dalam derajat Celsius.',
49
+ },
50
+ ];
51
+
52
+ const faqSchema: WithContext<FAQPage> = {
53
+ '@context': 'https://schema.org',
54
+ '@type': 'FAQPage',
55
+ mainEntity: faqData.map((item) => ({
56
+ '@type': 'Question',
57
+ name: item.question,
58
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
59
+ })),
60
+ };
61
+
62
+ const howToSchema: WithContext<HowToThing> = {
63
+ '@context': 'https://schema.org',
64
+ '@type': 'HowTo',
65
+ name: title,
66
+ description,
67
+ step: howToData.map((step, i) => ({
68
+ '@type': 'HowToStep',
69
+ position: i + 1,
70
+ name: step.name,
71
+ text: step.text,
72
+ })),
73
+ };
74
+
75
+ const appSchema: WithContext<SoftwareApplication> = {
76
+ '@context': 'https://schema.org',
77
+ '@type': 'SoftwareApplication',
78
+ name: title,
79
+ description,
80
+ applicationCategory: 'UtilityApplication',
81
+ operatingSystem: 'All',
82
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
83
+ inLanguage: 'id',
84
+ };
85
+
86
+ export const content: ToolLocaleContent<CricketThermometerUI> = {
87
+ slug,
88
+ title,
89
+ description,
90
+ faqTitle: 'Pertanyaan yang Sering Diajukan',
91
+ faq: faqData,
92
+ bibliographyTitle: 'Referensi Ilmiah',
93
+ bibliography: [
94
+ {
95
+ name: 'The American Naturalist - The Cricket as a Thermometer',
96
+ url: 'https://www.jstor.org/stable/2453256',
97
+ },
98
+ {
99
+ name: 'Wikipedia - Dolbear\'s Law',
100
+ url: 'https://en.wikipedia.org/wiki/Dolbear%27s_law',
101
+ },
102
+ ],
103
+ howTo: howToData,
104
+ schemas: [faqSchema, howToSchema, appSchema],
105
+ seo: [
106
+ {
107
+ type: 'title',
108
+ text: 'Panduan Lengkap: Cara Menggunakan Hukum Dolbear untuk Menghitung Suhu',
109
+ level: 2,
110
+ },
111
+ {
112
+ type: 'paragraph',
113
+ html: 'Tahukah Anda bahwa Anda bisa mengetahui suhu tepat hanya dengan mendengarkan alam? Pada tahun 1897, fisikawan Amos Dolbear menemukan hubungan matematis yang tepat antara laju kerikan jangkrik dan panas sekitar. Alat ini mendigitalisasi penemuan tersebut untuk mengubah ponsel Anda menjadi termometer alami.',
114
+ },
115
+ {
116
+ type: 'tip',
117
+ title: 'Mengapa jangkrik bernyanyi?',
118
+ html: '<p>"Nyanyian" jangkrik, atau <strong>stridulasi</strong>, sebenarnya adalah panggilan kawin. Jantan menggosokkan sayap mereka (bukan kaki mereka) bersama-sama untuk menciptakan suara ini. Menariknya, karena mereka adalah hewan berdarah dingin (ektoterm), kecepatan penggosokan ini bergantung langsung pada energi termal udara.</p>',
119
+ },
120
+ {
121
+ type: 'title',
122
+ text: 'Sains: Ektotermi dan Metabolisme',
123
+ level: 3,
124
+ },
125
+ {
126
+ type: 'paragraph',
127
+ html: 'Berbeda dengan mamalia yang menjaga suhu tubuh tetap konstan, serangga bergantung pada panas eksternal. Reaksi biokimia mereka mengikuti <strong>Persamaan Arrhenius</strong>: semakin banyak panas, semakin cepat reaksinya.',
128
+ },
129
+ {
130
+ type: 'paragraph',
131
+ html: 'Ini berarti agar otot jangkrik dapat berkontraksi dan menggosokkan sayapnya, mereka memerlukan reaksi enzimatik. Jika dingin, reaksi ini lambat dan kerikan menjadi lesu. Jika hangat, metabolisme meningkat dan nyanyian menjadi trill yang panik.',
132
+ },
133
+ {
134
+ type: 'title',
135
+ text: 'Rumus Dolbear',
136
+ level: 3,
137
+ },
138
+ {
139
+ type: 'paragraph',
140
+ html: 'Meskipun terdapat variasi untuk spesies yang berbeda, rumus yang paling terkenal adalah untuk jangkrik pohon salju (<em>Oecanthus fultoni</em>). Untuk mendapatkan suhu dalam derajat Celsius:',
141
+ },
142
+ {
143
+ type: 'code',
144
+ code: 'T(°C) = 10 + (N - 40) / 7\n\nDi mana N = jumlah kerikan per menit.',
145
+ ariaLabel: 'Rumus Dolbear untuk menghitung suhu dari kerikan jangkrik',
146
+ },
147
+ {
148
+ type: 'paragraph',
149
+ html: 'Alat kami melakukan ini secara otomatis: ia mengukur waktu di antara ketukan Anda, menghitung kerikan per menit (BPM) dan menerapkan rumus secara instan.',
150
+ },
151
+ {
152
+ type: 'title',
153
+ text: 'Fakta Menarik',
154
+ level: 3,
155
+ },
156
+ {
157
+ type: 'list',
158
+ items: [
159
+ '<strong>Termometer Cinta:</strong> Beberapa teori menunjukkan bahwa betina lebih menyukai jantan yang bernyanyi pada frekuensi yang "benar" untuk suhu saat ini, karena itu menunjukkan jantan tersebut sehat dan memiliki metabolisme yang kuat.',
160
+ '<strong>Batas Dingin:</strong> Di bawah 10°C (50°F), sebagian besar jangkrik berhenti bernyanyi karena metabolisme mereka terlalu lambat untuk mempertahankan upaya otot.',
161
+ '<strong>Sinkronisasi:</strong> Pada malam yang hangat, ribuan jangkrik dapat menyinkronkan kerikan mereka, menciptakan efek suara "gelombang" yang mengesankan.',
162
+ ],
163
+ },
164
+ {
165
+ type: 'tip',
166
+ title: 'Catatan Akurasi',
167
+ html: '<p>Akurasi bergantung pada spesies jangkrik. Alat ini dikalibrasi untuk jangkrik lapangan biasa dan jangkrik pohon. Faktor seperti kelembapan atau angin dapat mengubah hasilnya sebesar ±0,5°C.</p>',
168
+ },
169
+ ],
170
+ ui: {
171
+ labelWaiting: 'Menunggu...',
172
+ labelTapping: 'Terus mengetuk...',
173
+ tapInstruction: 'Setiap kali Anda mendengar kerikan',
174
+ btnReset: 'Reset',
175
+ btnSoundOn: 'Suara: Aktif',
176
+ btnSoundOff: 'Suara: Nonaktif',
177
+ unitChirpsMin: 'kerikan/menit',
178
+ faqTitle: 'Pertanyaan yang Sering Diajukan',
179
+ bibliographyTitle: 'Referensi Ilmiah',
180
+ },
181
+ };