@jjlmoya/utils-science 1.9.0 → 1.11.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 (100) hide show
  1. package/package.json +63 -62
  2. package/src/category/i18n/de.ts +96 -0
  3. package/src/category/i18n/id.ts +96 -0
  4. package/src/category/i18n/it.ts +96 -0
  5. package/src/category/i18n/ja.ts +96 -0
  6. package/src/category/i18n/ko.ts +96 -0
  7. package/src/category/i18n/nl.ts +96 -0
  8. package/src/category/i18n/pl.ts +96 -0
  9. package/src/category/i18n/pt.ts +96 -0
  10. package/src/category/i18n/ru.ts +96 -0
  11. package/src/category/i18n/sv.ts +96 -0
  12. package/src/category/i18n/tr.ts +96 -0
  13. package/src/category/i18n/zh.ts +96 -0
  14. package/src/category/index.ts +12 -0
  15. package/src/tests/i18n_coverage.test.ts +36 -0
  16. package/src/tests/locale_completeness.test.ts +2 -2
  17. package/src/tests/schemas_fulfillment.test.ts +23 -0
  18. package/src/tests/slug_uniqueness.test.ts +81 -0
  19. package/src/tests/title_quality.test.ts +55 -0
  20. package/src/tool/asteroid-impact/component.astro +1 -1
  21. package/src/tool/asteroid-impact/i18n/de.ts +194 -0
  22. package/src/tool/asteroid-impact/i18n/en.ts +75 -38
  23. package/src/tool/asteroid-impact/i18n/es.ts +75 -38
  24. package/src/tool/asteroid-impact/i18n/fr.ts +75 -38
  25. package/src/tool/asteroid-impact/i18n/id.ts +194 -0
  26. package/src/tool/asteroid-impact/i18n/it.ts +194 -0
  27. package/src/tool/asteroid-impact/i18n/ja.ts +194 -0
  28. package/src/tool/asteroid-impact/i18n/ko.ts +194 -0
  29. package/src/tool/asteroid-impact/i18n/nl.ts +194 -0
  30. package/src/tool/asteroid-impact/i18n/pl.ts +194 -0
  31. package/src/tool/asteroid-impact/i18n/pt.ts +194 -0
  32. package/src/tool/asteroid-impact/i18n/ru.ts +194 -0
  33. package/src/tool/asteroid-impact/i18n/sv.ts +194 -0
  34. package/src/tool/asteroid-impact/i18n/tr.ts +194 -0
  35. package/src/tool/asteroid-impact/i18n/zh.ts +194 -0
  36. package/src/tool/asteroid-impact/index.ts +13 -1
  37. package/src/tool/cellular-renewal/i18n/de.ts +207 -0
  38. package/src/tool/cellular-renewal/i18n/en.ts +83 -46
  39. package/src/tool/cellular-renewal/i18n/es.ts +83 -46
  40. package/src/tool/cellular-renewal/i18n/fr.ts +83 -46
  41. package/src/tool/cellular-renewal/i18n/id.ts +207 -0
  42. package/src/tool/cellular-renewal/i18n/it.ts +207 -0
  43. package/src/tool/cellular-renewal/i18n/ja.ts +207 -0
  44. package/src/tool/cellular-renewal/i18n/ko.ts +207 -0
  45. package/src/tool/cellular-renewal/i18n/nl.ts +207 -0
  46. package/src/tool/cellular-renewal/i18n/pl.ts +207 -0
  47. package/src/tool/cellular-renewal/i18n/pt.ts +207 -0
  48. package/src/tool/cellular-renewal/i18n/ru.ts +207 -0
  49. package/src/tool/cellular-renewal/i18n/sv.ts +207 -0
  50. package/src/tool/cellular-renewal/i18n/tr.ts +207 -0
  51. package/src/tool/cellular-renewal/i18n/zh.ts +207 -0
  52. package/src/tool/cellular-renewal/index.ts +13 -1
  53. package/src/tool/colony-counter/i18n/de.ts +185 -0
  54. package/src/tool/colony-counter/i18n/en.ts +69 -35
  55. package/src/tool/colony-counter/i18n/es.ts +69 -35
  56. package/src/tool/colony-counter/i18n/fr.ts +69 -35
  57. package/src/tool/colony-counter/i18n/id.ts +185 -0
  58. package/src/tool/colony-counter/i18n/it.ts +185 -0
  59. package/src/tool/colony-counter/i18n/ja.ts +185 -0
  60. package/src/tool/colony-counter/i18n/ko.ts +185 -0
  61. package/src/tool/colony-counter/i18n/nl.ts +185 -0
  62. package/src/tool/colony-counter/i18n/pl.ts +185 -0
  63. package/src/tool/colony-counter/i18n/pt.ts +185 -0
  64. package/src/tool/colony-counter/i18n/ru.ts +185 -0
  65. package/src/tool/colony-counter/i18n/sv.ts +185 -0
  66. package/src/tool/colony-counter/i18n/tr.ts +185 -0
  67. package/src/tool/colony-counter/i18n/zh.ts +185 -0
  68. package/src/tool/colony-counter/index.ts +12 -0
  69. package/src/tool/microwave-detector/i18n/de.ts +204 -0
  70. package/src/tool/microwave-detector/i18n/en.ts +75 -38
  71. package/src/tool/microwave-detector/i18n/es.ts +75 -38
  72. package/src/tool/microwave-detector/i18n/fr.ts +75 -38
  73. package/src/tool/microwave-detector/i18n/id.ts +204 -0
  74. package/src/tool/microwave-detector/i18n/it.ts +204 -0
  75. package/src/tool/microwave-detector/i18n/ja.ts +204 -0
  76. package/src/tool/microwave-detector/i18n/ko.ts +204 -0
  77. package/src/tool/microwave-detector/i18n/nl.ts +204 -0
  78. package/src/tool/microwave-detector/i18n/pl.ts +204 -0
  79. package/src/tool/microwave-detector/i18n/pt.ts +204 -0
  80. package/src/tool/microwave-detector/i18n/ru.ts +204 -0
  81. package/src/tool/microwave-detector/i18n/sv.ts +204 -0
  82. package/src/tool/microwave-detector/i18n/tr.ts +204 -0
  83. package/src/tool/microwave-detector/i18n/zh.ts +204 -0
  84. package/src/tool/microwave-detector/index.ts +13 -1
  85. package/src/tool/simulation-probability/i18n/de.ts +226 -0
  86. package/src/tool/simulation-probability/i18n/en.ts +79 -42
  87. package/src/tool/simulation-probability/i18n/es.ts +79 -42
  88. package/src/tool/simulation-probability/i18n/fr.ts +79 -42
  89. package/src/tool/simulation-probability/i18n/id.ts +226 -0
  90. package/src/tool/simulation-probability/i18n/it.ts +226 -0
  91. package/src/tool/simulation-probability/i18n/ja.ts +226 -0
  92. package/src/tool/simulation-probability/i18n/ko.ts +226 -0
  93. package/src/tool/simulation-probability/i18n/nl.ts +226 -0
  94. package/src/tool/simulation-probability/i18n/pl.ts +226 -0
  95. package/src/tool/simulation-probability/i18n/pt.ts +226 -0
  96. package/src/tool/simulation-probability/i18n/ru.ts +226 -0
  97. package/src/tool/simulation-probability/i18n/sv.ts +226 -0
  98. package/src/tool/simulation-probability/i18n/tr.ts +226 -0
  99. package/src/tool/simulation-probability/i18n/zh.ts +227 -0
  100. package/src/tool/simulation-probability/index.ts +13 -1
@@ -0,0 +1,96 @@
1
+ import type { CategoryLocaleContent } from '../../types';
2
+
3
+ export const content: CategoryLocaleContent = {
4
+ slug: 'science',
5
+ title: '交互式科学工具与模拟器',
6
+ description: '通过免费的在线工具探索科学。小行星撞击模拟器、细菌菌落计数、模拟概率和细胞更新计算器。',
7
+ seo: [
8
+ {
9
+ type: 'title',
10
+ text: '科学探索与模拟:掌控在手中的科学',
11
+ level: 2,
12
+ },
13
+ {
14
+ type: 'paragraph',
15
+ html: '<p>科学不仅仅是静态的知识体系,更是一个探索和实验的动态过程。在本板块中,我们提供免费的在线工具,旨在通过模拟和数据分析将复杂的科学概念带给每一位用户。从微生物学到天体物理学,我们的工具应用数学模型和物理理论,为您提供宇宙的交互式视角。</p><p>无论您是需要在实验室计数菌落形成单位,还是想估算我们生活在虚拟环境中的概率,我们的计算器都能通过为好奇心而设计的界面提供技术上的严谨性。</p>',
16
+ },
17
+ {
18
+ type: 'title',
19
+ text: '天体物理学与宇宙风险:小行星撞击',
20
+ level: 2,
21
+ },
22
+ {
23
+ type: 'paragraph',
24
+ html: '<p>宇宙浩瀚,有时也充满暴力。我们的小行星撞击模拟器使用终点弹道学和大气物理学方程来计算宇宙碰撞对地球的影响。它分析陨石坑大小、冲击波和排放的热辐射,以了解近地天体(NEO)带来的真实风险。</p>',
25
+ },
26
+ {
27
+ type: 'title',
28
+ text: '微生物学与数字实验室分析',
29
+ level: 2,
30
+ },
31
+ {
32
+ type: 'paragraph',
33
+ html: '<p>实验室工作需要精准和高效。数字菌落计数器简化了培养皿上 CFU(菌落形成单位)的计数,有助于通过基于触摸的标记界面最大限度地减少人为错误并加速细菌分析过程。</p>',
34
+ },
35
+ {
36
+ type: 'title',
37
+ text: '人类生物学与原子更新',
38
+ level: 2,
39
+ },
40
+ {
41
+ type: 'paragraph',
42
+ html: '<p>你已经不再是七年前的那个你了。细胞更新计算器根据分子生物学的最新研究,估算您体内原子和细胞的更替率。这是一个了解我们生物身份流动性的迷人工具。</p>',
43
+ },
44
+ {
45
+ type: 'title',
46
+ text: '分析哲学与模拟概率',
47
+ level: 2,
48
+ },
49
+ {
50
+ type: 'paragraph',
51
+ html: '<p>现实与计算之间是否存在界限?基于尼克·博斯特罗姆的三难困境,我们的模拟概率计算器允许您调整计算能力和文明生存变量,以估算我们的现实是人造的统计可能性。</p>',
52
+ },
53
+ {
54
+ type: 'title',
55
+ text: '家用物理与干扰检测',
56
+ level: 2,
57
+ },
58
+ {
59
+ type: 'paragraph',
60
+ html: '<p>科学也在您的厨房里。微波检测器利用 WiFi 信号强度来监测家用电器潜在的射频(RF)泄漏,应用电磁波干扰原理。</p>',
61
+ },
62
+ {
63
+ type: 'title',
64
+ text: '核心特点',
65
+ level: 2,
66
+ },
67
+ {
68
+ type: 'summary',
69
+ title: '我们的定义:',
70
+ items: [
71
+ '数学建模:基于真实物理定律(引力、热力学、弹道学)的模拟。',
72
+ '交互式教育:为学生和爱好者设计的工具,用于实验科学变量。',
73
+ '技术严谨:从科学出版物和学术数据库中提取的数据和公式。',
74
+ '科学数据隐私:所有计算和模拟过程均在本地运行,以确保您的研究安全。',
75
+ ],
76
+ },
77
+ {
78
+ type: 'title',
79
+ text: '关于科学模拟的说明',
80
+ level: 3,
81
+ },
82
+ {
83
+ type: 'paragraph',
84
+ html: '<p><strong>理论基础:</strong> 虽然我们的模拟器(如小行星撞击模拟器)使用精准的物理方程,但结果应被视为教育性估算。真实系统是混沌的,可能会受到大气和地质变量的影响,这些变量在这个简化版本中没有被建模。</p>',
85
+ },
86
+ {
87
+ type: 'title',
88
+ text: '迈向科学的民主化',
89
+ level: 2,
90
+ },
91
+ {
92
+ type: 'paragraph',
93
+ html: '<p>公众科学(Citizen Science)比以往任何时候都更加强大。获得专业级的模拟工具允许任何人验证理论或进行自己的思想实验。这些实用程序打破了传统实验室的围墙,将科学方法直接带到您的屏幕上。科学教育从被动(阅读书籍)转变为主动(数字式实验宇宙的力量)。</p>',
94
+ },
95
+ ],
96
+ };
@@ -12,6 +12,18 @@ export const scienceCategory: ScienceCategoryEntry = {
12
12
  es: () => import('./i18n/es').then((m) => m.content),
13
13
  en: () => import('./i18n/en').then((m) => m.content),
14
14
  fr: () => import('./i18n/fr').then((m) => m.content),
15
+ de: () => import('./i18n/de').then((m) => m.content),
16
+ it: () => import('./i18n/it').then((m) => m.content),
17
+ pt: () => import('./i18n/pt').then((m) => m.content),
18
+ id: () => import('./i18n/id').then((m) => m.content),
19
+ ja: () => import('./i18n/ja').then((m) => m.content),
20
+ ko: () => import('./i18n/ko').then((m) => m.content),
21
+ nl: () => import('./i18n/nl').then((m) => m.content),
22
+ pl: () => import('./i18n/pl').then((m) => m.content),
23
+ ru: () => import('./i18n/ru').then((m) => m.content),
24
+ sv: () => import('./i18n/sv').then((m) => m.content),
25
+ tr: () => import('./i18n/tr').then((m) => m.content),
26
+ zh: () => import('./i18n/zh').then((m) => m.content),
15
27
  },
16
28
  };
17
29
 
@@ -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
+ });
@@ -35,8 +35,8 @@ describe('Locale Completeness Validation', () => {
35
35
  });
36
36
  });
37
37
 
38
- it('tools are properly registered', () => {
39
- expect(ALL_TOOLS.length).toBeGreaterThan(0);
38
+ it('all 5 tools registered', () => {
39
+ expect(ALL_TOOLS.length).toBe(5);
40
40
  });
41
41
  });
42
42
 
@@ -0,0 +1,23 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { ALL_TOOLS } from '../tools';
3
+ import type { ToolLocaleContent } from '../types';
4
+
5
+ describe('Schemas Fulfillment Validation', () => {
6
+ ALL_TOOLS.forEach((tool) => {
7
+ describe(`Tool: ${tool.entry.id}`, () => {
8
+ Object.keys(tool.entry.i18n).forEach((locale) => {
9
+ it(`Locale: ${locale} should have faqSchema, appSchema and howToSchema`, async () => {
10
+ const loader = tool.entry.i18n[locale as keyof typeof tool.entry.i18n];
11
+ if (!loader) return;
12
+ const content = (await loader()) as ToolLocaleContent;
13
+
14
+ const schemaTypes = content.schemas.map((s: any) => s['@type']);
15
+
16
+ expect(schemaTypes, `Tool "${tool.entry.id}" locale "${locale}" is missing FAQPage schema`).toContain('FAQPage');
17
+ expect(schemaTypes, `Tool "${tool.entry.id}" locale "${locale}" is missing SoftwareApplication schema`).toContain('SoftwareApplication');
18
+ expect(schemaTypes, `Tool "${tool.entry.id}" locale "${locale}" is missing HowTo schema`).toContain('HowTo');
19
+ });
20
+ });
21
+ });
22
+ });
23
+ });
@@ -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
+ });
@@ -0,0 +1,55 @@
1
+ import { describe, it } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+
5
+ function getFiles(dir: string, ext: string[]): string[] {
6
+ const results: string[] = [];
7
+ if (!fs.existsSync(dir)) return results;
8
+ const list = fs.readdirSync(dir);
9
+ for (const file of list) {
10
+ const fullPath = path.join(dir, file);
11
+ const stat = fs.statSync(fullPath);
12
+ if (stat && stat.isDirectory()) {
13
+ results.push(...getFiles(fullPath, ext));
14
+ } else if (ext.some((e) => file.endsWith(e))) {
15
+ results.push(fullPath);
16
+ }
17
+ }
18
+ return results;
19
+ }
20
+
21
+ const SRC_DIR = path.join(process.cwd(), 'src');
22
+
23
+ describe('Project Titles - Separator Validation', () => {
24
+ const files = [
25
+ ...getFiles(path.join(SRC_DIR, 'tool'), ['.ts']),
26
+ ...getFiles(path.join(SRC_DIR, 'category'), ['.ts']),
27
+ ].filter(f => f.includes('i18n'));
28
+
29
+ it.each(files)('Verify that titles in %s do not contain | or -', (filePath) => {
30
+ const content = fs.readFileSync(filePath, 'utf-8');
31
+ const relativePath = path.relative(process.cwd(), filePath);
32
+
33
+ const titlePatterns = [
34
+ /const\s+title\s*=\s*['"]([^'"]+)['"]/g,
35
+ /title\s*:\s*['"]([^'"]+)['"]/g,
36
+ ];
37
+
38
+ const findings: string[] = [];
39
+
40
+ for (const pattern of titlePatterns) {
41
+ let match;
42
+ while ((match = pattern.exec(content)) !== null) {
43
+ const title = match[1];
44
+ if (title.includes('|') || title.includes('-')) {
45
+ findings.push(title);
46
+ }
47
+ }
48
+ }
49
+
50
+ if (findings.length > 0) {
51
+ const list = findings.map((f) => ` - "${f}"`).join('\n');
52
+ throw new Error(`Forbidden separators (| or -) found in titles in ${relativePath}:\n${list}`);
53
+ }
54
+ });
55
+ });
@@ -9,7 +9,6 @@ const { ui } = Astro.props;
9
9
  ---
10
10
 
11
11
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
12
- <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
13
12
 
14
13
  <div class="asteroid-app" id="asteroid-app">
15
14
  <div id="asteroid-game-map" class="asteroid-game-map" style="touch-action: none;"></div>
@@ -170,6 +169,7 @@ const { ui } = Astro.props;
170
169
  </div>
171
170
 
172
171
  <script>
172
+ import L from "leaflet";
173
173
  import { ImpactPhysics, type Composition } from "./logic/impactPhysics";
174
174
  import { VERDICT_CONFIGS } from "./constants";
175
175
  import { getCompositionColor } from "./utils";
@@ -0,0 +1,194 @@
1
+ const slug = 'asteroideneinschlag-simulator';
2
+ const description = 'Simulieren Sie Asteroideneinschläge mit realer Physik. Berechnen Sie Energie, Krater, Wärmestrahlung und Schockwelle. Würden Sie Chicxulub überleben?';
3
+ const title = 'Asteroideneinschlag Simulator: Apokalypse Rechner';
4
+ const howTo = [
5
+ {
6
+ name: 'Projektilgröße wählen',
7
+ text: 'Geben Sie den Asteroidendurchmesser ein, von einem kleinen 10-Meter-Meteoriten bis hin zu einem 10-Kilometer-Planetenkiller.',
8
+ },
9
+ {
10
+ name: 'Geschwindigkeit und Winkel konfigurieren',
11
+ text: 'Passen Sie die Annäherungsgeschwindigkeit und den Eintrittswinkel an (45° ist statistisch der wahrscheinlichste Wert).',
12
+ },
13
+ {
14
+ name: 'Natur des Asteroiden definieren',
15
+ text: 'Wählen Sie aus, ob der Asteroid aus Gestein, Eisen oder Eis besteht, um die Kratertiefe korrekt zu berechnen.',
16
+ },
17
+ {
18
+ name: 'Überlebensurteil analysieren',
19
+ text: 'Ziehen Sie den Asteroiden auf die Karte und geben Sie an, wie weit Sie entfernt sind, um die Auswirkungen von Strahlung, Erdbeben und Schockwelle zu sehen.',
20
+ },
21
+ ];
22
+ const faq = [
23
+ {
24
+ question: 'Wie wird die Einschlagsenergie berechnet?',
25
+ answer: 'Die primäre Energie ist kinetisch: (1/2) * Masse * Geschwindigkeit². Wir verwenden realistische Dichten (z. B. 3000 kg/m³ für steinige Asteroiden) und typische Eintrittsgeschwindigkeiten in die Atmosphäre (11 bis 72 km/s). Die resultierende Energie wird in Megatonnen TNT gemessen.',
26
+ },
27
+ {
28
+ question: 'Was ist eine thermische Schockwelle?',
29
+ answer: 'Beim Eintritt in die Atmosphäre komprimiert der Asteroid die Luft so heftig, dass ein Feuerball entsteht, der tausendmal heller als die Sonne ist. Die daraus resultierende Wärmestrahlung kann Verbrennungen dritten Grades verursachen und Wälder in meilenweiter Entfernung vom Einschlagort in Brand setzen.',
30
+ },
31
+ {
32
+ question: 'Warum erzeugen manche Asteroiden keine Krater?',
33
+ answer: 'Kleinere Gesteine (<50m) zerfallen und explodieren aufgrund des Luftdrucks meist in der Atmosphäre (Airburst), wie in Tscheljabinsk geschehen. Die Energie wird als gewaltige Druckwelle freigesetzt, trifft aber nicht als fester Körper am Boden auf.',
34
+ },
35
+ {
36
+ question: 'Wie hoch ist die tatsächliche Wahrscheinlichkeit eines einschlags?',
37
+ answer: 'Kleinere Einschläge (wie Russland 2013) ereignen sich jedes Jahrzehnt. Katastrophale Einschläge (Typ Tunguska) alle paar Jahrhunderte. Ein globales Massenaussterben wie bei Chicxulub findet etwa alle 100 Millionen Jahre statt.',
38
+ },
39
+ ];
40
+ import type { ToolLocaleContent } from '../../../types';
41
+
42
+ export const content: ToolLocaleContent = {
43
+ slug,
44
+ title,
45
+ description,
46
+ faqTitle: 'Häufig gestellte Fragen',
47
+ bibliographyTitle: 'Bibliografie',
48
+ ui: {
49
+ copied: 'Kopiert',
50
+ noHistory: 'Kein Verlauf',
51
+ load: 'Laden',
52
+ delete: 'Löschen',
53
+ activateGPS: 'GPS aktivieren',
54
+ analysisLabel: 'Analyse',
55
+ dragToMap: 'AUF DIE KARTE ZIEHEN',
56
+ diameterLabel: 'Durchmesser',
57
+ velocityLabel: 'Geschwindigkeit',
58
+ typeLabel: 'Typ',
59
+ historicalData: 'Historische Daten',
60
+ composition: 'Zusammensetzung',
61
+ rock: 'Gestein',
62
+ iron: 'Eisen',
63
+ ice: 'Eis',
64
+ clearAll: 'Alles löschen',
65
+ searching: 'Suche...',
66
+ gpsActive: 'GPS aktiv',
67
+ gpsError: 'GPS-Fehler',
68
+ verdictSafe: 'SICHERHEITSZONE',
69
+ verdictSafeSub: 'Keine Bedrohung',
70
+ verdictShock: 'SCHOCKWELLE',
71
+ verdictShockSub: 'Strukturschäden',
72
+ verdictBurned: 'WÄRMESTRAHLUNG',
73
+ verdictBurnedSub: 'Extreme Gefahr',
74
+ verdictVaporized: 'GROUND ZERO',
75
+ verdictVaporizedSub: 'Direkter Einschlag',
76
+ presetAerial: 'Luftdetonation',
77
+ presetForest: 'Wald',
78
+ presetComet: 'Komet',
79
+ presetELE: 'E.L.E. (Globales Aussterben)',
80
+ },
81
+ seo: [
82
+ {
83
+ type: 'title',
84
+ text: 'Wenn der Himmel fällt: Die Physik der kosmischen Apokalypse',
85
+ level: 2,
86
+ },
87
+ {
88
+ type: 'paragraph',
89
+ html: 'Asteroiden sind nicht einfach nur Weltraumgestein. Sie sind kosmische Geschosse, die mit 20 km/s fliegen und mehr Energie freisetzen können als alle Atomwaffen auf der Erde zusammen. Dieser Simulator übersetzt abstrakte Physik in greifbare menschliche Konsequenzen.',
90
+ },
91
+ {
92
+ type: 'title',
93
+ text: 'Die Gleichung des Jüngsten Gerichts',
94
+ level: 3,
95
+ },
96
+ {
97
+ type: 'paragraph',
98
+ html: 'Alles beginnt mit der kinetischen Energie: <strong>E = ½mv²</strong>. Ein 100-Meter-Asteroid, der mit 20 km/s fliegt, setzt etwa 0,5 Megatonnen TNT frei. Zum Vergleich: Die Hiroshima-Bombe hatte eine Sprengkraft von 0,015 Megatonnen.',
99
+ },
100
+ {
101
+ type: 'paragraph',
102
+ html: 'Aber die Größe skaliert exponentiell. Ein Objekt, das zehnmal größer ist, hat das 1.000-fache Volumen (und die 1.000-fache Masse) und setzt eine Energie frei, die <strong>500 Megatonnen</strong> entspricht. Chicxulub, der Dinosaurier-Killer, setzte das Äquivalent von <strong>100 Millionen Megatonnen</strong> frei.',
103
+ },
104
+ {
105
+ type: 'paragraph',
106
+ html: 'Ein 1 km großer Asteroid, der auf die Erde trifft, würde mehr Energie freisetzen als alle Atomwaffen des Planeten, wenn sie gleichzeitig gezündet würden.',
107
+ },
108
+ {
109
+ type: 'title',
110
+ text: 'Anatomie der Zerstörung: Konzentrische Schichten der Apokalypse',
111
+ level: 3,
112
+ },
113
+ {
114
+ type: 'list',
115
+ items: [
116
+ '<strong>Der Krater (Ground Zero):</strong> Der Kraterdurchmesser skaliert mit E^0,3. Ein Einschlag von 1 Megatonne erzeugt einen Krater von ca. 1 km. Alles im Inneren wird sofort verdampft.',
117
+ '<strong>Wärmestrahlung (Der Blitz):</strong> Der Feuerball emittiert intensive Infrarotstrahlung. In einer Entfernung von E^0,41 km entzündet sich Kleidung und die Haut erleidet Verbrennungen dritten Grades.',
118
+ '<strong>Schockwelle (Der Hammer):</strong> Die Überdruckwelle breitet sich mit Überschallgeschwindigkeit aus. Bei 1 psi zerbricht Glas. Bei 5 psi stürzen Gebäude ein.',
119
+ '<strong>Erdbeben (Das seismische Echo):</strong> Der Einschlag erzeugt globale seismische Wellen. Chicxulub verursachte ein Erdbeben der Stärke 11, was die Richterskala sprengte.',
120
+ ],
121
+ },
122
+ {
123
+ type: 'title',
124
+ text: 'Historische Einschläge: Lehren aus der Vergangenheit',
125
+ level: 3,
126
+ },
127
+ {
128
+ type: 'table',
129
+ headers: ['Ort & Jahr', 'Größe', 'Energie', 'Auswirkungen'],
130
+ rows: [
131
+ ['Tscheljabinsk, Russland (2013)', '20 Meter', '500 Kilotonnen', 'Schockwelle bei 100 km, 1.500 Verletzte, zerbrochene Fenster'],
132
+ ['Tunguska, Sibirien (1908)', '50-60 Meter', '10-15 Megatonnen', '2.000 km² Wald dem Erdboden gleichgemacht, 80 Millionen Bäume gefällt'],
133
+ ['Chicxulub, Golf von Mexiko (vor 66 Mio. J.)', '10 km', '100 Mio. Megatonnen', 'Aussterben von 75 % des Lebens auf der Erde'],
134
+ ],
135
+ },
136
+ ],
137
+ faq,
138
+ bibliography: [
139
+ {
140
+ name: 'Collins, G. S., et al. (2005). Earth Impact Effects Program: Ein webbasiertes Computerprogramm zur Berechnung der regionalen Umweltfolgen eines Meteoriteneinschlags auf der Erde.',
141
+ url: 'https://impact.ese.ic.ac.uk/ImpactEarth/',
142
+ },
143
+ {
144
+ name: 'Toon, O. B., et al. (1997). Environmental perturbations caused by the impacts of asteroids and comets. Reviews of Geophysics.',
145
+ url: 'https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/96RG03038',
146
+ },
147
+ {
148
+ name: 'Chapman, C. R., & Morrison, D. (1994). Impacts on the Earth by asteroids and comets: assessing the hazard. Nature.',
149
+ url: 'https://www.nature.com/articles/367033a0',
150
+ },
151
+ {
152
+ name: 'Schulte, P., et al. (2010). The Chicxulub Asteroid Impact and Mass Extinction at the Cretaceous-Paleogene Boundary. Science.',
153
+ url: 'https://www.science.org/doi/10.1126/science.1177265',
154
+ },
155
+ {
156
+ name: 'Brown, P., et al. (2013). A 500-kiloton airburst over Chelyabinsk and an enhanced hazard from small impactors. Nature.',
157
+ url: 'https://www.nature.com/articles/nature12741',
158
+ },
159
+ ],
160
+ howTo,
161
+
162
+ schemas: [
163
+ {
164
+ '@context': 'https://schema.org',
165
+ '@type': 'SoftwareApplication',
166
+ name: title,
167
+ description: description,
168
+ applicationCategory: 'ScientificApplication',
169
+ operatingSystem: 'Any',
170
+ },
171
+ {
172
+ '@context': 'https://schema.org',
173
+ '@type': 'FAQPage',
174
+ mainEntity: faq.map((item) => ({
175
+ '@type': 'Question',
176
+ name: item.question,
177
+ acceptedAnswer: {
178
+ '@type': 'Answer',
179
+ text: item.answer,
180
+ },
181
+ })),
182
+ },
183
+ {
184
+ '@context': 'https://schema.org',
185
+ '@type': 'HowTo',
186
+ name: title,
187
+ step: howTo.map((step) => ({
188
+ '@type': 'HowToStep',
189
+ name: step.name,
190
+ text: step.text,
191
+ })),
192
+ },
193
+ ],
194
+ };
@@ -1,9 +1,48 @@
1
+ const slug = 'asteroid-impact-simulator';
2
+ const description = 'Simulate asteroid impacts with real physics. Calculate energy, crater, thermal radiation and shockwave. Would you survive Chicxulub?';
3
+ const title = 'Asteroid Impact Simulator: Apocalypse Calculator';
4
+ const howTo = [
5
+ {
6
+ name: 'Choose projectile size',
7
+ text: 'Enter the asteroid diameter, from a small 10-meter meteorite to a 10-kilometer planet killer.',
8
+ },
9
+ {
10
+ name: 'Configure velocity and angle',
11
+ text: 'Adjust the approach velocity and entry angle (45° is the statistically most likely value).',
12
+ },
13
+ {
14
+ name: 'Define asteroid nature',
15
+ text: 'Select whether the asteroid is made of rock, iron, or ice to calculate the crater depth correctly.',
16
+ },
17
+ {
18
+ name: 'Analyze survival verdict',
19
+ text: 'Drag the asteroid onto the map and indicate how far away you are to see the effects of radiation, earthquake, and shockwave.',
20
+ },
21
+ ];
22
+ const faq = [
23
+ {
24
+ question: 'How is impact energy calculated?',
25
+ answer: 'Primary energy is kinetic: (1/2) * mass * velocity². We use realistic densities (e.g. 3000 kg/m³ for rocky asteroids) and typical atmospheric entry velocities (11 to 72 km/s). The resulting energy is measured in Megatons of TNT.',
26
+ },
27
+ {
28
+ question: 'What is a thermal shockwave?',
29
+ answer: 'Upon entering the atmosphere, the asteroid compresses the air so violently that it creates a fireball a thousand times brighter than the Sun. The resulting thermal radiation can cause third-degree burns and set forests ablaze miles from the impact.',
30
+ },
31
+ {
32
+ question: 'Why don\'t some asteroids create craters?',
33
+ answer: 'Smaller rocks (<50m) usually fragment and explode in the atmosphere due to air pressure (Airburst), as happened in Chelyabinsk. The energy is released as a powerful pressure shockwave, but it doesn\'t hit the ground as a solid body.',
34
+ },
35
+ {
36
+ question: 'What is the real probability of an impact?',
37
+ answer: 'Small impacts (like Russia in 2013) happen every decade. Catastrophic impacts (Tunguska-style) every few centuries. A global extinction event like Chicxulub happens approximately every 100 million years.',
38
+ },
39
+ ];
1
40
  import type { ToolLocaleContent } from '../../../types';
2
41
 
3
42
  export const content: ToolLocaleContent = {
4
- slug: 'asteroid-impact-simulator',
5
- title: 'Asteroid Impact Simulator: Apocalypse Calculator',
6
- description: 'Simulate asteroid impacts with real physics. Calculate energy, crater, thermal radiation and shockwave. Would you survive Chicxulub?',
43
+ slug,
44
+ title,
45
+ description,
7
46
  faqTitle: 'Frequently Asked Questions',
8
47
  bibliographyTitle: 'Bibliography',
9
48
  ui: {
@@ -95,24 +134,7 @@ export const content: ToolLocaleContent = {
95
134
  ],
96
135
  },
97
136
  ],
98
- faq: [
99
- {
100
- question: 'How is impact energy calculated?',
101
- answer: 'Primary energy is kinetic: (1/2) * mass * velocity². We use realistic densities (e.g. 3000 kg/m³ for rocky asteroids) and typical atmospheric entry velocities (11 to 72 km/s). The resulting energy is measured in Megatons of TNT.',
102
- },
103
- {
104
- question: 'What is a thermal shockwave?',
105
- answer: 'Upon entering the atmosphere, the asteroid compresses the air so violently that it creates a fireball a thousand times brighter than the Sun. The resulting thermal radiation can cause third-degree burns and set forests ablaze miles from the impact.',
106
- },
107
- {
108
- question: 'Why don\'t some asteroids create craters?',
109
- answer: 'Smaller rocks (<50m) usually fragment and explode in the atmosphere due to air pressure (Airburst), as happened in Chelyabinsk. The energy is released as a powerful pressure shockwave, but it doesn\'t hit the ground as a solid body.',
110
- },
111
- {
112
- question: 'What is the real probability of an impact?',
113
- answer: 'Small impacts (like Russia in 2013) happen every decade. Catastrophic impacts (Tunguska-style) every few centuries. A global extinction event like Chicxulub happens approximately every 100 million years.',
114
- },
115
- ],
137
+ faq,
116
138
  bibliography: [
117
139
  {
118
140
  name: 'Collins, G. S., et al. (2005). Earth Impact Effects Program: A Web-based computer program for calculating the regional environmental consequences of a meteoroid impact on Earth.',
@@ -135,23 +157,38 @@ export const content: ToolLocaleContent = {
135
157
  url: 'https://www.nature.com/articles/nature12741',
136
158
  },
137
159
  ],
138
- howTo: [
139
- {
140
- name: 'Choose projectile size',
141
- text: 'Enter the asteroid diameter, from a small 10-meter meteorite to a 10-kilometer planet killer.',
142
- },
143
- {
144
- name: 'Configure velocity and angle',
145
- text: 'Adjust the approach velocity and entry angle (45° is the statistically most likely value).',
146
- },
147
- {
148
- name: 'Define asteroid nature',
149
- text: 'Select whether the asteroid is made of rock, iron, or ice to calculate the crater depth correctly.',
150
- },
151
- {
152
- name: 'Analyze survival verdict',
153
- text: 'Drag the asteroid onto the map and indicate how far away you are to see the effects of radiation, earthquake, and shockwave.',
160
+ howTo,
161
+
162
+ schemas: [
163
+ {
164
+ '@context': 'https://schema.org',
165
+ '@type': 'SoftwareApplication',
166
+ name: title,
167
+ description: description,
168
+ applicationCategory: 'ScientificApplication',
169
+ operatingSystem: 'Any',
170
+ },
171
+ {
172
+ '@context': 'https://schema.org',
173
+ '@type': 'FAQPage',
174
+ mainEntity: faq.map((item) => ({
175
+ '@type': 'Question',
176
+ name: item.question,
177
+ acceptedAnswer: {
178
+ '@type': 'Answer',
179
+ text: item.answer,
180
+ },
181
+ })),
182
+ },
183
+ {
184
+ '@context': 'https://schema.org',
185
+ '@type': 'HowTo',
186
+ name: title,
187
+ step: howTo.map((step) => ({
188
+ '@type': 'HowToStep',
189
+ name: step.name,
190
+ text: step.text,
191
+ })),
154
192
  },
155
193
  ],
156
- schemas: [],
157
194
  };