@jjlmoya/utils-nautical 1.16.0 → 1.18.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 (49) hide show
  1. package/package.json +4 -2
  2. package/src/category/i18n/de.ts +1 -1
  3. package/src/category/i18n/en.ts +1 -1
  4. package/src/category/i18n/es.ts +16 -16
  5. package/src/category/i18n/fr.ts +16 -16
  6. package/src/category/i18n/id.ts +1 -1
  7. package/src/category/i18n/it.ts +1 -1
  8. package/src/category/i18n/nl.ts +1 -1
  9. package/src/category/i18n/pl.ts +1 -1
  10. package/src/category/i18n/pt.ts +1 -1
  11. package/src/category/i18n/ru.ts +3 -3
  12. package/src/category/i18n/sv.ts +1 -1
  13. package/src/category/i18n/tr.ts +1 -1
  14. package/src/data.ts +0 -6
  15. package/src/layouts/PreviewLayout.astro +1 -0
  16. package/src/tests/diacritics_density.test.ts +118 -0
  17. package/src/tests/inverted_punctuation.test.ts +84 -0
  18. package/src/tests/no_en_dash.test.ts +70 -0
  19. package/src/tests/pagespeed_best_practices.test.ts +198 -0
  20. package/src/tests/script_density.test.ts +94 -0
  21. package/src/tool/endurance/component.astro +10 -10
  22. package/src/tool/endurance/i18n/es.ts +54 -54
  23. package/src/tool/endurance/i18n/fr.ts +70 -70
  24. package/src/tool/endurance/i18n/ru.ts +9 -9
  25. package/src/tool/nauticalConverter/component.astro +15 -15
  26. package/src/tool/nauticalConverter/i18n/es.ts +46 -46
  27. package/src/tool/nauticalConverter/i18n/fr.ts +53 -53
  28. package/src/tool/nauticalConverter/i18n/pl.ts +3 -3
  29. package/src/tool/nauticalConverter/i18n/ru.ts +8 -8
  30. package/src/tool/nauticalConverter/i18n/zh.ts +3 -3
  31. package/src/tool/sailArea/component.astro +13 -13
  32. package/src/tool/sailArea/i18n/es.ts +53 -53
  33. package/src/tool/sailArea/i18n/fr.ts +70 -70
  34. package/src/tool/sailArea/i18n/ru.ts +8 -8
  35. package/src/tool/sailArea/i18n/zh.ts +5 -5
  36. package/src/tool/speedConverter/i18n/es.ts +58 -58
  37. package/src/tool/speedConverter/i18n/fr.ts +75 -75
  38. package/src/tool/speedConverter/i18n/ru.ts +6 -6
  39. package/src/tool/speedConverter/i18n/zh.ts +5 -5
  40. package/src/tool/tideCalculator/component.astro +5 -5
  41. package/src/tool/tideCalculator/i18n/es.ts +39 -39
  42. package/src/tool/tideCalculator/i18n/fr.ts +43 -43
  43. package/src/tool/tideCalculator/i18n/ru.ts +6 -6
  44. package/src/tool/tideCalculator/i18n/zh.ts +1 -1
  45. package/src/tool/tideCalculator/tide-height-calculator.css +136 -5
  46. package/src/tool/underKeel/component.astro +7 -7
  47. package/src/tool/underKeel/i18n/es.ts +39 -39
  48. package/src/tool/underKeel/i18n/fr.ts +45 -45
  49. package/src/tool/underKeel/i18n/ru.ts +5 -5
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-nautical",
3
- "version": "1.16.0",
3
+ "version": "1.18.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
7
7
  "exports": {
8
8
  ".": "./src/index.ts",
9
9
  "./data": "./src/data.ts",
10
- "./entries": "./src/entries.ts"
10
+ "./entries": "./src/entries.ts",
11
+ "./runtime/*": "./src/tool/*/index.ts",
12
+ "./category-seo": "./src/category/seo.astro"
11
13
  },
12
14
  "files": [
13
15
  "src",
@@ -13,7 +13,7 @@ const seo: CategoryLocaleContent['seo'] = [
13
13
  },
14
14
  {
15
15
  type: 'paragraph',
16
- html: 'Die moderne Navigation hat mit dem Aufkommen digitaler Werkzeuge eine radikale Transformation erfahren. Ob auf einem kleinen Freizeitboot oder am Steuer einer Kreuzyacht die Fähigkeit, Positions-, Wind- und Strömungsdaten sofort zu verarbeiten, ist nicht nur eine Frage des Komforts, sondern ein grundlegendes Sicherheitsprinzip auf See.',
16
+ html: 'Die moderne Navigation hat mit dem Aufkommen digitaler Werkzeuge eine radikale Transformation erfahren. Ob auf einem kleinen Freizeitboot oder am Steuer einer Kreuzyacht - die Fähigkeit, Positions-, Wind- und Strömungsdaten sofort zu verarbeiten, ist nicht nur eine Frage des Komforts, sondern ein grundlegendes Sicherheitsprinzip auf See.',
17
17
  },
18
18
  {
19
19
  type: 'paragraph',
@@ -13,7 +13,7 @@ const seo: CategoryLocaleContent['seo'] = [
13
13
  },
14
14
  {
15
15
  type: 'paragraph',
16
- html: 'Modern navigation has undergone a radical transformation with the advent of digital tools. Whether you are on a small recreational craft or at the helm of a cruising yacht, the ability to process position, wind and current data instantly is not just a matter of convenience it is a fundamental pillar of safety at sea.',
16
+ html: 'Modern navigation has undergone a radical transformation with the advent of digital tools. Whether you are on a small recreational craft or at the helm of a cruising yacht, the ability to process position, wind and current data instantly is not just a matter of convenience - it is a fundamental pillar of safety at sea.',
17
17
  },
18
18
  {
19
19
  type: 'paragraph',
@@ -1,23 +1,23 @@
1
1
  import type { CategoryLocaleContent } from '../index';
2
2
 
3
3
  const slug = 'vela-y-nautica';
4
- const title = 'Vela y Nautica';
4
+ const title = 'Vela y Náutica';
5
5
  const description =
6
- 'Herramientas de calculo nautico para navegantes: mareas, autonomia, superficie velica, conversores de unidades y velocidad. Ideales para el estudio del PER y Patron de Yate.';
6
+ 'Herramientas de cálculo náutico para navegantes: mareas, autonomía, superficie vélica, conversores de unidades y velocidad. Ideales para el estudio del PER y Patrón de Yate.';
7
7
 
8
8
  const seo: CategoryLocaleContent['seo'] = [
9
9
  {
10
10
  type: 'title',
11
- text: '¿Por que usar herramientas digitales en navegacion y vela?',
11
+ text: '¿Por qué usar herramientas digitales en navegación y vela?',
12
12
  level: 2,
13
13
  },
14
14
  {
15
15
  type: 'paragraph',
16
- html: 'La navegacion moderna ha experimentado una transformacion radical con la llegada de las herramientas digitales. Ya sea que te encuentres en una pequeña embarcacion de recreo o al mando de un velero de crucero, la capacidad de procesar datos de posicion, viento y corriente de forma instantanea no es solo una cuestion de comodidad, sino un pilar fundamental de la seguridad en el mar.',
16
+ html: 'La navegación moderna ha experimentado una transformación radical con la llegada de las herramientas digitales. Ya sea que te encuentres en una pequeña embarcación de recreo o al mando de un velero de crucero, la capacidad de procesar datos de posición, viento y corriente de forma instantánea no es solo una cuestión de comodidad, sino un pilar fundamental de la seguridad en el mar.',
17
17
  },
18
18
  {
19
19
  type: 'paragraph',
20
- html: 'Historicamente, el marino dependia exclusivamente del sextante, el cronometro de marina y las tablas de reduccion para determinar su posicion en el vasto oceano. Hoy, aunque el romanticismo del sextante persiste, la realidad operativa exige una velocidad de respuesta que solo las herramientas de calculo digital pueden proporcionar.',
20
+ html: 'Históricamente, el marino dependía exclusivamente del sextante, el cronómetro de marina y las tablas de reducción para determinar su posición en el vasto océano. Hoy, aunque el romanticismo del sextante persiste, la realidad operativa exige una velocidad de respuesta que solo las herramientas de cálculo digital pueden proporcionar.',
21
21
  },
22
22
  {
23
23
  type: 'title',
@@ -26,48 +26,48 @@ const seo: CategoryLocaleContent['seo'] = [
26
26
  },
27
27
  {
28
28
  type: 'title',
29
- text: 'Geolocalización y Cartografia Digital de Alta Precision',
29
+ text: 'Geolocalización y Cartografía Digital de Alta Precisión',
30
30
  level: 3,
31
31
  },
32
32
  {
33
33
  type: 'paragraph',
34
- html: 'La cartografia digital ha democratizado la navegacion, permitiendo que incluso barcos pequeños tengan acceso a informacion que antes estaba limitada a buques comerciales de gran calado. Un patron responsable utiliza las herramientas digitales para validar su juicio, no para sustituirlo.',
34
+ html: 'La cartografía digital ha democratizado la navegación, permitiendo que incluso barcos pequeños tengan acceso a información que antes estaba limitada a buques comerciales de gran calado. Un patrón responsable utiliza las herramientas digitales para validar su juicio, no para sustituirlo.',
35
35
  },
36
36
  {
37
37
  type: 'list',
38
38
  items: [
39
- 'Precision en la entrada de datos: Errores tipograficos minimos pueden alejarte kilometros de tu destino.',
40
- 'Compatibilidad entre dispositivos: Permite sincronizar la planificacion en tablet con los sistemas del puente de mando.',
39
+ 'Precisión en la entrada de datos: Errores tipográficos mínimos pueden alejarte kilómetros de tu destino.',
40
+ 'Compatibilidad entre dispositivos: Permite sincronizar la planificación en tablet con los sistemas del puente de mando.',
41
41
  'Respaldo ante fallos de hardware: Las apps web ligeras son un seguro si el plotter de abordo falla.',
42
- 'Planificacion de travesias (Passage Planning): Las calculadorasnáuticas permiten estimar consumos y distancias con precision matematica.',
42
+ 'Planificación de travesías (Passage Planning): Las calculadoras náuticas permiten estimar consumos y distancias con precisión matemática.',
43
43
  ],
44
44
  },
45
45
  {
46
46
  type: 'title',
47
- text: 'Meteorologia Marina y Optimizacion de la Ruta',
47
+ text: 'Meteorología Marina y Optimización de la Ruta',
48
48
  level: 3,
49
49
  },
50
50
  {
51
51
  type: 'paragraph',
52
- html: 'El viento y el estado del mar son los verdaderos soberanos de la navegacion a vela. La interpretacion correcta de las escalas de viento (como la escala Beaufort) y su conversion a unidades practicas como nudos es el dia a dia de cualquier navegante.',
52
+ html: 'El viento y el estado del mar son los verdaderos soberanos de la navegación a vela. La interpretación correcta de las escalas de viento (como la escala Beaufort) y su conversión a unidades prácticas como nudos es el día a día de cualquier navegante.',
53
53
  },
54
54
  {
55
55
  type: 'tip',
56
56
  title: 'La importancia de la redundancia y el Plan B',
57
- html: 'Nunca confies toda tu navegacion a un solo sistema electronico. Mantén siempre una copia de seguridad de tus coordenadas criticas en papel. Las herramientas web son excelentes para la planificacion previa, pero el buen marinero siempre tiene un plan de emergencia.',
57
+ html: 'Nunca confíes toda tu navegación a un solo sistema electrónico. Mantén siempre una copia de seguridad de tus coordenadas críticas en papel. Las herramientas web son excelentes para la planificación previa, pero el buen marinero siempre tiene un plan de emergencia.',
58
58
  },
59
59
  {
60
60
  type: 'title',
61
- text: 'Formacion Nautica y el uso de Calculadoras',
61
+ text: 'Formación Náutica y el uso de Calculadoras',
62
62
  level: 2,
63
63
  },
64
64
  {
65
65
  type: 'paragraph',
66
- html: 'Incluso en los examenes oficiales para obtener los titulos nauticos (como el PER en España), el uso de calculos sobre la carta sigue siendo obligatorio. Las herramientas digitales sirven como el compañero de estudio perfecto, permitiendo a los aspirantes verificar sus ejercicios de estima, calculos de marea o correcciones de aguja magnetica.',
66
+ html: 'Incluso en los exámenes oficiales para obtener los títulos náuticos (como el PER en España), el uso de cálculos sobre la carta sigue siendo obligatorio. Las herramientas digitales sirven como el compañero de estudio perfecto, permitiendo a los aspirantes verificar sus ejercicios de estima, cálculos de marea o correcciones de aguja magnética.',
67
67
  },
68
68
  {
69
69
  type: 'paragraph',
70
- html: 'Nuestra coleccion de utilidades busca ser ese puente entre la rigurosidad academica de las cartas de papel y la inmediatez de la navegacion moderna. Queremos que cada patron, aficionado o profesional, encuentre aqui el dato rapido y preciso que necesita antes de soltar amarras.',
70
+ html: 'Nuestra colección de utilidades busca ser ese puente entre la rigurosidad académica de las cartas de papel y la inmediatez de la navegación moderna. Queremos que cada patrón, aficionado o profesional, encuentre aquí el dato rápido y preciso que necesita antes de soltar amarras.',
71
71
  },
72
72
  ];
73
73
 
@@ -3,58 +3,58 @@ import type { CategoryLocaleContent } from '../index';
3
3
  const slug = 'voile-et-nautisme';
4
4
  const title = 'Voile et Nautisme';
5
5
  const description =
6
- "Outils de calcul nautique pour les navigateurs : marees, autonomie, surface velique, convertisseurs d'unites et de vitesse. Ideaux pour la preparation aux examens de plaisance.";
6
+ "Outils de calcul nautique pour les navigateurs: marées, autonomie, surface vélique, convertisseurs d'unités et de vitesse. Idéaux pour la préparation aux examens de plaisance.";
7
7
 
8
8
  const seo: CategoryLocaleContent['seo'] = [
9
9
  {
10
10
  type: 'title',
11
- text: 'Pourquoi utiliser des outils numeriques en voile et navigation ?',
11
+ text: 'Pourquoi utiliser des outils numériques en voile et navigation ?',
12
12
  level: 2,
13
13
  },
14
14
  {
15
15
  type: 'paragraph',
16
- html: "La navigation moderne a connu une transformation radicale avec l'avenement des outils numeriques. Que vous soyez a bord d'une petite embarcation de plaisance ou aux commandes d'un voilier de croisiere, la capacite de traiter des donnees de position, de vent et de courant instantanement est non seulement une question de commodite, mais un pilier fondamental de la securite en mer.",
16
+ html: "La navigation moderne a connu une transformation radicale avec l'avènement des outils numériques. Que vous soyez à bord d'une petite embarcation de plaisance ou aux commandes d'un voilier de croisière, la capacité de traiter des données de position, de vent et de courant instantanément est non seulement une question de commodité, mais un pilier fondamental de la sécurité en mer.",
17
17
  },
18
18
  {
19
19
  type: 'paragraph',
20
- html: "Historiquement, le marin dependait exclusivement du sextant, du chronometre de marine et des tables de reduction pour determiner sa position sur le vaste ocean. Aujourd'hui, bien que le romantisme du sextant persiste, la realite operationnelle exige une rapidite de reponse que seuls les outils de calcul numeriques peuvent fournir.",
20
+ html: "Historiquement, le marin dépendait exclusivement du sextant, du chronomètre de marine et des tables de réduction pour déterminer sa position sur le vaste océan. Aujourd'hui, bien que le romantisme du sextant persiste, la réalité opérationnelle exige une rapidité de réponse que seuls les outils de calcul numériques peuvent fournir.",
21
21
  },
22
22
  {
23
23
  type: 'title',
24
- text: 'Aspects cles pour le navigateur moderne',
24
+ text: 'Aspects clés pour le navigateur moderne',
25
25
  level: 2,
26
26
  },
27
27
  {
28
28
  type: 'title',
29
- text: 'Geolocalisation et cartographie numerique de haute precision',
29
+ text: 'Géolocalisation et cartographie numérique de haute précision',
30
30
  level: 3,
31
31
  },
32
32
  {
33
33
  type: 'paragraph',
34
- html: "La cartographie numerique a democratise la navigation, permettant meme aux petits bateaux d'acceder a des informations autrefois reservees aux grands navires commerciaux. Un skipper responsable utilise les outils numeriques pour valider son jugement, non pour le remplacer.",
34
+ html: "La cartographie numérique a démocratisé la navigation, permettant même aux petits bateaux d'accéder à des informations autrefois réservées aux grands navires commerciaux. Un skipper responsable utilise les outils numériques pour valider son jugement, non pour le remplacer.",
35
35
  },
36
36
  {
37
37
  type: 'list',
38
38
  items: [
39
- "Precision de saisie des donnees : De petites erreurs typographiques peuvent vous eloigner de kilometres de votre destination.",
40
- "Compatibilite entre appareils : Synchronisez la planification sur tablette avec les instruments de bord.",
41
- "Sauvegarde en cas de panne materielle : Les applications web legeres sont une assurance si le traceur de bord tombe en panne.",
42
- "Planification de traversees : Les calculateurs nautiques permettent d'estimer avec precision les consommations et les distances.",
39
+ "Précision de saisie des données: De petites erreurs typographiques peuvent vous éloigner de kilomètres de votre destination.",
40
+ "Compatibilité entre appareils: Synchronisez la planification sur tablette avec les instruments de bord.",
41
+ "Sauvegarde en cas de panne matérielle: Les applications web légères sont une assurance si le traceur de bord tombe en panne.",
42
+ "Planification de traversées: Les calculateurs nautiques permettent d'estimer avec précision les consommations et les distances.",
43
43
  ],
44
44
  },
45
45
  {
46
46
  type: 'title',
47
- text: 'Meteorologie marine et optimisation de la route',
47
+ text: 'Météorologie marine et optimisation de la route',
48
48
  level: 3,
49
49
  },
50
50
  {
51
51
  type: 'paragraph',
52
- html: "Le vent et l'etat de la mer sont les veritables souverains de la navigation a voile. L'interpretation correcte des echelles de vent (comme l'echelle Beaufort) et leur conversion en unites pratiques comme les noeuds est le quotidien de tout navigateur.",
52
+ html: "Le vent et l'état de la mer sont les véritables souverains de la navigation à voile. L'interprétation correcte des échelles de vent (comme l'échelle Beaufort) et leur conversion en unités pratiques comme les nœuds est le quotidien de tout navigateur.",
53
53
  },
54
54
  {
55
55
  type: 'tip',
56
56
  title: "L'importance de la redondance et du Plan B",
57
- html: "Ne confiez jamais toute votre navigation a un seul systeme electronique. Conservez toujours une copie de sauvegarde de vos coordonnees critiques sur papier. Les outils web sont excellents pour la planification prealable, mais le bon marin a toujours un plan d'urgence.",
57
+ html: "Ne confiez jamais toute votre navigation à un seul système électronique. Conservez toujours une copie de sauvegarde de vos coordonnées critiques sur papier. Les outils web sont excellents pour la planification préalable, mais le bon marin a toujours un plan d'urgence.",
58
58
  },
59
59
  {
60
60
  type: 'title',
@@ -63,11 +63,11 @@ const seo: CategoryLocaleContent['seo'] = [
63
63
  },
64
64
  {
65
65
  type: 'paragraph',
66
- html: "Meme dans les examens officiels pour l'obtention des titres nautiques, les calculs sur carte restent obligatoires. Les outils numeriques servent de compagnon d'etude ideal, permettant aux candidats de verifier leurs exercices d'estime, calculs de maree et corrections de compas.",
66
+ html: "Même dans les examens officiels pour l'obtention des titres nautiques, les calculs sur carte restent obligatoires. Les outils numériques servent de compagnon d'étude idéal, permettant aux candidats de vérifier leurs exercices d'estime, calculs de marée et corrections de compas.",
67
67
  },
68
68
  {
69
69
  type: 'paragraph',
70
- html: "Notre collection d'utilitaires vise a etre ce pont entre la rigueur academique des cartes papier et l'imediatete de la navigation moderne. Nous souhaitons que chaque skipper, amateur ou professionnel, trouve ici la donnee rapide et precise dont il a besoin avant de larguer les amarres.",
70
+ html: "Notre collection d'utilitaires vise à être ce pont entre la rigueur académique des cartes papier et l'immédiateté de la navigation moderne. Nous souhaitons que chaque skipper, amateur ou professionnel, trouve ici la donnée rapide et précise dont il a besoin avant de larguer les amarres.",
71
71
  },
72
72
  ];
73
73
 
@@ -13,7 +13,7 @@ const seo: CategoryLocaleContent['seo'] = [
13
13
  },
14
14
  {
15
15
  type: 'paragraph',
16
- html: 'Navigasi modern telah mengalami transformasi radikal dengan hadirnya alat digital. Baik Anda berada di kapal rekreasi kecil maupun di kemudi kapal pesiar, kemampuan untuk memproses data posisi, angin, dan arus secara instan bukan hanya soal kenyamanan ini adalah pilar keselamatan fundamental di laut.',
16
+ html: 'Navigasi modern telah mengalami transformasi radikal dengan hadirnya alat digital. Baik Anda berada di kapal rekreasi kecil maupun di kemudi kapal pesiar, kemampuan untuk memproses data posisi, angin, dan arus secara instan bukan hanya soal kenyamanan - ini adalah pilar keselamatan fundamental di laut.',
17
17
  },
18
18
  {
19
19
  type: 'paragraph',
@@ -13,7 +13,7 @@ const seo: CategoryLocaleContent['seo'] = [
13
13
  },
14
14
  {
15
15
  type: 'paragraph',
16
- html: 'La navigazione moderna ha subito una trasformazione radicale con l\'avvento degli strumenti digitali. Che si trovi su una piccola imbarcazione da diporto o al timone di uno yacht da crociera, la capacità di elaborare istantaneamente dati di posizione, vento e corrente non è solo una questione di comodità è un pilastro fondamentale della sicurezza in mare.',
16
+ html: 'La navigazione moderna ha subito una trasformazione radicale con l\'avvento degli strumenti digitali. Che si trovi su una piccola imbarcazione da diporto o al timone di uno yacht da crociera, la capacità di elaborare istantaneamente dati di posizione, vento e corrente non è solo una questione di comodità - è un pilastro fondamentale della sicurezza in mare.',
17
17
  },
18
18
  {
19
19
  type: 'paragraph',
@@ -13,7 +13,7 @@ const seo: CategoryLocaleContent['seo'] = [
13
13
  },
14
14
  {
15
15
  type: 'paragraph',
16
- html: 'Moderne navigatie heeft een radicale transformatie ondergaan met de komst van digitale tools. Of u nu op een kleine recreatievaarder bent of aan het roer van een cruisingjacht staat, de mogelijkheid om positie-, wind- en stroomgegevens direct te verwerken is niet alleen een kwestie van gemak het is een fundamentele pijler van veiligheid op zee.',
16
+ html: 'Moderne navigatie heeft een radicale transformatie ondergaan met de komst van digitale tools. Of u nu op een kleine recreatievaarder bent of aan het roer van een cruisingjacht staat, de mogelijkheid om positie-, wind- en stroomgegevens direct te verwerken is niet alleen een kwestie van gemak - het is een fundamentele pijler van veiligheid op zee.',
17
17
  },
18
18
  {
19
19
  type: 'paragraph',
@@ -13,7 +13,7 @@ const seo: CategoryLocaleContent['seo'] = [
13
13
  },
14
14
  {
15
15
  type: 'paragraph',
16
- html: 'Nowoczesna nawigacja przeszła radykalną transformację wraz z pojawieniem się cyfrowych narzędzi. Czy jesteś na małej łodzi rekreacyjnej, czy przy sterze jachtu rejsowego, zdolność do natychmiastowego przetwarzania danych pozycji, wiatru i prądu to nie tylko kwestia wygody jest to fundamentalny filar bezpieczeństwa na morzu.',
16
+ html: 'Nowoczesna nawigacja przeszła radykalną transformację wraz z pojawieniem się cyfrowych narzędzi. Czy jesteś na małej łodzi rekreacyjnej, czy przy sterze jachtu rejsowego, zdolność do natychmiastowego przetwarzania danych pozycji, wiatru i prądu to nie tylko kwestia wygody - jest to fundamentalny filar bezpieczeństwa na morzu.',
17
17
  },
18
18
  {
19
19
  type: 'paragraph',
@@ -13,7 +13,7 @@ const seo: CategoryLocaleContent['seo'] = [
13
13
  },
14
14
  {
15
15
  type: 'paragraph',
16
- html: 'A navegação moderna passou por uma transformação radical com o advento das ferramentas digitais. Quer você esteja em uma pequena embarcação de recreio ou ao leme de um iate de cruzeiro, a capacidade de processar dados de posição, vento e corrente instantaneamente não é apenas uma questão de conveniência é um pilar fundamental de segurança no mar.',
16
+ html: 'A navegação moderna passou por uma transformação radical com o advento das ferramentas digitais. Quer você esteja em uma pequena embarcação de recreio ou ao leme de um iate de cruzeiro, a capacidade de processar dados de posição, vento e corrente instantaneamente não é apenas uma questão de conveniência - é um pilar fundamental de segurança no mar.',
17
17
  },
18
18
  {
19
19
  type: 'paragraph',
@@ -13,7 +13,7 @@ const seo: CategoryLocaleContent['seo'] = [
13
13
  },
14
14
  {
15
15
  type: 'paragraph',
16
- html: 'Современная навигация претерпела радикальную трансформацию с появлением цифровых инструментов. Находитесь ли вы на небольшом прогулочном судне или стоите за штурвалом крейсерской яхты, способность мгновенно обрабатывать данные о позиции, ветре и течении это не просто вопрос удобства, а основополагающий принцип безопасности на море.',
16
+ html: 'Современная навигация претерпела радикальную трансформацию с появлением цифровых инструментов. Находитесь ли вы на небольшом прогулочном судне или стоите за штурвалом крейсерской яхты, способность мгновенно обрабатывать данные о позиции, ветре и течении - это не просто вопрос удобства, а основополагающий принцип безопасности на море.',
17
17
  },
18
18
  {
19
19
  type: 'paragraph',
@@ -38,7 +38,7 @@ const seo: CategoryLocaleContent['seo'] = [
38
38
  items: [
39
39
  'Точность ввода данных: Минимальные опечатки могут увести вас на мили от пункта назначения.',
40
40
  'Совместимость между устройствами: Синхронизируйте планирование перехода на планшете с навигационными приборами.',
41
- 'Резервная копия при отказе оборудования: Лёгкие веб-приложения это страховка на случай сбоя бортового плоттера.',
41
+ 'Резервная копия при отказе оборудования: Лёгкие веб-приложения - это страховка на случай сбоя бортового плоттера.',
42
42
  'Планирование перехода: Навигационные калькуляторы позволяют точно оценить расход топлива и расстояния.',
43
43
  ],
44
44
  },
@@ -49,7 +49,7 @@ const seo: CategoryLocaleContent['seo'] = [
49
49
  },
50
50
  {
51
51
  type: 'paragraph',
52
- html: 'Ветер и волнение моря истинные властители парусного спорта. Правильная интерпретация шкал ветра (например, шкалы Бофорта) и их перевод в практические единицы узлы является повседневной реальностью любого навигатора.',
52
+ html: 'Ветер и волнение моря - истинные властители парусного спорта. Правильная интерпретация шкал ветра (например, шкалы Бофорта) и их перевод в практические единицы - узлы - является повседневной реальностью любого навигатора.',
53
53
  },
54
54
  {
55
55
  type: 'tip',
@@ -13,7 +13,7 @@ const seo: CategoryLocaleContent['seo'] = [
13
13
  },
14
14
  {
15
15
  type: 'paragraph',
16
- html: 'Modern navigering har genomgått en radikal omvandling med introduktionen av digitala verktyg. Oavsett om du är ombord på en liten fritidsbåt eller vid rodret på en kryssningsjakt, är förmågan att omedelbart bearbeta positions-, vind- och strömdata inte bara en bekvämlighet det är en grundläggande säkerhetspelare till sjöss.',
16
+ html: 'Modern navigering har genomgått en radikal omvandling med introduktionen av digitala verktyg. Oavsett om du är ombord på en liten fritidsbåt eller vid rodret på en kryssningsjakt, är förmågan att omedelbart bearbeta positions-, vind- och strömdata inte bara en bekvämlighet - det är en grundläggande säkerhetspelare till sjöss.',
17
17
  },
18
18
  {
19
19
  type: 'paragraph',
@@ -13,7 +13,7 @@ const seo: CategoryLocaleContent['seo'] = [
13
13
  },
14
14
  {
15
15
  type: 'paragraph',
16
- html: 'Modern navigasyon, dijital araçların ortaya çıkmasıyla köklü bir dönüşüm geçirdi. İster küçük bir eğlence teknesinde olun, ister bir kruvaziyer yatın dümenini tutun, konum, rüzgar ve akıntı verilerini anında işleme kabiliyeti yalnızca bir kolaylık meselesi değil denizde güvenliğin temel bir direğidir.',
16
+ html: 'Modern navigasyon, dijital araçların ortaya çıkmasıyla köklü bir dönüşüm geçirdi. İster küçük bir eğlence teknesinde olun, ister bir kruvaziyer yatın dümenini tutun, konum, rüzgar ve akıntı verilerini anında işleme kabiliyeti yalnızca bir kolaylık meselesi değil - denizde güvenliğin temel bir direğidir.',
17
17
  },
18
18
  {
19
19
  type: 'paragraph',
package/src/data.ts CHANGED
@@ -1,12 +1,6 @@
1
1
  export { nauticalCategory } from './category';
2
2
  export type { CategoryLocaleContent } from './category';
3
3
 
4
- export { tideCalculator } from './tool/tideCalculator';
5
- export { underKeel } from './tool/underKeel';
6
- export { nauticalConverter } from './tool/nauticalConverter';
7
- export { sailArea } from './tool/sailArea';
8
- export { speedConverter } from './tool/speedConverter';
9
- export { endurance } from './tool/endurance';
10
4
 
11
5
  export type { TideCalculatorUI, TideCalculatorLocaleContent } from './tool/tideCalculator';
12
6
  export type { UnderKeelUI, UnderKeelLocaleContent } from './tool/underKeel';
@@ -78,6 +78,7 @@ const { title, currentLocale = "es", localeUrls = {}, hasSidebar = false } = Ast
78
78
  transition:
79
79
  background-color 0.3s ease,
80
80
  color 0.3s ease;
81
+ font-family: Inter, sans-serif;
81
82
  }
82
83
 
83
84
  main {
@@ -0,0 +1,118 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { ALL_TOOLS } from '../tools';
3
+
4
+ type LocaleWithDiacritics = keyof typeof DIACRITIC_RULES;
5
+
6
+ const DIACRITIC_RULES = {
7
+ de: {
8
+ language: 'German',
9
+ expectedCharacters: 'ä ö ü ß',
10
+ characters: /[äöüÄÖÜß]/g,
11
+ minPerThousandLetters: 0.1,
12
+ },
13
+ es: {
14
+ language: 'Spanish',
15
+ expectedCharacters: 'á é í ó ú ü ñ',
16
+ characters: /[áéíóúüñÁÉÍÓÚÜÑ]/g,
17
+ minPerThousandLetters: 0.1,
18
+ },
19
+ fr: {
20
+ language: 'French',
21
+ expectedCharacters: 'à â æ ç é è ê ë î ï ô œ ù û ü ÿ',
22
+ characters: /[àâæçéèêëîïôœùûüÿÀÂÆÇÉÈÊËÎÏÔŒÙÛÜŸ]/g,
23
+ minPerThousandLetters: 0.1,
24
+ },
25
+ it: {
26
+ language: 'Italian',
27
+ expectedCharacters: 'à è é ì í î ò ó ù ú',
28
+ characters: /[àèéìíîòóùúÀÈÉÌÍÎÒÓÙÚ]/g,
29
+ minPerThousandLetters: 0.1,
30
+ },
31
+ pl: {
32
+ language: 'Polish',
33
+ expectedCharacters: 'ą ć ę ł ń ó ś ź ż',
34
+ characters: /[ąćęłńóśźżĄĆĘŁŃÓŚŹŻ]/g,
35
+ minPerThousandLetters: 0.1,
36
+ },
37
+ pt: {
38
+ language: 'Portuguese',
39
+ expectedCharacters: 'á â ã à ç é ê í ó ô õ ú ü',
40
+ characters: /[áâãàçéêíóôõúüÁÂÃÀÇÉÊÍÓÔÕÚÜ]/g,
41
+ minPerThousandLetters: 0.1,
42
+ },
43
+ sv: {
44
+ language: 'Swedish',
45
+ expectedCharacters: 'å ä ö',
46
+ characters: /[åäöÅÄÖ]/g,
47
+ minPerThousandLetters: 0.1,
48
+ },
49
+ tr: {
50
+ language: 'Turkish',
51
+ expectedCharacters: 'ç ğ ı İ ö ş ü',
52
+ characters: /[çğıöşüÇĞİÖŞÜ]/g,
53
+ minPerThousandLetters: 0.1,
54
+ },
55
+ } as const;
56
+
57
+ const LETTERS = /\p{L}/gu;
58
+ const TRANSLATABLE_KEYS = ['title', 'description', 'ui', 'seo', 'faq', 'howTo'] as const;
59
+
60
+ function collectStrings(value: unknown): string[] {
61
+ if (typeof value === 'string') return [value];
62
+ if (!value || typeof value !== 'object') return [];
63
+ if (Array.isArray(value)) return value.flatMap(collectStrings);
64
+ return Object.values(value).flatMap(collectStrings);
65
+ }
66
+
67
+ function normalizeText(value: unknown): string {
68
+ return collectStrings(value).join(' ').normalize('NFC');
69
+ }
70
+
71
+ function translatableContent(content: Record<string, unknown>) {
72
+ return TRANSLATABLE_KEYS.map((key) => content[key]);
73
+ }
74
+
75
+ function letterCount(text: string): number {
76
+ return text.match(LETTERS)?.length ?? 0;
77
+ }
78
+
79
+ function diacriticCount(text: string, locale: LocaleWithDiacritics): number {
80
+ return text.match(DIACRITIC_RULES[locale].characters)?.length ?? 0;
81
+ }
82
+
83
+ function diacriticsPerThousandLetters(text: string, locale: LocaleWithDiacritics): number {
84
+ const letters = letterCount(text);
85
+ if (letters === 0) return 0;
86
+ return diacriticCount(text, locale) / letters * 1000;
87
+ }
88
+
89
+ describe('Diacritics density validation', () => {
90
+ ALL_TOOLS.forEach((tool) => {
91
+ describe(`Tool: ${tool.entry.id}`, () => {
92
+ Object.keys(DIACRITIC_RULES).forEach((locale) => {
93
+ it(`${locale} keeps the expected accent and special-letter set`, async () => {
94
+ const typedLocale = locale as LocaleWithDiacritics;
95
+ const loader = tool.entry.i18n[typedLocale];
96
+ if (!loader) return;
97
+
98
+ const content = await loader();
99
+ const text = normalizeText(translatableContent(content as Record<string, unknown>));
100
+ const rule = DIACRITIC_RULES[typedLocale];
101
+ const letters = letterCount(text);
102
+ const matches = diacriticCount(text, typedLocale);
103
+ const density = diacriticsPerThousandLetters(text, typedLocale);
104
+
105
+ expect(
106
+ density,
107
+ [
108
+ `Possible spelling or encoding issue detected in ${tool.entry.id}/${typedLocale} (${rule.language}).`,
109
+ `The text has ${matches} special characters (${density.toFixed(2)} per 1000 letters, ${letters} letters analyzed).`,
110
+ `This locale should include some of these characters: ${rule.expectedCharacters}.`,
111
+ 'If the count is 0 or near 0, accents, tildes, or special letters were probably stripped by encoding or normalization.',
112
+ ].join(' '),
113
+ ).toBeGreaterThanOrEqual(rule.minPerThousandLetters);
114
+ });
115
+ });
116
+ });
117
+ });
118
+ });
@@ -0,0 +1,84 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { ALL_TOOLS } from '../tools';
3
+
4
+ const INVERTED_PUNCTUATION_LOCALES = {
5
+ es: {
6
+ language: 'Spanish',
7
+ questionStart: '¿',
8
+ questionEnd: '?',
9
+ exclamationStart: '¡',
10
+ exclamationEnd: '!',
11
+ },
12
+ } as const;
13
+
14
+ type InvertedPunctuationLocale = keyof typeof INVERTED_PUNCTUATION_LOCALES;
15
+
16
+ const TRANSLATABLE_KEYS = ['title', 'description', 'ui', 'seo', 'faq', 'howTo'] as const;
17
+
18
+ function collectStrings(value: unknown): string[] {
19
+ if (typeof value === 'string') return [value];
20
+ if (!value || typeof value !== 'object') return [];
21
+ if (Array.isArray(value)) return value.flatMap(collectStrings);
22
+ return Object.values(value).flatMap(collectStrings);
23
+ }
24
+
25
+ function translatableStrings(content: Record<string, unknown>): string[] {
26
+ return TRANSLATABLE_KEYS.flatMap((key) => collectStrings(content[key]));
27
+ }
28
+
29
+ function sentenceStart(text: string, endIndex: number): string {
30
+ const beforeMark = text.slice(0, endIndex).trimEnd();
31
+ const boundary = Math.max(
32
+ beforeMark.lastIndexOf('.'),
33
+ beforeMark.lastIndexOf(':'),
34
+ beforeMark.lastIndexOf(';'),
35
+ beforeMark.lastIndexOf('\n'),
36
+ );
37
+
38
+ return beforeMark.slice(boundary + 1).trimStart();
39
+ }
40
+
41
+ function findMissingInvertedMarks(
42
+ text: string,
43
+ startMark: string,
44
+ endMark: string,
45
+ ): string[] {
46
+ return [...text.matchAll(new RegExp(`\\${endMark}`, 'g'))]
47
+ .map((match) => sentenceStart(text, match.index ?? 0))
48
+ .filter((segment) => segment.length > 0 && !segment.includes(startMark))
49
+ .map((segment) => `${segment}${endMark}`);
50
+ }
51
+
52
+ describe('Inverted punctuation validation', () => {
53
+ ALL_TOOLS.forEach((tool) => {
54
+ describe(`Tool: ${tool.entry.id}`, () => {
55
+ Object.keys(INVERTED_PUNCTUATION_LOCALES).forEach((locale) => {
56
+ it(`${locale} uses opening punctuation marks for questions and exclamations`, async () => {
57
+ const typedLocale = locale as InvertedPunctuationLocale;
58
+ const loader = tool.entry.i18n[typedLocale];
59
+ if (!loader) return;
60
+
61
+ const rule = INVERTED_PUNCTUATION_LOCALES[typedLocale];
62
+ const content = await loader();
63
+ const strings = translatableStrings(content as Record<string, unknown>);
64
+ const missingQuestions = strings.flatMap((text) =>
65
+ findMissingInvertedMarks(text, rule.questionStart, rule.questionEnd)
66
+ );
67
+ const missingExclamations = strings.flatMap((text) =>
68
+ findMissingInvertedMarks(text, rule.exclamationStart, rule.exclamationEnd)
69
+ );
70
+ const failures = [...missingQuestions, ...missingExclamations];
71
+
72
+ expect(
73
+ failures,
74
+ [
75
+ `Missing opening punctuation marks in ${tool.entry.id}/${typedLocale} (${rule.language}).`,
76
+ `Questions must use ${rule.questionStart}...${rule.questionEnd} and exclamations must use ${rule.exclamationStart}...${rule.exclamationEnd}.`,
77
+ `Examples: ${failures.slice(0, 5).join(' | ')}`,
78
+ ].join(' '),
79
+ ).toHaveLength(0);
80
+ });
81
+ });
82
+ });
83
+ });
84
+ });
@@ -0,0 +1,70 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+
5
+ function getFiles(dir: string): string[] {
6
+ const results: string[] = [];
7
+ if (!fs.existsSync(dir)) {
8
+ return results;
9
+ }
10
+ const list = fs.readdirSync(dir);
11
+ for (const file of list) {
12
+ const fullPath = path.join(dir, file);
13
+ const stat = fs.statSync(fullPath);
14
+ if (stat && stat.isDirectory()) {
15
+ if (file !== 'tests' && file !== 'node_modules' && file !== '.astro') {
16
+ results.push(...getFiles(fullPath));
17
+ }
18
+ } else {
19
+ results.push(fullPath);
20
+ }
21
+ }
22
+ return results;
23
+ }
24
+
25
+ function isContentFile(filePath: string): boolean {
26
+ return /\\i18n\\/.test(filePath) || filePath.endsWith('bibliography.ts');
27
+ }
28
+
29
+ const srcDir = path.join(process.cwd(), 'src');
30
+ const scriptsDir = path.join(process.cwd(), 'scripts');
31
+ const filesToTest = [
32
+ ...getFiles(srcDir).filter(isContentFile),
33
+ ...getFiles(scriptsDir).filter(isContentFile),
34
+ ];
35
+
36
+ const aiTypographyGarbage = [
37
+ '\u2013',
38
+ '\u2014',
39
+ '\u2026',
40
+ '\u201C',
41
+ '\u201D',
42
+ '\u2018',
43
+ '\u2019',
44
+ '\u00AB',
45
+ '\u00BB',
46
+ '\u200B',
47
+ '\u201E',
48
+ ];
49
+
50
+ describe('Typography Garbage Character Validation', () => {
51
+ filesToTest.forEach((filePath) => {
52
+ const relativePath = path.relative(process.cwd(), filePath);
53
+ it(`should not contain typography garbage characters in ${relativePath}`, () => {
54
+ const content = fs.readFileSync(filePath, 'utf-8');
55
+ const hasAiPatterns = aiTypographyGarbage.some(char => content.includes(char));
56
+ expect(hasAiPatterns).toBe(false);
57
+ });
58
+
59
+ it(`should not contain space before colon in ${relativePath}`, () => {
60
+ const content = fs.readFileSync(filePath, 'utf-8');
61
+ const spaceBeforeColon = / : /.test(content);
62
+ expect(spaceBeforeColon).toBe(false);
63
+ });
64
+
65
+ it(`should not contain double hyphen in ${relativePath}`, () => {
66
+ const content = fs.readFileSync(filePath, 'utf-8');
67
+ expect(content).not.toContain('--');
68
+ });
69
+ });
70
+ });