@jjlmoya/utils-nature 1.14.0 → 1.16.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.
- package/package.json +4 -2
- package/src/category/i18n/fr.ts +6 -6
- package/src/category/i18n/ru.ts +5 -5
- package/src/layouts/PreviewLayout.astro +1 -1
- package/src/tests/diacritics_density.test.ts +118 -0
- package/src/tests/inverted_punctuation.test.ts +84 -0
- package/src/tests/no_en_dash.test.ts +71 -0
- package/src/tests/pagespeed_best_practices.test.ts +198 -0
- package/src/tests/script_density.test.ts +94 -0
- package/src/tool/cricketThermometer/i18n/de.ts +4 -4
- package/src/tool/cricketThermometer/i18n/en.ts +1 -1
- package/src/tool/cricketThermometer/i18n/es.ts +1 -1
- package/src/tool/cricketThermometer/i18n/fr.ts +7 -7
- package/src/tool/cricketThermometer/i18n/id.ts +1 -1
- package/src/tool/cricketThermometer/i18n/it.ts +1 -1
- package/src/tool/cricketThermometer/i18n/ja.ts +1 -1
- package/src/tool/cricketThermometer/i18n/ko.ts +1 -1
- package/src/tool/cricketThermometer/i18n/nl.ts +1 -1
- package/src/tool/cricketThermometer/i18n/pl.ts +4 -4
- package/src/tool/cricketThermometer/i18n/pt.ts +1 -1
- package/src/tool/cricketThermometer/i18n/ru.ts +6 -6
- package/src/tool/cricketThermometer/i18n/sv.ts +1 -1
- package/src/tool/cricketThermometer/i18n/tr.ts +1 -1
- package/src/tool/cricketThermometer/i18n/zh.ts +6 -6
- package/src/tool/digitalCarbon/digital-carbon-footprint-calculator.css +57 -1
- package/src/tool/digitalCarbon/i18n/de.ts +2 -2
- package/src/tool/digitalCarbon/i18n/fr.ts +4 -4
- package/src/tool/digitalCarbon/i18n/ru.ts +1 -1
- package/src/tool/rainHarvester/i18n/de.ts +4 -4
- package/src/tool/rainHarvester/i18n/en.ts +1 -1
- package/src/tool/rainHarvester/i18n/es.ts +1 -1
- package/src/tool/rainHarvester/i18n/fr.ts +2 -2
- package/src/tool/rainHarvester/i18n/id.ts +1 -1
- package/src/tool/rainHarvester/i18n/it.ts +1 -1
- package/src/tool/rainHarvester/i18n/ja.ts +1 -1
- package/src/tool/rainHarvester/i18n/ko.ts +1 -1
- package/src/tool/rainHarvester/i18n/nl.ts +1 -1
- package/src/tool/rainHarvester/i18n/pl.ts +4 -4
- package/src/tool/rainHarvester/i18n/pt.ts +1 -1
- package/src/tool/rainHarvester/i18n/ru.ts +7 -7
- package/src/tool/rainHarvester/i18n/sv.ts +1 -1
- package/src/tool/rainHarvester/i18n/tr.ts +1 -1
- package/src/tool/rainHarvester/i18n/zh.ts +4 -4
- package/src/tool/seedCalculator/component.astro +2 -2
- package/src/tool/seedCalculator/i18n/fr.ts +1 -1
- package/src/tool/seedCalculator/i18n/pl.ts +1 -1
- package/src/tool/seedCalculator/i18n/ru.ts +4 -4
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { ALL_TOOLS } from '../tools';
|
|
3
|
+
|
|
4
|
+
type ScriptLocale = keyof typeof SCRIPT_RULES;
|
|
5
|
+
|
|
6
|
+
const SCRIPT_RULES = {
|
|
7
|
+
ja: {
|
|
8
|
+
language: 'Japanese',
|
|
9
|
+
scriptName: 'kana/kanji',
|
|
10
|
+
scriptCharacters: /[\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Han}]/gu,
|
|
11
|
+
minScriptRatio: 0.45,
|
|
12
|
+
},
|
|
13
|
+
ko: {
|
|
14
|
+
language: 'Korean',
|
|
15
|
+
scriptName: 'hangul',
|
|
16
|
+
scriptCharacters: /\p{Script=Hangul}/gu,
|
|
17
|
+
minScriptRatio: 0.55,
|
|
18
|
+
},
|
|
19
|
+
ru: {
|
|
20
|
+
language: 'Russian',
|
|
21
|
+
scriptName: 'cyrillic',
|
|
22
|
+
scriptCharacters: /\p{Script=Cyrillic}/gu,
|
|
23
|
+
minScriptRatio: 0.65,
|
|
24
|
+
},
|
|
25
|
+
zh: {
|
|
26
|
+
language: 'Chinese',
|
|
27
|
+
scriptName: 'han',
|
|
28
|
+
scriptCharacters: /\p{Script=Han}/gu,
|
|
29
|
+
minScriptRatio: 0.45,
|
|
30
|
+
},
|
|
31
|
+
} as const;
|
|
32
|
+
|
|
33
|
+
const LETTERS = /\p{L}/gu;
|
|
34
|
+
const TRANSLATABLE_KEYS = ['title', 'description', 'ui', 'seo', 'faq', 'howTo'] as const;
|
|
35
|
+
|
|
36
|
+
function collectStrings(value: unknown): string[] {
|
|
37
|
+
if (typeof value === 'string') return [value];
|
|
38
|
+
if (!value || typeof value !== 'object') return [];
|
|
39
|
+
if (Array.isArray(value)) return value.flatMap(collectStrings);
|
|
40
|
+
return Object.values(value).flatMap(collectStrings);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function normalizeText(value: unknown): string {
|
|
44
|
+
return collectStrings(value).join(' ').normalize('NFC');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function translatableContent(content: Record<string, unknown>) {
|
|
48
|
+
return TRANSLATABLE_KEYS.map((key) => content[key]);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function letterCount(text: string): number {
|
|
52
|
+
return text.match(LETTERS)?.length ?? 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function scriptCount(text: string, locale: ScriptLocale): number {
|
|
56
|
+
return text.match(SCRIPT_RULES[locale].scriptCharacters)?.length ?? 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function scriptRatio(text: string, locale: ScriptLocale): number {
|
|
60
|
+
const letters = letterCount(text);
|
|
61
|
+
if (letters === 0) return 0;
|
|
62
|
+
return scriptCount(text, locale) / letters;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
describe('Native script density validation', () => {
|
|
66
|
+
ALL_TOOLS.forEach((tool) => {
|
|
67
|
+
describe(`Tool: ${tool.entry.id}`, () => {
|
|
68
|
+
Object.keys(SCRIPT_RULES).forEach((locale) => {
|
|
69
|
+
it(`${locale} keeps most translated text in its native script`, async () => {
|
|
70
|
+
const typedLocale = locale as ScriptLocale;
|
|
71
|
+
const loader = tool.entry.i18n[typedLocale];
|
|
72
|
+
if (!loader) return;
|
|
73
|
+
|
|
74
|
+
const content = await loader();
|
|
75
|
+
const rule = SCRIPT_RULES[typedLocale];
|
|
76
|
+
const text = normalizeText(translatableContent(content as Record<string, unknown>));
|
|
77
|
+
const letters = letterCount(text);
|
|
78
|
+
const matches = scriptCount(text, typedLocale);
|
|
79
|
+
const ratio = scriptRatio(text, typedLocale);
|
|
80
|
+
|
|
81
|
+
expect(
|
|
82
|
+
ratio,
|
|
83
|
+
[
|
|
84
|
+
`Possible broken translation detected in ${tool.entry.id}/${typedLocale} (${rule.language}).`,
|
|
85
|
+
`The text has ${matches} ${rule.scriptName} characters out of ${letters} analyzed letters (${(ratio * 100).toFixed(1)}%).`,
|
|
86
|
+
`Most translatable content should be written in ${rule.scriptName} script.`,
|
|
87
|
+
'Non-translatable fields such as slug, bibliography, and schemas are ignored to avoid false positives.',
|
|
88
|
+
].join(' '),
|
|
89
|
+
).toBeGreaterThanOrEqual(rule.minScriptRatio);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -4,7 +4,7 @@ import type { ToolLocaleContent } from '../../../types';
|
|
|
4
4
|
import type { CricketThermometerUI } from '../ui';
|
|
5
5
|
|
|
6
6
|
const slug = 'grillen-thermometer';
|
|
7
|
-
const title = 'Grillen Thermometer
|
|
7
|
+
const title = 'Grillen Thermometer: Dolbearsches Gesetz Temperaturrechner';
|
|
8
8
|
const description =
|
|
9
9
|
'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.';
|
|
10
10
|
|
|
@@ -105,7 +105,7 @@ export const content: ToolLocaleContent<CricketThermometerUI> = {
|
|
|
105
105
|
{
|
|
106
106
|
type: 'tip',
|
|
107
107
|
title: 'Warum singen Grillen?',
|
|
108
|
-
html: '<p>Der
|
|
108
|
+
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>',
|
|
109
109
|
},
|
|
110
110
|
{
|
|
111
111
|
type: 'title',
|
|
@@ -146,9 +146,9 @@ export const content: ToolLocaleContent<CricketThermometerUI> = {
|
|
|
146
146
|
{
|
|
147
147
|
type: 'list',
|
|
148
148
|
items: [
|
|
149
|
-
'<strong>Thermometer der Liebe:</strong> Einige Theorien besagen, dass Weibchen Männchen bevorzugen, die in der
|
|
149
|
+
'<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.',
|
|
150
150
|
'<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.',
|
|
151
|
-
'<strong>Synchronisation:</strong> In warmen Nächten können tausende Grillen ihr Zirpen synchronisieren und so einen beeindruckenden
|
|
151
|
+
'<strong>Synchronisation:</strong> In warmen Nächten können tausende Grillen ihr Zirpen synchronisieren und so einen beeindruckenden "Wellen"-Klangeffekt erzeugen.',
|
|
152
152
|
],
|
|
153
153
|
},
|
|
154
154
|
{
|
|
@@ -4,7 +4,7 @@ import type { ToolLocaleContent } from '../../../types';
|
|
|
4
4
|
import type { CricketThermometerUI } from '../ui';
|
|
5
5
|
|
|
6
6
|
const slug = 'cricket-thermometer';
|
|
7
|
-
const title = 'Cricket Thermometer
|
|
7
|
+
const title = 'Cricket Thermometer: Dolbear\'s Law Temperature Calculator';
|
|
8
8
|
const description =
|
|
9
9
|
'No thermometer? Listen to the crickets. Calculate the exact temperature by counting chirps with our Dolbear\'s Law calculator.';
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ import type { ToolLocaleContent } from '../../../types';
|
|
|
4
4
|
import type { CricketThermometerUI } from '../ui';
|
|
5
5
|
|
|
6
6
|
const slug = 'termometro-grillo';
|
|
7
|
-
const title = '¿Qué temperatura hace
|
|
7
|
+
const title = '¿Qué temperatura hace?: Termómetro de Grillos (Ley de Dolbear)';
|
|
8
8
|
const description =
|
|
9
9
|
'¿No tienes termómetro? Escucha a los grillos. Calcula la temperatura exacta contando sus chirridos con nuestra calculadora de la Ley de Dolbear.';
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ import type { ToolLocaleContent } from '../../../types';
|
|
|
4
4
|
import type { CricketThermometerUI } from '../ui';
|
|
5
5
|
|
|
6
6
|
const slug = 'thermometre-grillon';
|
|
7
|
-
const title = 'Thermomètre à Grillons
|
|
7
|
+
const title = 'Thermomètre à Grillons: Loi de Dolbear';
|
|
8
8
|
const description =
|
|
9
9
|
'Pas de thermomètre ? Écoutez les grillons. Calculez la température exacte en comptant les stridulations avec notre calculateur de la Loi de Dolbear.';
|
|
10
10
|
|
|
@@ -95,7 +95,7 @@ export const content: ToolLocaleContent<CricketThermometerUI> = {
|
|
|
95
95
|
seo: [
|
|
96
96
|
{
|
|
97
97
|
type: 'title',
|
|
98
|
-
text: 'Guide Complet
|
|
98
|
+
text: 'Guide Complet: Comment Utiliser la Loi de Dolbear pour Calculer la Température',
|
|
99
99
|
level: 2,
|
|
100
100
|
},
|
|
101
101
|
{
|
|
@@ -109,12 +109,12 @@ export const content: ToolLocaleContent<CricketThermometerUI> = {
|
|
|
109
109
|
},
|
|
110
110
|
{
|
|
111
111
|
type: 'title',
|
|
112
|
-
text: 'La Science
|
|
112
|
+
text: 'La Science: Ectothermie et Métabolisme',
|
|
113
113
|
level: 3,
|
|
114
114
|
},
|
|
115
115
|
{
|
|
116
116
|
type: 'paragraph',
|
|
117
|
-
html: 'Contrairement aux mammifères, qui maintiennent une température corporelle constante, les insectes dépendent de la chaleur externe. Leurs réactions biochimiques suivent l\'<strong>Équation d\'Arrhenius</strong
|
|
117
|
+
html: 'Contrairement aux mammifères, qui maintiennent une température corporelle constante, les insectes dépendent de la chaleur externe. Leurs réactions biochimiques suivent l\'<strong>Équation d\'Arrhenius</strong>: plus il fait chaud, plus la réaction est rapide.',
|
|
118
118
|
},
|
|
119
119
|
{
|
|
120
120
|
type: 'paragraph',
|
|
@@ -136,7 +136,7 @@ export const content: ToolLocaleContent<CricketThermometerUI> = {
|
|
|
136
136
|
},
|
|
137
137
|
{
|
|
138
138
|
type: 'paragraph',
|
|
139
|
-
html: 'Notre outil fait cela automatiquement
|
|
139
|
+
html: 'Notre outil fait cela automatiquement: il mesure le temps entre vos tapotements, calcule les stridulations par minute (BPM) et applique la formule instantanément.',
|
|
140
140
|
},
|
|
141
141
|
{
|
|
142
142
|
type: 'title',
|
|
@@ -162,8 +162,8 @@ export const content: ToolLocaleContent<CricketThermometerUI> = {
|
|
|
162
162
|
labelTapping: 'Continuez à tapoter...',
|
|
163
163
|
tapInstruction: 'Chaque fois que vous entendez une stridulation',
|
|
164
164
|
btnReset: 'Réinitialiser',
|
|
165
|
-
btnSoundOn: 'Son
|
|
166
|
-
btnSoundOff: 'Son
|
|
165
|
+
btnSoundOn: 'Son: On',
|
|
166
|
+
btnSoundOff: 'Son: Off',
|
|
167
167
|
unitChirpsMin: 'strid./min',
|
|
168
168
|
},
|
|
169
169
|
};
|
|
@@ -4,7 +4,7 @@ import type { ToolLocaleContent } from '../../../types';
|
|
|
4
4
|
import type { CricketThermometerUI } from '../ui';
|
|
5
5
|
|
|
6
6
|
const slug = 'termometer-jangkrik';
|
|
7
|
-
const title = 'Termometer Jangkrik
|
|
7
|
+
const title = 'Termometer Jangkrik: Kalkulator Suhu Hukum Dolbear';
|
|
8
8
|
const description =
|
|
9
9
|
'Tidak ada termometer? Dengarkan jangkrik. Hitung suhu tepat dengan menghitung kerikan menggunakan kalkulator Hukum Dolbear kami.';
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ import type { ToolLocaleContent } from '../../../types';
|
|
|
4
4
|
import type { CricketThermometerUI } from '../ui';
|
|
5
5
|
|
|
6
6
|
const slug = 'termometro-a-grillo';
|
|
7
|
-
const title = 'Termometro a Grillo
|
|
7
|
+
const title = 'Termometro a Grillo: Calcolatore della Temperatura via Legge di Dolbear';
|
|
8
8
|
const description =
|
|
9
9
|
'Senza termometro? Ascolta i grilli. Calcola la temperatura esatta contando i friniti con il nostro calcolatore basato sulla Legge di Dolbear.';
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ import type { ToolLocaleContent } from '../../../types';
|
|
|
4
4
|
import type { CricketThermometerUI } from '../ui';
|
|
5
5
|
|
|
6
6
|
const slug = 'cricket-thermometer';
|
|
7
|
-
const title = '
|
|
7
|
+
const title = 'コオロギ温度計: ドルベアの法則による温度計算機';
|
|
8
8
|
const description =
|
|
9
9
|
'温度計がない?そんな時はコオロギの声を聞きましょう。ドルベアの法則に基づき、鳴き声を数えるだけで正確な温度を算出します。';
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ import type { ToolLocaleContent } from '../../../types';
|
|
|
4
4
|
import type { CricketThermometerUI } from '../ui';
|
|
5
5
|
|
|
6
6
|
const slug = 'cricket-thermometer';
|
|
7
|
-
const title = '귀뚜라미
|
|
7
|
+
const title = '귀뚜라미 온도계: 돌베어 법칙 온도 계산기';
|
|
8
8
|
const description =
|
|
9
9
|
'온도계가 없으신가요? 귀뚜라미 소리에 귀를 기울여 보세요. 돌베어 법칙 계산기를 사용하여 귀뚜라미 울음소리 횟수로 정확한 온도를 계산할 수 있습니다.';
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ import type { ToolLocaleContent } from '../../../types';
|
|
|
4
4
|
import type { CricketThermometerUI } from '../ui';
|
|
5
5
|
|
|
6
6
|
const slug = 'krekels-thermometer';
|
|
7
|
-
const title = 'Krekels thermometer
|
|
7
|
+
const title = 'Krekels thermometer: Dolbears wet temperatuurcalculator';
|
|
8
8
|
const description =
|
|
9
9
|
'Geen thermometer? Luister naar de krekels. Bereken de exacte temperatuur door het aantal tsjirpen te tellen met onze Dolbears wet calculator.';
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ import type { ToolLocaleContent } from '../../../types';
|
|
|
4
4
|
import type { CricketThermometerUI } from '../ui';
|
|
5
5
|
|
|
6
6
|
const slug = 'termometr-swierszczy';
|
|
7
|
-
const title = 'Termometr świerszczowy
|
|
7
|
+
const title = 'Termometr świerszczowy: Kalkulator temperatury według prawa Dolbeara';
|
|
8
8
|
const description =
|
|
9
9
|
'Nie masz termometru? Posłuchaj świerszczy. Oblicz dokładną temperaturę, licząc cykania za pomocą naszego kalkulatora opartego na prawie Dolbeara.';
|
|
10
10
|
|
|
@@ -104,8 +104,8 @@ export const content: ToolLocaleContent<CricketThermometerUI> = {
|
|
|
104
104
|
},
|
|
105
105
|
{
|
|
106
106
|
type: 'tip',
|
|
107
|
-
title: 'Dlaczego świerszcze
|
|
108
|
-
html: '<p
|
|
107
|
+
title: 'Dlaczego świerszcze "śpiewają"?',
|
|
108
|
+
html: '<p>"Śpiew" świerszcza, czyli <strong>strydulacja</strong>, to w rzeczywistości wołanie godowe. Samce pocierają o siebie skrzydła (nie nogi), aby wydać ten dźwięk. Co ciekawe, ponieważ są to zwierzęta zmiennocieplne (ektotermy), szybkość tego pocierania zależy bezpośrednio od energii cieplnej powietrza.</p>',
|
|
109
109
|
},
|
|
110
110
|
{
|
|
111
111
|
type: 'title',
|
|
@@ -146,7 +146,7 @@ export const content: ToolLocaleContent<CricketThermometerUI> = {
|
|
|
146
146
|
{
|
|
147
147
|
type: 'list',
|
|
148
148
|
items: [
|
|
149
|
-
'<strong>Termometry miłości:</strong> Niektóre teorie sugerują, że samice wolą samców śpiewających z
|
|
149
|
+
'<strong>Termometry miłości:</strong> Niektóre teorie sugerują, że samice wolą samców śpiewających z "właściwą" częstotliwością dla aktualnej temperatury, ponieważ świadczy to o zdrowiu samca i silnym metabolizmie.',
|
|
150
150
|
'<strong>Granica zimna:</strong> Poniżej 10°C (50°F) większość świerszczy przestaje śpiewać, ponieważ ich metabolizm jest zbyt wolny, by podtrzymać wysiłek mięśni.',
|
|
151
151
|
'<strong>Synchronizacja:</strong> W ciepłe noce tysiące świerszczy potrafią zsynchronizować swoje cykanie, tworząc imponujący efekt fali dźwiękowej.',
|
|
152
152
|
],
|
|
@@ -4,7 +4,7 @@ import type { ToolLocaleContent } from '../../../types';
|
|
|
4
4
|
import type { CricketThermometerUI } from '../ui';
|
|
5
5
|
|
|
6
6
|
const slug = 'termometro-grilo';
|
|
7
|
-
const title = 'Termómetro de Grilo
|
|
7
|
+
const title = 'Termómetro de Grilo: Calculadora de Temperatura da Lei de Dolbear';
|
|
8
8
|
const description =
|
|
9
9
|
'Sem termómetro? Ouça os grilos. Calcule a temperatura exata contando os cri-cris com a nossa calculadora da Lei de Dolbear.';
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ import type { ToolLocaleContent } from '../../../types';
|
|
|
4
4
|
import type { CricketThermometerUI } from '../ui';
|
|
5
5
|
|
|
6
6
|
const slug = 'sverchkovyy-termometr';
|
|
7
|
-
const title = 'Сверчковый
|
|
7
|
+
const title = 'Сверчковый термометр: Калькулятор температуры по закону Долбера';
|
|
8
8
|
const description =
|
|
9
9
|
'Нет термометра? Послушайте сверчков. Рассчитайте точную температуру, подсчитав количество стрекотаний с помощью нашего калькулятора закона Долбера.';
|
|
10
10
|
|
|
@@ -17,7 +17,7 @@ const faqData = [
|
|
|
17
17
|
{
|
|
18
18
|
question: 'Почему в жару сверчки стрекочут быстрее?',
|
|
19
19
|
answer:
|
|
20
|
-
'Сверчки
|
|
20
|
+
'Сверчки - холоднокровные животные (эктотермы). Скорость их метаболических процессов и мышечных сокращений зависит от внешней температуры; чем теплее, тем больше у них энергии для быстрого издания звуков.',
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
question: 'Насколько точны эти измерения?',
|
|
@@ -104,8 +104,8 @@ export const content: ToolLocaleContent<CricketThermometerUI> = {
|
|
|
104
104
|
},
|
|
105
105
|
{
|
|
106
106
|
type: 'tip',
|
|
107
|
-
title: 'Почему сверчки
|
|
108
|
-
html: '<p
|
|
107
|
+
title: 'Почему сверчки "поют"?',
|
|
108
|
+
html: '<p>"Песня" сверчка, или <strong>стридуляция</strong>, на самом деле является брачным зовом. Самцы трут крыльями (не ногами) друг о друга, чтобы создать этот звук. Удивительно, но так как они являются холоднокровными животными (эктотермами), скорость этого трения напрямую зависит от тепловой энергии воздуха.</p>',
|
|
109
109
|
},
|
|
110
110
|
{
|
|
111
111
|
type: 'title',
|
|
@@ -146,9 +146,9 @@ export const content: ToolLocaleContent<CricketThermometerUI> = {
|
|
|
146
146
|
{
|
|
147
147
|
type: 'list',
|
|
148
148
|
items: [
|
|
149
|
-
'<strong>Термометры любви:</strong> Некоторые теории предполагают, что самки предпочитают самцов, которые поют на
|
|
149
|
+
'<strong>Термометры любви:</strong> Некоторые теории предполагают, что самки предпочитают самцов, которые поют на "правильной" частоте для текущей температуры, так как это указывает на то, что самец здоров и имеет сильный метаболизм.',
|
|
150
150
|
'<strong>Предел холода:</strong> Ниже 10°C (50°F) большинство сверчков перестают петь, потому что их метаболизм слишком медленный для поддержания мышечного усилия.',
|
|
151
|
-
'<strong>Синхронизация:</strong> Теплыми ночами тысячи сверчков могут синхронизировать свое стрекотание, создавая впечатляющий звуковой эффект
|
|
151
|
+
'<strong>Синхронизация:</strong> Теплыми ночами тысячи сверчков могут синхронизировать свое стрекотание, создавая впечатляющий звуковой эффект "волны".',
|
|
152
152
|
],
|
|
153
153
|
},
|
|
154
154
|
{
|
|
@@ -4,7 +4,7 @@ import type { ToolLocaleContent } from '../../../types';
|
|
|
4
4
|
import type { CricketThermometerUI } from '../ui';
|
|
5
5
|
|
|
6
6
|
const slug = 'syrstermometer';
|
|
7
|
-
const title = 'Syrstermometer
|
|
7
|
+
const title = 'Syrstermometer: Dolbears lag temperaturkalkylator';
|
|
8
8
|
const description =
|
|
9
9
|
'Ingen termometer? Lyssna på syrsorna. Beräkna exakt temperatur genom att räkna spelningar med vår kalkylator för Dolbears lag.';
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ import type { ToolLocaleContent } from '../../../types';
|
|
|
4
4
|
import type { CricketThermometerUI } from '../ui';
|
|
5
5
|
|
|
6
6
|
const slug = 'cricket-termometer';
|
|
7
|
-
const title = 'Cırcır Böceği Termometresi
|
|
7
|
+
const title = 'Cırcır Böceği Termometresi: Dolbear Yasası Sıcaklık Hesaplayıcı';
|
|
8
8
|
const description =
|
|
9
9
|
'Termometreniz mi yok? Cırcır böceklerini dinleyin. Dolbear Yasası hesaplayıcımızla ötüşleri sayarak tam sıcaklığı hesaplayın.';
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ import type { ToolLocaleContent } from '../../../types';
|
|
|
4
4
|
import type { CricketThermometerUI } from '../ui';
|
|
5
5
|
|
|
6
6
|
const slug = 'cricket-thermometer';
|
|
7
|
-
const title = '
|
|
7
|
+
const title = '蟋蟀温度计: 杜倍耳定律温度计算器';
|
|
8
8
|
const description =
|
|
9
9
|
'没有温度计?听听蟋蟀的声音。使用我们的杜倍耳定律计算器,通过计算鸣叫次数来得出准确温度。';
|
|
10
10
|
|
|
@@ -42,7 +42,7 @@ const howToData = [
|
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
44
|
name: '输入数值',
|
|
45
|
-
text: '
|
|
45
|
+
text: '跟随鸣叫节奏点击"TAP"按钮几秒钟,计算器会自动计算 BPM(每分钟鸣叫次数)。',
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
48
|
name: '验证温度',
|
|
@@ -104,8 +104,8 @@ export const content: ToolLocaleContent<CricketThermometerUI> = {
|
|
|
104
104
|
},
|
|
105
105
|
{
|
|
106
106
|
type: 'tip',
|
|
107
|
-
title: '
|
|
108
|
-
html: '<p
|
|
107
|
+
title: '蟋蟀为什么要"唱歌"?',
|
|
108
|
+
html: '<p>蟋蟀的"歌声",即<strong>摩擦发声</strong>,实际上是一种求偶信号。公蟋蟀通过摩擦双翅(而不是腿)来发出这种声音。令人着迷的是,由于它们是冷血动物(变温动物),这种摩擦的速度直接取决于空气的热能。</p>',
|
|
109
109
|
},
|
|
110
110
|
{
|
|
111
111
|
type: 'title',
|
|
@@ -146,9 +146,9 @@ export const content: ToolLocaleContent<CricketThermometerUI> = {
|
|
|
146
146
|
{
|
|
147
147
|
type: 'list',
|
|
148
148
|
items: [
|
|
149
|
-
'<strong>爱情温度计:</strong>
|
|
149
|
+
'<strong>爱情温度计:</strong> 一些理论认为,母蟋蟀更喜欢在当前温度下以"正确"频率唱歌的公蟋蟀,因为这表明该公蟋蟀身体健康且代谢强健。',
|
|
150
150
|
'<strong>寒冷极限:</strong> 低于 10°C (50°F) 时,大多数蟋蟀会停止唱歌,因为它们的代谢太慢,无法维持肌肉输出。',
|
|
151
|
-
'<strong>同步鸣叫:</strong>
|
|
151
|
+
'<strong>同步鸣叫:</strong> 在温暖的夜晚,成千上万只蟋蟀可以同步鸣叫,产生令人印象深刻的"声波"效果。',
|
|
152
152
|
],
|
|
153
153
|
},
|
|
154
154
|
{
|
|
@@ -95,6 +95,7 @@
|
|
|
95
95
|
|
|
96
96
|
.dc-input {
|
|
97
97
|
flex: 1;
|
|
98
|
+
min-width: 0;
|
|
98
99
|
background: transparent;
|
|
99
100
|
border: none;
|
|
100
101
|
padding: 0.75rem 1rem;
|
|
@@ -339,4 +340,59 @@
|
|
|
339
340
|
opacity: 0.05;
|
|
340
341
|
color: var(--dc-accent);
|
|
341
342
|
pointer-events: none;
|
|
342
|
-
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
@media (max-width: 640px) {
|
|
346
|
+
.dc-wrap {
|
|
347
|
+
padding: 0.75rem;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.dc-container {
|
|
351
|
+
border-radius: 1.25rem;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.dc-inputs,
|
|
355
|
+
.dc-results-grid,
|
|
356
|
+
.dc-sidebar {
|
|
357
|
+
padding: 1.25rem;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.dc-section-head {
|
|
361
|
+
align-items: flex-start;
|
|
362
|
+
font-size: 1.25rem;
|
|
363
|
+
margin-bottom: 1.5rem;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.dc-search-box {
|
|
367
|
+
flex-direction: column;
|
|
368
|
+
gap: 0.75rem;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.dc-input {
|
|
372
|
+
width: 100%;
|
|
373
|
+
font-size: 1rem;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.dc-btn-primary {
|
|
377
|
+
width: 100%;
|
|
378
|
+
min-width: 0;
|
|
379
|
+
min-height: 3rem;
|
|
380
|
+
padding: 0.75rem 1rem;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.dc-result-card.main,
|
|
384
|
+
.dc-impact-items,
|
|
385
|
+
.dc-stats-grid {
|
|
386
|
+
grid-template-columns: 1fr;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.dc-result-card.main {
|
|
390
|
+
align-items: flex-start;
|
|
391
|
+
gap: 1rem;
|
|
392
|
+
padding: 1.25rem;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.dc-stat-item.full {
|
|
396
|
+
grid-column: auto;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
@@ -143,7 +143,7 @@ export const content: DigitalCarbonLocaleContent = {
|
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
type: 'paragraph',
|
|
146
|
-
html: 'Der <strong>digitale CO₂-Fußabdruck</strong> einer Website wird in Gramm CO₂-Äquivalent (gCO₂e) pro Besuch gemessen. Eine durchschnittliche Website erzeugt etwa 0,5 g CO₂ pro Ladevorgang. Obwohl das unbedeutend scheint, kann eine Seite mit 100.000 monatlichen Besuchen mehr als 600 kg CO₂ pro Jahr emittieren
|
|
146
|
+
html: 'Der <strong>digitale CO₂-Fußabdruck</strong> einer Website wird in Gramm CO₂-Äquivalent (gCO₂e) pro Besuch gemessen. Eine durchschnittliche Website erzeugt etwa 0,5 g CO₂ pro Ladevorgang. Obwohl das unbedeutend scheint, kann eine Seite mit 100.000 monatlichen Besuchen mehr als 600 kg CO₂ pro Jahr emittieren - was einer Fahrt von mehr als 3.000 km mit einem Benziner entspricht.',
|
|
147
147
|
},
|
|
148
148
|
{
|
|
149
149
|
type: 'title',
|
|
@@ -221,7 +221,7 @@ export const content: DigitalCarbonLocaleContent = {
|
|
|
221
221
|
},
|
|
222
222
|
{
|
|
223
223
|
type: 'paragraph',
|
|
224
|
-
html: 'Das Internet macht zwischen <strong>2 % und 4 % der weltweiten CO₂-Emissionen</strong> aus
|
|
224
|
+
html: 'Das Internet macht zwischen <strong>2 % und 4 % der weltweiten CO₂-Emissionen</strong> aus - ein Wert, der mit der Luftfahrtindustrie vergleichbar ist. Jedes Kilobyte, das Sie einsparen, macht nicht nur Ihre Website schneller: Es reduziert messbar die digitale Verschmutzung.',
|
|
225
225
|
},
|
|
226
226
|
],
|
|
227
227
|
bibliography,
|
|
@@ -21,7 +21,7 @@ const faqData = [
|
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
question: 'Comment réduire le CO₂ de mon site web ?',
|
|
24
|
-
answer: 'Le moyen le plus efficace est de réduire le poids de la page
|
|
24
|
+
answer: 'Le moyen le plus efficace est de réduire le poids de la page: optimisez les images (WebP), minimisez les fichiers CSS y JS, utilisez le chargement différé (lazy loading) y choisissez un hébergeur utilisant des énergies renouvelables.',
|
|
25
25
|
},
|
|
26
26
|
];
|
|
27
27
|
|
|
@@ -125,7 +125,7 @@ export const content: DigitalCarbonLocaleContent = {
|
|
|
125
125
|
seo: [
|
|
126
126
|
{
|
|
127
127
|
type: 'title',
|
|
128
|
-
text: 'Calculateur d\'empreinte carbone numérique
|
|
128
|
+
text: 'Calculateur d\'empreinte carbone numérique: Quel est le CO₂ généré par votre site',
|
|
129
129
|
level: 2,
|
|
130
130
|
},
|
|
131
131
|
{
|
|
@@ -139,7 +139,7 @@ export const content: DigitalCarbonLocaleContent = {
|
|
|
139
139
|
},
|
|
140
140
|
{
|
|
141
141
|
type: 'paragraph',
|
|
142
|
-
html: 'Chaque fois que vous ouvrez une page web, votre appareil, votre routeur, les câbles sous-marins et les serveurs à l\'autre bout du monde consomment de l\'électricité. Cette électricité est encore largement générée par la combustion d\'énergies fossiles. Résultat
|
|
142
|
+
html: 'Chaque fois que vous ouvrez une page web, votre appareil, votre routeur, les câbles sous-marins et les serveurs à l\'autre bout du monde consomment de l\'électricité. Cette électricité est encore largement générée par la combustion d\'énergies fossiles. Résultat: une quantité réelle de <strong>CO₂ émise dans l\'atmosphère à chaque visite</strong>.',
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
type: 'paragraph',
|
|
@@ -221,7 +221,7 @@ export const content: DigitalCarbonLocaleContent = {
|
|
|
221
221
|
},
|
|
222
222
|
{
|
|
223
223
|
type: 'paragraph',
|
|
224
|
-
html: 'Internet représente entre <strong>2% et 4% des émissions mondiales de CO₂</strong>, un chiffre comparable à l\'industrie aéronautique. Chaque kilo-octet éliminé ne rend pas seulement votre site plus rapide
|
|
224
|
+
html: 'Internet représente entre <strong>2% et 4% des émissions mondiales de CO₂</strong>, un chiffre comparable à l\'industrie aéronautique. Chaque kilo-octet éliminé ne rend pas seulement votre site plus rapide: il réduit de manière mesurable la pollution numérique.',
|
|
225
225
|
},
|
|
226
226
|
],
|
|
227
227
|
bibliography,
|
|
@@ -21,7 +21,7 @@ const faqData = [
|
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
question: 'Как я могу уменьшить выбросы CO₂ моего сайта?',
|
|
24
|
-
answer: 'Самый эффективный способ
|
|
24
|
+
answer: 'Самый эффективный способ - уменьшить вес страницы: оптимизировать изображения (WebP), минифицировать файлы CSS и JS, использовать ленивую загрузку и выбрать хостинг-провайдера, использующего возобновляемую энергию.',
|
|
25
25
|
},
|
|
26
26
|
];
|
|
27
27
|
|
|
@@ -9,7 +9,7 @@ const description = 'Berechnen Sie, wie viel Regenwasser Sie von Ihrem Dach samm
|
|
|
9
9
|
const faqData = [
|
|
10
10
|
{
|
|
11
11
|
question: 'Wie viel Wasser kann ich tatsächlich von meinem Dach sammeln?',
|
|
12
|
-
answer: 'Als Faustregel gilt: Pro Quadratmeter Dachfläche und Millimeter Regen können Sie etwa 1 Liter Wasser sammeln. Es entstehen jedoch Verluste durch Verdunstung und Filtration, die mit dem
|
|
12
|
+
answer: 'Als Faustregel gilt: Pro Quadratmeter Dachfläche und Millimeter Regen können Sie etwa 1 Liter Wasser sammeln. Es entstehen jedoch Verluste durch Verdunstung und Filtration, die mit dem "Abflussbeiwert" angepasst werden.',
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
question: 'Was ist der Abflussbeiwert?',
|
|
@@ -91,7 +91,7 @@ export const content: RainHarvesterLocaleContent = {
|
|
|
91
91
|
unitM2: 'm²',
|
|
92
92
|
unitMm: 'mm',
|
|
93
93
|
unitLiters: 'Liter',
|
|
94
|
-
helpRainfall: 'Unbekannt? Suchen Sie bei Google nach
|
|
94
|
+
helpRainfall: 'Unbekannt? Suchen Sie bei Google nach "durchschnittlicher jährlicher Niederschlag [Ihre Stadt]".',
|
|
95
95
|
efficiencyTitle: 'Effizienzfaktor',
|
|
96
96
|
efficiencyNote: 'Für Filter und Verdunstung wird ein Verlust von 10 % angesetzt.',
|
|
97
97
|
resultTitle: 'Jährliches Erntepotenzial',
|
|
@@ -113,7 +113,7 @@ export const content: RainHarvesterLocaleContent = {
|
|
|
113
113
|
},
|
|
114
114
|
{
|
|
115
115
|
type: 'paragraph',
|
|
116
|
-
html: 'Die meisten Hausbesitzer sind sich des Potenzials ihres eigenen Daches nicht bewusst. Ein Standarddach kann jedes Jahr Tausende Liter kostenloses Wasser auffangen. Dieses Tool quantifiziert dieses Potenzial, sodass Sie genau berechnen können, wie viel Wasser Sie
|
|
116
|
+
html: 'Die meisten Hausbesitzer sind sich des Potenzials ihres eigenen Daches nicht bewusst. Ein Standarddach kann jedes Jahr Tausende Liter kostenloses Wasser auffangen. Dieses Tool quantifiziert dieses Potenzial, sodass Sie genau berechnen können, wie viel Wasser Sie "ernten" können, und die ideale Tankgröße für die Speicherung bestimmen können.',
|
|
117
117
|
},
|
|
118
118
|
{
|
|
119
119
|
type: 'title',
|
|
@@ -126,7 +126,7 @@ export const content: RainHarvesterLocaleContent = {
|
|
|
126
126
|
},
|
|
127
127
|
{
|
|
128
128
|
type: 'paragraph',
|
|
129
|
-
html: '<code style="display:block;padding:1rem;background:var(
|
|
129
|
+
html: '<code style="display:block;padding:1rem;background:var(-bg-alt);border-radius:0.5rem;margin:1rem 0;font-family:monospace;">Volumen = Fläche × Niederschlag × Abflussbeiwert × Filtereffizienz</code>',
|
|
130
130
|
},
|
|
131
131
|
{
|
|
132
132
|
type: 'list',
|
|
@@ -126,7 +126,7 @@ export const content: RainHarvesterLocaleContent = {
|
|
|
126
126
|
},
|
|
127
127
|
{
|
|
128
128
|
type: 'paragraph',
|
|
129
|
-
html: '<code style="display:block;padding:1rem;background:var(
|
|
129
|
+
html: '<code style="display:block;padding:1rem;background:var(-bg-alt);border-radius:0.5rem;margin:1rem 0;font-family:monospace;">Volume = Area × Rainfall × Runoff Coefficient × Filter Efficiency</code>',
|
|
130
130
|
},
|
|
131
131
|
{
|
|
132
132
|
type: 'list',
|
|
@@ -126,7 +126,7 @@ export const content: RainHarvesterLocaleContent = {
|
|
|
126
126
|
},
|
|
127
127
|
{
|
|
128
128
|
type: 'paragraph',
|
|
129
|
-
html: '<code style="display:block;padding:1rem;background:var(
|
|
129
|
+
html: '<code style="display:block;padding:1rem;background:var(-bg-alt);border-radius:0.5rem;margin:1rem 0;font-family:monospace;">Volumen = Área × Precipitación × Coeficiente de Escorrentía × Eficiencia del Filtro</code>',
|
|
130
130
|
},
|
|
131
131
|
{
|
|
132
132
|
type: 'list',
|
|
@@ -108,7 +108,7 @@ export const content: RainHarvesterLocaleContent = {
|
|
|
108
108
|
seo: [
|
|
109
109
|
{
|
|
110
110
|
type: 'title',
|
|
111
|
-
text: 'Récupération de l\'eau de pluie
|
|
111
|
+
text: 'Récupération de l\'eau de pluie: Autonomie et durabilité',
|
|
112
112
|
level: 2,
|
|
113
113
|
},
|
|
114
114
|
{
|
|
@@ -126,7 +126,7 @@ export const content: RainHarvesterLocaleContent = {
|
|
|
126
126
|
},
|
|
127
127
|
{
|
|
128
128
|
type: 'paragraph',
|
|
129
|
-
html: '<code style="display:block;padding:1rem;background:var(
|
|
129
|
+
html: '<code style="display:block;padding:1rem;background:var(-bg-alt);border-radius:0.5rem;margin:1rem 0;font-family:monospace;">Volume = Surface × Précipitations × Coefficient de Ruissellement × Efficacité du Filtre</code>',
|
|
130
130
|
},
|
|
131
131
|
{
|
|
132
132
|
type: 'list',
|
|
@@ -126,7 +126,7 @@ export const content: RainHarvesterLocaleContent = {
|
|
|
126
126
|
},
|
|
127
127
|
{
|
|
128
128
|
type: 'paragraph',
|
|
129
|
-
html: '<code style="display:block;padding:1rem;background:var(
|
|
129
|
+
html: '<code style="display:block;padding:1rem;background:var(-bg-alt);border-radius:0.5rem;margin:1rem 0;font-family:monospace;">Volume = Luas × Curah Hujan × Koefisien Limpasan × Efisiensi Filter</code>',
|
|
130
130
|
},
|
|
131
131
|
{
|
|
132
132
|
type: 'list',
|
|
@@ -126,7 +126,7 @@ export const content: RainHarvesterLocaleContent = {
|
|
|
126
126
|
},
|
|
127
127
|
{
|
|
128
128
|
type: 'paragraph',
|
|
129
|
-
html: '<code style="display:block;padding:1rem;background:var(
|
|
129
|
+
html: '<code style="display:block;padding:1rem;background:var(-bg-alt);border-radius:0.5rem;margin:1rem 0;font-family:monospace;">Volume = Area × Precipitazioni × Coefficiente di Deflusso × Efficienza Filtro</code>',
|
|
130
130
|
},
|
|
131
131
|
{
|
|
132
132
|
type: 'list',
|