@jjlmoya/utils-nature 1.20.0 → 1.22.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 +1 -1
- package/src/category/index.ts +3 -2
- package/src/entries.ts +5 -1
- package/src/index.ts +4 -0
- package/src/pages/[locale]/[slug].astro +5 -4
- package/src/tests/diacritics_density.test.ts +1 -1
- package/src/tests/inverted_punctuation.test.ts +1 -1
- package/src/tests/script_density.test.ts +1 -1
- package/src/tests/seo_length.test.ts +1 -0
- package/src/tests/seo_translation_completeness.test.ts +69 -0
- package/src/tests/title_quality.test.ts +1 -1
- package/src/tests/tool_validation.test.ts +2 -3
- package/src/tests/translation_copy.test.ts +2 -2
- package/src/tool/compostBinVolumeRatioCalculator/bibliography.astro +18 -0
- package/src/tool/compostBinVolumeRatioCalculator/bibliography.ts +12 -0
- package/src/tool/compostBinVolumeRatioCalculator/component.astro +77 -0
- package/src/tool/compostBinVolumeRatioCalculator/compost-bin-volume-ratio-calculator.css +509 -0
- package/src/tool/compostBinVolumeRatioCalculator/controller.ts +189 -0
- package/src/tool/compostBinVolumeRatioCalculator/dom-views.ts +162 -0
- package/src/tool/compostBinVolumeRatioCalculator/entry.ts +28 -0
- package/src/tool/compostBinVolumeRatioCalculator/evaluator.ts +26 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/de.ts +193 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/en.ts +193 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/es.ts +193 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/fr.ts +193 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/id.ts +185 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/it.ts +193 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/ja.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/ko.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/nl.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/pl.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/pt.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/ru.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/sv.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/tr.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/zh.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/index.ts +11 -0
- package/src/tool/compostBinVolumeRatioCalculator/logic.test.ts +55 -0
- package/src/tool/compostBinVolumeRatioCalculator/logic.ts +165 -0
- package/src/tool/compostBinVolumeRatioCalculator/seo.astro +23 -0
- package/src/tool/compostBinVolumeRatioCalculator/storage.ts +25 -0
- package/src/tool/compostBinVolumeRatioCalculator/ui.ts +54 -0
- package/src/tool/cricketThermometer/component.astro +1 -1
- package/src/tool/cricketThermometer/i18n/de.ts +2 -2
- package/src/tool/cricketThermometer/i18n/en.ts +2 -2
- package/src/tool/cricketThermometer/i18n/es.ts +2 -2
- package/src/tool/cricketThermometer/i18n/fr.ts +2 -2
- package/src/tool/cricketThermometer/i18n/id.ts +2 -2
- package/src/tool/cricketThermometer/i18n/it.ts +2 -2
- package/src/tool/cricketThermometer/i18n/ja.ts +2 -2
- package/src/tool/cricketThermometer/i18n/ko.ts +2 -2
- package/src/tool/cricketThermometer/i18n/nl.ts +2 -2
- package/src/tool/cricketThermometer/i18n/pl.ts +2 -2
- package/src/tool/cricketThermometer/i18n/pt.ts +2 -2
- package/src/tool/cricketThermometer/i18n/ru.ts +2 -2
- package/src/tool/cricketThermometer/i18n/sv.ts +2 -2
- package/src/tool/cricketThermometer/i18n/tr.ts +2 -2
- package/src/tool/cricketThermometer/i18n/zh.ts +2 -2
- package/src/tool/cricketThermometer/index.ts +1 -0
- package/src/tool/digitalCarbon/component.astro +3 -3
- package/src/tool/digitalCarbon/i18n/de.ts +2 -2
- package/src/tool/digitalCarbon/i18n/en.ts +2 -2
- package/src/tool/digitalCarbon/i18n/es.ts +2 -2
- package/src/tool/digitalCarbon/i18n/fr.ts +2 -2
- package/src/tool/digitalCarbon/i18n/id.ts +2 -2
- package/src/tool/digitalCarbon/i18n/it.ts +2 -2
- package/src/tool/digitalCarbon/i18n/ja.ts +2 -2
- package/src/tool/digitalCarbon/i18n/ko.ts +2 -2
- package/src/tool/digitalCarbon/i18n/nl.ts +2 -2
- package/src/tool/digitalCarbon/i18n/pl.ts +2 -2
- package/src/tool/digitalCarbon/i18n/pt.ts +2 -2
- package/src/tool/digitalCarbon/i18n/ru.ts +2 -2
- package/src/tool/digitalCarbon/i18n/sv.ts +2 -2
- package/src/tool/digitalCarbon/i18n/tr.ts +2 -2
- package/src/tool/digitalCarbon/i18n/zh.ts +2 -2
- package/src/tool/digitalCarbon/index.ts +1 -0
- package/src/tool/rainHarvester/i18n/de.ts +2 -2
- package/src/tool/rainHarvester/i18n/en.ts +2 -2
- package/src/tool/rainHarvester/i18n/es.ts +2 -2
- package/src/tool/rainHarvester/i18n/fr.ts +2 -2
- package/src/tool/rainHarvester/i18n/id.ts +2 -2
- package/src/tool/rainHarvester/i18n/it.ts +2 -2
- package/src/tool/rainHarvester/i18n/ja.ts +2 -2
- package/src/tool/rainHarvester/i18n/ko.ts +2 -2
- package/src/tool/rainHarvester/i18n/nl.ts +2 -2
- package/src/tool/rainHarvester/i18n/pl.ts +2 -2
- package/src/tool/rainHarvester/i18n/pt.ts +2 -2
- package/src/tool/rainHarvester/i18n/ru.ts +2 -2
- package/src/tool/rainHarvester/i18n/sv.ts +2 -2
- package/src/tool/rainHarvester/i18n/tr.ts +2 -2
- package/src/tool/rainHarvester/i18n/zh.ts +2 -2
- package/src/tool/rainHarvester/index.ts +1 -0
- package/src/tool/seedCalculator/i18n/de.ts +2 -2
- package/src/tool/seedCalculator/i18n/en.ts +2 -2
- package/src/tool/seedCalculator/i18n/es.ts +2 -2
- package/src/tool/seedCalculator/i18n/fr.ts +2 -2
- package/src/tool/seedCalculator/i18n/id.ts +2 -2
- package/src/tool/seedCalculator/i18n/it.ts +2 -2
- package/src/tool/seedCalculator/i18n/ja.ts +2 -2
- package/src/tool/seedCalculator/i18n/ko.ts +2 -2
- package/src/tool/seedCalculator/i18n/nl.ts +2 -2
- package/src/tool/seedCalculator/i18n/pl.ts +2 -2
- package/src/tool/seedCalculator/i18n/pt.ts +2 -2
- package/src/tool/seedCalculator/i18n/ru.ts +2 -2
- package/src/tool/seedCalculator/i18n/sv.ts +2 -2
- package/src/tool/seedCalculator/i18n/tr.ts +2 -2
- package/src/tool/seedCalculator/i18n/zh.ts +2 -2
- package/src/tool/seedCalculator/index.ts +1 -0
- package/src/tool/urbanGardenPlanner/bibliography.astro +9 -0
- package/src/tool/urbanGardenPlanner/bibliography.ts +16 -0
- package/src/tool/urbanGardenPlanner/component.astro +131 -0
- package/src/tool/urbanGardenPlanner/controller.ts +88 -0
- package/src/tool/urbanGardenPlanner/dom-views.ts +84 -0
- package/src/tool/urbanGardenPlanner/entry.ts +29 -0
- package/src/tool/urbanGardenPlanner/evaluator.ts +27 -0
- package/src/tool/urbanGardenPlanner/i18n/de.ts +50 -0
- package/src/tool/urbanGardenPlanner/i18n/en.ts +179 -0
- package/src/tool/urbanGardenPlanner/i18n/es.ts +50 -0
- package/src/tool/urbanGardenPlanner/i18n/fr.ts +50 -0
- package/src/tool/urbanGardenPlanner/i18n/id.ts +50 -0
- package/src/tool/urbanGardenPlanner/i18n/it.ts +45 -0
- package/src/tool/urbanGardenPlanner/i18n/ja.ts +39 -0
- package/src/tool/urbanGardenPlanner/i18n/ko.ts +39 -0
- package/src/tool/urbanGardenPlanner/i18n/nl.ts +39 -0
- package/src/tool/urbanGardenPlanner/i18n/pl.ts +39 -0
- package/src/tool/urbanGardenPlanner/i18n/pt.ts +39 -0
- package/src/tool/urbanGardenPlanner/i18n/ru.ts +39 -0
- package/src/tool/urbanGardenPlanner/i18n/sv.ts +39 -0
- package/src/tool/urbanGardenPlanner/i18n/tr.ts +104 -0
- package/src/tool/urbanGardenPlanner/i18n/zh.ts +104 -0
- package/src/tool/urbanGardenPlanner/index.ts +11 -0
- package/src/tool/urbanGardenPlanner/logic.test.ts +45 -0
- package/src/tool/urbanGardenPlanner/logic.ts +55 -0
- package/src/tool/urbanGardenPlanner/seo.astro +15 -0
- package/src/tool/urbanGardenPlanner/storage.ts +25 -0
- package/src/tool/urbanGardenPlanner/ui.ts +38 -0
- package/src/tool/urbanGardenPlanner/urban-garden-rainwater-and-soil-planner.css +531 -0
- package/src/tools.ts +5 -2
- package/src/types.ts +4 -4
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
2
|
+
import { bibliography } from '../bibliography';
|
|
3
|
+
import type { UrbanGardenPlannerLocaleContent } from '../entry';
|
|
4
|
+
|
|
5
|
+
const slug = 'kalkulator-podloza-i-deszczowki-do-ogrodu';
|
|
6
|
+
const title = 'Planer podłoża i deszczówki dla ogrodu miejskiego';
|
|
7
|
+
const description = 'Oblicz objętość podłoża do podwyższonych grządek i oszacuj zbiór deszczówki dla małego ogrodu miejskiego.';
|
|
8
|
+
const faqData = [
|
|
9
|
+
{ question: 'Ile ziemi potrzebuję do podwyższonej grządki?', answer: 'Wpisz powierzchnię uprawy i głębokość podłoża. Planer mnoży te wartości i przelicza wynik na litry, aby ułatwić zamówienie ziemi lub kompostu.' },
|
|
10
|
+
{ question: 'Jak obliczyć deszczówkę dla ogrodu?', answer: 'Wpisz powierzchnię zbierającą wodę i wysokość opadu. Następnie planer stosuje współczynnik spływu 85 procent i zbioru 90 procent jako ostrożne założenie planistyczne.' },
|
|
11
|
+
{ question: 'Czy mogę użyć tego dla donicy na balkonie?', answer: 'Tak. Użyj powierzchni donicy jako obszaru uprawy, podaj planowaną głębokość i powierzchnię dachu lub daszku doprowadzającego wodę do zbiornika.' },
|
|
12
|
+
{ question: 'Czy zebrana deszczówka jest bezpieczna dla roślin jadalnych?', answer: 'Nie zawsze. Sprawdź powierzchnię zbierającą i zbiornik, zapewnij odpowiednie filtrowanie oraz odpływ i przestrzegaj lokalnych zaleceń.' },
|
|
13
|
+
];
|
|
14
|
+
const howToData = [
|
|
15
|
+
{ name: 'Zmierz miejsce uprawy', text: 'Wpisz powierzchnię grządki, balkonu lub pojemnika, który otrzyma podłoże.' },
|
|
16
|
+
{ name: 'Wybierz głębokość podłoża', text: 'Podaj planowaną głębokość w centymetrach, uwzględniając osiadanie.' },
|
|
17
|
+
{ name: 'Dodaj powierzchnię zbioru', text: 'Wpisz dach, daszek lub inną powierzchnię kierującą wodę do zbiornika.' },
|
|
18
|
+
{ name: 'Sprawdź opad', text: 'Wpisz wysokość opadu w milimetrach i porównaj wodę z wielkością ogrodu.' },
|
|
19
|
+
];
|
|
20
|
+
const faqSchema: WithContext<FAQPage> = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faqData.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) };
|
|
21
|
+
const howToSchema: WithContext<HowTo> = { '@context': 'https://schema.org', '@type': 'HowTo', name: title, description, step: howToData.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name, text: step.text })) };
|
|
22
|
+
const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'UtilityApplication', operatingSystem: 'All', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' }, inLanguage: 'pl' };
|
|
23
|
+
export const content: UrbanGardenPlannerLocaleContent = {
|
|
24
|
+
slug, title, description,
|
|
25
|
+
ui: { eyebrow: 'Mały ogród mierzony żywymi warstwami', headInputs: 'Ustaw parametry ogrodu', headScene: 'Odczytaj krajobraz', labelGardenArea: 'Powierzchnia uprawy', labelDepth: 'Głębokość podłoża', labelCollectionArea: 'Powierzchnia zbioru', labelRainfall: 'Opad deszczu', unitSquareMeters: 'm²', unitCentimeters: 'cm', unitMillimeters: 'mm', unitLiters: 'l', helpGardenArea: 'Powierzchnia grządki, balkonu lub pojemnika.', helpDepth: 'Warstwa ziemi, którą chcesz wypełnić.', helpCollectionArea: 'Powierzchnia kierująca wodę do zbiornika.', helpRainfall: 'Sprawdź niedawny deszcz lub lokalny opad projektowy.', presetsTitle: 'Zacznij od kształtu', presetBalcony: 'Donica balkonowa', presetRaisedBed: 'Podwyższona grządka', presetCommunity: 'Ogród społecznościowy', labelSoilNeeded: 'Potrzebne podłoże', labelWaterCaptured: 'Zebrana woda', labelGardenDepth: 'Na tym ogrodzie', labelWateringArea: 'Przy 10 mm wody', sceneCatchment: 'Zbiór', sceneGardenBed: 'Miejsce uprawy', sceneSoil: 'Warstwa ziemi', sceneWater: 'Zebrana woda', statusBalanced: 'Przydatne połączenie do planowania', statusLightCapture: 'Lekki epizod deszczowy', statusDeepBed: 'Głęboki profil ziemi', statusNoRain: 'Oczekiwanie na opad', statusNote: 'Użyj tego obrazu do dobrania materiałów i porównania scenariuszy. To nie jest zalecenie podlewania.', assumptionTitle: 'Założenia planistyczne', assumptionText: 'Szacunek zachowuje 85 procent opadu jako spływ i 90 procent po stratach zbioru. Jeden litr na metrze kwadratowym to jeden milimetr wody.', limitationTitle: 'Zadbaj o bezpieczeństwo', limitationText: 'Zapewnij odpływ, unikaj skażonych powierzchni zbiorczych i sprawdź lokalne przepisy przed użyciem wody na roślinach jadalnych.' },
|
|
26
|
+
seo: [
|
|
27
|
+
{ type: 'title', text: 'Oblicz podłoże i deszczówkę dla miejskiego ogrodu', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: 'Podwyższona grządka, balkon i ogród społecznościowy wymagają dwóch praktycznych odpowiedzi: ile litrów podłoża potrzeba oraz ile deszczu może zebrać pobliska powierzchnia? Ten planer pokazuje oba szacunki razem.' },
|
|
29
|
+
{ type: 'title', text: 'Wzór na objętość podłoża', level: 3 },
|
|
30
|
+
{ type: 'paragraph', html: 'Wzór to <code>powierzchnia w m² × głębokość w cm × 10 = litry podłoża</code>. Grządka o powierzchni 12 m² i głębokości 30 cm potrzebuje 3 600 litrów przed uwzględnieniem osiadania, drenażu i planu upraw.' },
|
|
31
|
+
{ type: 'list', items: ['<strong>Powierzchnia uprawy:</strong> podstawa grządki, balkonu lub pojemnika.', '<strong>Głębokość:</strong> wysokość planowanej warstwy podłoża.', '<strong>Powierzchnia zbioru:</strong> dach, daszek lub inne źródło wody.', '<strong>Opad:</strong> deszcz testowany w milimetrach.'] },
|
|
32
|
+
{ type: 'title', text: 'Szacowanie zbioru deszczówki', level: 3 },
|
|
33
|
+
{ type: 'paragraph', html: 'Szacunek zaczyna się od <code>powierzchnia zbioru × opad</code>, a potem uwzględnia 85 procent spływu i 90 procent po stratach zbioru. Wynik służy do porównania scenariuszy, a nie do obiecywania dostępnej ilości wody.' },
|
|
34
|
+
{ type: 'title', text: 'Porównuj scenariusze offline', level: 3 },
|
|
35
|
+
{ type: 'paragraph', html: 'Wypróbuj presety dla balkonu, grządki i ogrodu społecznościowego, a potem wpisz własne pomiary. Adres, mapa, prognoza pogody ani dane osobowe nie opuszczają przeglądarki.' },
|
|
36
|
+
{ type: 'tip', title: 'Ważne ograniczenia', html: 'Drenaż, jakość wody, parowanie, wybór roślin i lokalne przepisy nadal wymagają decyzji człowieka. Skażony dach lub zbiornik nie jest automatycznie odpowiedni dla roślin jadalnych.' },
|
|
37
|
+
],
|
|
38
|
+
faq: faqData, howTo: howToData, bibliography, schemas: [faqSchema, howToSchema, appSchema],
|
|
39
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
2
|
+
import { bibliography } from '../bibliography';
|
|
3
|
+
import type { UrbanGardenPlannerLocaleContent } from '../entry';
|
|
4
|
+
|
|
5
|
+
const slug = 'calculadora-substrato-e-captacao-agua-chuva';
|
|
6
|
+
const title = 'Planejador de substrato e água da chuva para hortas urbanas';
|
|
7
|
+
const description = 'Calcule o volume de substrato para canteiros elevados e estime a captação de água da chuva para pequenas hortas urbanas.';
|
|
8
|
+
const faqData = [
|
|
9
|
+
{ question: 'De quanto substrato preciso para um canteiro elevado?', answer: 'Informe a área de cultivo e a profundidade do substrato. O planejador multiplica os valores e converte o resultado em litros para facilitar a compra de terra ou composto.' },
|
|
10
|
+
{ question: 'Como calcular a captação de água da chuva para uma horta?', answer: 'Informe a área de captação e a altura da chuva. O planejador aplica um fator de escoamento de 85 por cento e um fator de coleta de 90 por cento para uma estimativa cautelosa.' },
|
|
11
|
+
{ question: 'Posso usar a ferramenta para um vaso de varanda?', answer: 'Sim. Use a área do vaso como área de cultivo, informe a profundidade prevista e acrescente a área do telhado ou toldo que alimenta o recipiente.' },
|
|
12
|
+
{ question: 'A água da chuva captada é segura para plantas comestíveis?', answer: 'Não automaticamente. Verifique a superfície de captação e o recipiente, providencie filtragem e drenagem adequadas e siga as orientações locais.' },
|
|
13
|
+
];
|
|
14
|
+
const howToData = [
|
|
15
|
+
{ name: 'Meça o espaço de cultivo', text: 'Informe a área do canteiro, varanda ou recipiente que receberá o substrato.' },
|
|
16
|
+
{ name: 'Escolha a profundidade', text: 'Digite a profundidade planejada em centímetros, considerando a acomodação do material.' },
|
|
17
|
+
{ name: 'Adicione a área de captação', text: 'Informe o telhado, toldo ou outra superfície que conduz a água até o recipiente.' },
|
|
18
|
+
{ name: 'Teste um evento de chuva', text: 'Digite a chuva em milímetros e compare a água captada com o tamanho da horta.' },
|
|
19
|
+
];
|
|
20
|
+
const faqSchema: WithContext<FAQPage> = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faqData.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) };
|
|
21
|
+
const howToSchema: WithContext<HowTo> = { '@context': 'https://schema.org', '@type': 'HowTo', name: title, description, step: howToData.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name, text: step.text })) };
|
|
22
|
+
const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'UtilityApplication', operatingSystem: 'All', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' }, inLanguage: 'pt' };
|
|
23
|
+
export const content: UrbanGardenPlannerLocaleContent = {
|
|
24
|
+
slug, title, description,
|
|
25
|
+
ui: { eyebrow: 'Uma horta pequena, medida em camadas vivas', headInputs: 'Defina a sua horta', headScene: 'Leia a paisagem', labelGardenArea: 'Área de cultivo', labelDepth: 'Profundidade do substrato', labelCollectionArea: 'Área de captação', labelRainfall: 'Evento de chuva', unitSquareMeters: 'm²', unitCentimeters: 'cm', unitMillimeters: 'mm', unitLiters: 'L', helpGardenArea: 'Área do canteiro, varanda ou vaso.', helpDepth: 'A camada de terra que quer preencher.', helpCollectionArea: 'A superfície que envia água para o recipiente.', helpRainfall: 'Experimente uma chuva recente ou uma chuva de projeto local.', presetsTitle: 'Comece por uma forma', presetBalcony: 'Vaso de varanda', presetRaisedBed: 'Canteiro elevado', presetCommunity: 'Horta comunitária', labelSoilNeeded: 'Substrato necessário', labelWaterCaptured: 'Água captada', labelGardenDepth: 'Sobre esta horta', labelWateringArea: 'Com 10 mm de água', sceneCatchment: 'Captação', sceneGardenBed: 'Área de cultivo', sceneSoil: 'Camada de solo', sceneWater: 'Água captada', statusBalanced: 'Uma combinação útil para planear', statusLightCapture: 'Um evento de chuva leve', statusDeepBed: 'Um perfil de solo profundo', statusNoRain: 'A aguardar um evento de chuva', statusNote: 'Use esta fotografia para dimensionar materiais e comparar cenários. Não é uma prescrição de rega.', assumptionTitle: 'Pressupostos de planeamento', assumptionText: 'A estimativa conserva 85 por cento da chuva como escoamento e 90 por cento depois das perdas de captação. Um litro sobre um metro quadrado equivale a um milímetro de água.', limitationTitle: 'Use a horta com segurança', limitationText: 'Garanta drenagem, evite superfícies de captação contaminadas e confirme as regras locais antes de usar água recolhida em plantas comestíveis.' },
|
|
26
|
+
seo: [
|
|
27
|
+
{ type: 'title', text: 'Calcule substrato e água da chuva para uma horta urbana', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: 'Um canteiro elevado, uma varanda ou uma horta comunitária levantam duas perguntas práticas: quantos litros de substrato são necessários e quanta chuva pode ser recolhida por uma superfície próxima? Este planejador apresenta as duas estimativas em conjunto.' },
|
|
29
|
+
{ type: 'title', text: 'Fórmula do volume de substrato', level: 3 },
|
|
30
|
+
{ type: 'paragraph', html: 'A fórmula é <code>área em m² × profundidade em cm × 10 = litros de substrato</code>. Um canteiro de 12 m² com 30 cm de profundidade precisa de 3.600 litros antes de considerar acomodação, drenagem e o plano de cultivo.' },
|
|
31
|
+
{ type: 'list', items: ['<strong>Área de cultivo:</strong> base do canteiro, varanda ou vaso.', '<strong>Profundidade:</strong> altura planejada da camada de substrato.', '<strong>Captação:</strong> telhado, toldo ou outra superfície de entrada.', '<strong>Chuva:</strong> precipitação a testar em milímetros.'] },
|
|
32
|
+
{ type: 'title', text: 'Estime a captação de água da chuva', level: 3 },
|
|
33
|
+
{ type: 'paragraph', html: 'A estimativa começa com <code>área de captação × chuva</code> e aplica 85 por cento de escoamento e 90 por cento depois das perdas de coleta. O resultado compara cenários e não garante um volume disponível.' },
|
|
34
|
+
{ type: 'title', text: 'Compare cenários sem ligação', level: 3 },
|
|
35
|
+
{ type: 'paragraph', html: 'Experimente os presets de varanda, canteiro e horta comunitária e depois substitua-os pelas suas medidas. O endereço, o mapa, a previsão meteorológica e os dados pessoais não saem do navegador.' },
|
|
36
|
+
{ type: 'tip', title: 'Limites importantes', html: 'Drenagem, qualidade da água, evaporação, escolha das plantas e regras locais ainda exigem uma decisão humana. Um telhado ou recipiente contaminado não é automaticamente adequado para culturas comestíveis.' },
|
|
37
|
+
],
|
|
38
|
+
faq: faqData, howTo: howToData, bibliography, schemas: [faqSchema, howToSchema, appSchema],
|
|
39
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
2
|
+
import { bibliography } from '../bibliography';
|
|
3
|
+
import type { UrbanGardenPlannerLocaleContent } from '../entry';
|
|
4
|
+
|
|
5
|
+
const slug = 'kalkulyator-grunta-i-dozhdevoy-vody-dlya-sada';
|
|
6
|
+
const title = 'Планировщик грунта и дождевой воды для городского сада';
|
|
7
|
+
const description = 'Рассчитайте объём грунта для высокой грядки и оцените сбор дождевой воды для небольшого городского сада.';
|
|
8
|
+
const faqData = [
|
|
9
|
+
{ question: 'Сколько грунта нужно для высокой грядки?', answer: 'Введите площадь посадки и глубину грунта. Планировщик перемножит значения и переведёт результат в литры, чтобы оценить объём земли или компоста.' },
|
|
10
|
+
{ question: 'Как рассчитать дождевую воду для сада?', answer: 'Введите площадь сбора и высоту осадков. Затем планировщик применит коэффициент стока 85 процентов и коэффициент сбора 90 процентов для осторожной оценки.' },
|
|
11
|
+
{ question: 'Можно ли использовать расчёт для балкона?', answer: 'Да. Укажите площадь ящика или грядки как площадь посадки, добавьте глубину грунта и площадь крыши или навеса, который питает ёмкость.' },
|
|
12
|
+
{ question: 'Безопасна ли собранная дождевая вода для съедобных растений?', answer: 'Не всегда. Проверьте поверхность сбора и ёмкость, обеспечьте подходящую фильтрацию и дренаж и соблюдайте местные рекомендации.' },
|
|
13
|
+
];
|
|
14
|
+
const howToData = [
|
|
15
|
+
{ name: 'Измерьте место посадки', text: 'Введите площадь грядки, балкона или контейнера, который получит грунт.' },
|
|
16
|
+
{ name: 'Выберите глубину грунта', text: 'Укажите планируемую глубину в сантиметрах с учётом оседания.' },
|
|
17
|
+
{ name: 'Добавьте площадь сбора', text: 'Введите крышу, навес или другую поверхность, отводящую воду в ёмкость.' },
|
|
18
|
+
{ name: 'Проверьте осадки', text: 'Введите количество осадков в миллиметрах и сравните воду с размером сада.' },
|
|
19
|
+
];
|
|
20
|
+
const faqSchema: WithContext<FAQPage> = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faqData.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) };
|
|
21
|
+
const howToSchema: WithContext<HowTo> = { '@context': 'https://schema.org', '@type': 'HowTo', name: title, description, step: howToData.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name, text: step.text })) };
|
|
22
|
+
const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'UtilityApplication', operatingSystem: 'All', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' }, inLanguage: 'ru' };
|
|
23
|
+
export const content: UrbanGardenPlannerLocaleContent = {
|
|
24
|
+
slug, title, description,
|
|
25
|
+
ui: { eyebrow: 'Небольшой сад, измеренный живыми слоями', headInputs: 'Настройте свой сад', headScene: 'Прочитайте ландшафт', labelGardenArea: 'Площадь посадки', labelDepth: 'Глубина грунта', labelCollectionArea: 'Площадь сбора', labelRainfall: 'Осадки', unitSquareMeters: 'м²', unitCentimeters: 'см', unitMillimeters: 'мм', unitLiters: 'л', helpGardenArea: 'Площадь грядки, балкона или контейнера.', helpDepth: 'Слой грунта, который нужно заполнить.', helpCollectionArea: 'Поверхность, отводящая воду в ёмкость.', helpRainfall: 'Проверьте недавний дождь или местный расчётный ливень.', presetsTitle: 'Начните с формы', presetBalcony: 'Балконный ящик', presetRaisedBed: 'Высокая грядка', presetCommunity: 'Общественный сад', labelSoilNeeded: 'Необходимый грунт', labelWaterCaptured: 'Собранная вода', labelGardenDepth: 'На всей площади сада', labelWateringArea: 'При слое воды 10 мм', sceneCatchment: 'Сбор', sceneGardenBed: 'Место посадки', sceneSoil: 'Слой грунта', sceneWater: 'Собранная вода', statusBalanced: 'Полезное сочетание для планирования', statusLightCapture: 'Небольшой дождь', statusDeepBed: 'Глубокий профиль грунта', statusNoRain: 'Ожидание осадков', statusNote: 'Используйте этот снимок для расчёта материалов и сравнения сценариев. Это не норма полива.', assumptionTitle: 'Расчётные допущения', assumptionText: 'Оценка учитывает 85 процентов осадков как сток и 90 процентов после потерь при сборе. Один литр на квадратном метре равен одному миллиметру воды.', limitationTitle: 'Соблюдайте безопасность', limitationText: 'Предусмотрите дренаж, избегайте загрязнённых поверхностей сбора и проверьте местные правила перед использованием воды для съедобных растений.' },
|
|
26
|
+
seo: [
|
|
27
|
+
{ type: 'title', text: 'Рассчитайте грунт и дождевую воду для городского сада', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: 'Высокая грядка, балкон или общественный сад требуют двух практических ответов: сколько литров грунта нужно и сколько дождя может собрать расположенная рядом поверхность? Планировщик показывает обе оценки вместе.' },
|
|
29
|
+
{ type: 'title', text: 'Формула объёма грунта', level: 3 },
|
|
30
|
+
{ type: 'paragraph', html: 'Формула: <code>площадь в м² × глубина в см × 10 = литры грунта</code>. Для грядки площадью 12 м² и глубиной 30 см потребуется 3 600 литров до учёта оседания, дренажа и плана посадок.' },
|
|
31
|
+
{ type: 'list', items: ['<strong>Площадь посадки:</strong> основание грядки, балкона или контейнера.', '<strong>Глубина:</strong> высота планируемого слоя грунта.', '<strong>Сбор:</strong> крыша, навес или другая поверхность подачи.', '<strong>Осадки:</strong> количество дождя для проверки в миллиметрах.'] },
|
|
32
|
+
{ type: 'title', text: 'Оцените сбор дождевой воды', level: 3 },
|
|
33
|
+
{ type: 'paragraph', html: 'Оценка начинается с <code>площадь сбора × осадки</code>, затем учитывает 85 процентов стока и 90 процентов после потерь сбора. Результат помогает сравнивать сценарии, но не гарантирует доступный объём воды.' },
|
|
34
|
+
{ type: 'title', text: 'Сравнивайте сценарии офлайн', level: 3 },
|
|
35
|
+
{ type: 'paragraph', html: 'Проверьте пресеты для балкона, грядки и общественного сада, затем замените их своими измерениями. Адрес, карта, прогноз погоды и личные данные не покидают браузер.' },
|
|
36
|
+
{ type: 'tip', title: 'Важные ограничения', html: 'Дренаж, качество воды, испарение, выбор растений и местные правила требуют человеческого решения. Загрязнённая крыша или ёмкость не подходят для съедобных культур автоматически.' },
|
|
37
|
+
],
|
|
38
|
+
faq: faqData, howTo: howToData, bibliography, schemas: [faqSchema, howToSchema, appSchema],
|
|
39
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
2
|
+
import { bibliography } from '../bibliography';
|
|
3
|
+
import type { UrbanGardenPlannerLocaleContent } from '../entry';
|
|
4
|
+
|
|
5
|
+
const slug = 'kalkylator-jordvolym-och-regnvatten';
|
|
6
|
+
const title = 'Planerare för jord och regnvatten i stadsodlingen';
|
|
7
|
+
const description = 'Beräkna jordvolym för odlingslådor och uppskatta regnvatten för en liten stadsodling.';
|
|
8
|
+
const faqData = [
|
|
9
|
+
{ question: 'Hur mycket jord behövs till en odlingslåda?', answer: 'Fyll i odlingsytan och jordlagrets djup. Planeraren multiplicerar värdena och omvandlar resultatet till liter så att du kan beställa jord eller kompost.' },
|
|
10
|
+
{ question: 'Hur beräknar jag regnvatten till en odling?', answer: 'Fyll i uppsamlingsytan och regnets höjd. Därefter används en avrinningsfaktor på 85 procent och en insamlingsfaktor på 90 procent för en försiktig uppskattning.' },
|
|
11
|
+
{ question: 'Fungerar den för en balkonglåda?', answer: 'Ja. Använd lådans yta som odlingsyta, fyll i jorddjupet och lägg till taket eller skärmtaket som leder vatten till behållaren.' },
|
|
12
|
+
{ question: 'Är uppsamlat regnvatten säkert för ätbara växter?', answer: 'Inte automatiskt. Kontrollera uppsamlingsyta och behållare, ordna lämplig filtrering och dränering och följ lokala råd.' },
|
|
13
|
+
];
|
|
14
|
+
const howToData = [
|
|
15
|
+
{ name: 'Mät odlingsytan', text: 'Ange ytan för lådan, balkongen eller behållaren som ska fyllas med jord.' },
|
|
16
|
+
{ name: 'Välj jorddjup', text: 'Ange det planerade djupet i centimeter och räkna med att materialet kan sjunka.' },
|
|
17
|
+
{ name: 'Lägg till uppsamlingsyta', text: 'Ange tak, skärmtak eller annan yta som leder vatten till behållaren.' },
|
|
18
|
+
{ name: 'Testa ett regn', text: 'Ange nederbörden i millimeter och jämför vattnet med odlingens storlek.' },
|
|
19
|
+
];
|
|
20
|
+
const faqSchema: WithContext<FAQPage> = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faqData.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) };
|
|
21
|
+
const howToSchema: WithContext<HowTo> = { '@context': 'https://schema.org', '@type': 'HowTo', name: title, description, step: howToData.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name, text: step.text })) };
|
|
22
|
+
const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'UtilityApplication', operatingSystem: 'All', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' }, inLanguage: 'sv' };
|
|
23
|
+
export const content: UrbanGardenPlannerLocaleContent = {
|
|
24
|
+
slug, title, description,
|
|
25
|
+
ui: { eyebrow: 'En liten odling, mätt i levande lager', headInputs: 'Ställ in odlingen', headScene: 'Läs landskapet', labelGardenArea: 'Odlingsyta', labelDepth: 'Jorddjup', labelCollectionArea: 'Uppsamlingsyta', labelRainfall: 'Regnhändelse', unitSquareMeters: 'm²', unitCentimeters: 'cm', unitMillimeters: 'mm', unitLiters: 'L', helpGardenArea: 'Ytan för låda, balkong eller planteringskärl.', helpDepth: 'Jordlagret som ska fyllas.', helpCollectionArea: 'Ytan som leder vatten till behållaren.', helpRainfall: 'Prova ett nyligt regn eller lokal dimensionerande nederbörd.', presetsTitle: 'Börja med en form', presetBalcony: 'Balkonglåda', presetRaisedBed: 'Odlingslåda', presetCommunity: 'Gemensam odling', labelSoilNeeded: 'Jord som behövs', labelWaterCaptured: 'Uppsamlat vatten', labelGardenDepth: 'Över denna odling', labelWateringArea: 'Vid 10 mm vatten', sceneCatchment: 'Uppsamling', sceneGardenBed: 'Odlingsyta', sceneSoil: 'Jordlager', sceneWater: 'Uppsamlat vatten', statusBalanced: 'En användbar kombination för planering', statusLightCapture: 'En liten regnhändelse', statusDeepBed: 'Ett djupt jordlager', statusNoRain: 'Väntar på regn', statusNote: 'Använd översikten för att dimensionera material och jämföra scenarier. Den är inte en bevattningsordination.', assumptionTitle: 'Planeringsantaganden', assumptionText: 'Beräkningen behåller 85 procent av regnet som avrinning och 90 procent efter uppsamlingsförluster. En liter över en kvadratmeter motsvarar en millimeter vatten.', limitationTitle: 'Odla säkert', limitationText: 'Ordna dränering, undvik förorenade uppsamlingsytor och kontrollera lokala regler innan vattnet används på ätbara grödor.' },
|
|
26
|
+
seo: [
|
|
27
|
+
{ type: 'title', text: 'Beräkna jord och regnvatten för en stadsodling', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: 'En odlingslåda, balkong eller gemensam odling väcker två praktiska frågor: hur många liter jord behövs och hur mycket regn kan en närliggande yta samla? Planeraren visar båda uppskattningarna tillsammans.' },
|
|
29
|
+
{ type: 'title', text: 'Formel för jordvolym', level: 3 },
|
|
30
|
+
{ type: 'paragraph', html: 'Formeln är <code>yta i m² × djup i cm × 10 = liter jord</code>. En odling på 12 m² med 30 cm djup behöver 3 600 liter före sättning, dränering och planteringsplan.' },
|
|
31
|
+
{ type: 'list', items: ['<strong>Odlingsyta:</strong> botten på låda, balkong eller kärl.', '<strong>Jorddjup:</strong> höjden på det planerade lagret.', '<strong>Uppsamlingsyta:</strong> tak, skärmtak eller annan tillförsel.', '<strong>Regn:</strong> nederbörd som testas i millimeter.'] },
|
|
32
|
+
{ type: 'title', text: 'Uppskatta regnvatten till odlingen', level: 3 },
|
|
33
|
+
{ type: 'paragraph', html: 'Uppskattningen börjar med <code>uppsamlingsyta × regn</code> och använder sedan 85 procent avrinning och 90 procent efter insamlingsförluster. Resultatet jämför scenarier och garanterar inte en viss vattenmängd.' },
|
|
34
|
+
{ type: 'title', text: 'Jämför scenarier offline', level: 3 },
|
|
35
|
+
{ type: 'paragraph', html: 'Testa förinställningarna för balkong, odlingslåda och gemensam odling och ersätt dem sedan med dina mått. Adress, karta, väderprognos och personuppgifter lämnar inte webbläsaren.' },
|
|
36
|
+
{ type: 'tip', title: 'Viktiga begränsningar', html: 'Dränering, vattenkvalitet, avdunstning, växtval och lokala regler kräver fortfarande mänsklig bedömning. Ett förorenat tak eller en förorenad behållare är inte automatiskt lämplig för ätbara grödor.' },
|
|
37
|
+
],
|
|
38
|
+
faq: faqData, howTo: howToData, bibliography, schemas: [faqSchema, howToSchema, appSchema],
|
|
39
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
2
|
+
import { bibliography } from '../bibliography';
|
|
3
|
+
import type { UrbanGardenPlannerLocaleContent } from '../entry';
|
|
4
|
+
|
|
5
|
+
const slug = 'sehir-bahcesi-toprak-ve-yagmur-suyu-planlayici';
|
|
6
|
+
const title = 'Şehir Bahçesi Toprak ve Yağmur Suyu Planlayıcısı';
|
|
7
|
+
const description = 'Yükseltilmiş yatak veya saksı bahçesi için toprak hacmini ve toplanabilecek yağmur suyunu hesaplayın.';
|
|
8
|
+
|
|
9
|
+
const faqData = [
|
|
10
|
+
{ question: 'Toprak hacmi nasıl hesaplanır?', answer: 'Alanı uzunluk ile genişliğin çarpımı, ardından bu sonucu yatak derinliği ile çarpımı olarak hesaplayın. Sonucu litreye çevirmek için 1000 ile çarpın.' },
|
|
11
|
+
{ question: 'Yağmur suyu ne kadar toplanabilir?', answer: 'Yaklaşık su hacmi, toplama alanı, yağış miktarı ve akış katsayısının çarpımıdır. Planlayıcı, yağış miktarı için seçtiğiniz birimi metrekare başına litre olarak kullanır.' },
|
|
12
|
+
{ question: 'Akış katsayısı ne anlama gelir?', answer: 'Akış katsayısı, yağışın ne kadarının depoya ulaşacağını tahmin eder. Yapraklar, yüzey koşulları ve sıçrama nedeniyle oluşan kayıpları hesaba katmak için 1 değerinden küçük bir katsayı seçin.' },
|
|
13
|
+
{ question: 'Bu hesaplamalar çevrimdışı çalışır mı?', answer: 'Evet. Değerler tarayıcınızda hesaplanır ve kaydedilen senaryolar cihazınızdaki yerel depolama alanında tutulur.' },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
const howToData = [
|
|
17
|
+
{ name: 'Yatak veya saksı ölçülerini girin', text: 'Uzunluk, genişlik ve toprak derinliği değerlerini metre cinsinden yazın.' },
|
|
18
|
+
{ name: 'Yağmur suyu ayarlarını yapın', text: 'Toplama alanını metrekare, yağış miktarını milimetre ve akış katsayısını girin.' },
|
|
19
|
+
{ name: 'Sonuçları karşılaştırın', text: 'Gerekli toprak hacmini ve tahmini yağmur suyu miktarını birlikte inceleyin.' },
|
|
20
|
+
{ name: 'Senaryoyu kaydedin', text: 'Aynı sayfada farklı bahçe seçeneklerini karşılaştırmak için senaryonuza bir ad verip kaydedin.' },
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const faqSchema: WithContext<FAQPage> = {
|
|
24
|
+
'@context': 'https://schema.org',
|
|
25
|
+
'@type': 'FAQPage',
|
|
26
|
+
mainEntity: faqData.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const howToSchema: WithContext<HowTo> = {
|
|
30
|
+
'@context': 'https://schema.org',
|
|
31
|
+
'@type': 'HowTo',
|
|
32
|
+
name: 'Şehir bahçesi toprak ve yağmur suyu hesabı yapma',
|
|
33
|
+
step: howToData.map((item) => ({ '@type': 'HowToStep', name: item.name, text: item.text })),
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const appSchema: WithContext<SoftwareApplication> = {
|
|
37
|
+
'@context': 'https://schema.org',
|
|
38
|
+
'@type': 'SoftwareApplication',
|
|
39
|
+
name: title,
|
|
40
|
+
description,
|
|
41
|
+
applicationCategory: 'UtilitiesApplication',
|
|
42
|
+
operatingSystem: 'Any',
|
|
43
|
+
isAccessibleForFree: true,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const content: UrbanGardenPlannerLocaleContent = {
|
|
47
|
+
slug,
|
|
48
|
+
title,
|
|
49
|
+
description,
|
|
50
|
+
ui: {
|
|
51
|
+
eyebrow: 'Küçük bir bahçe, canlı katmanlarıyla ölçülür',
|
|
52
|
+
headInputs: 'Bahçe koşullarını ayarla',
|
|
53
|
+
headScene: 'Manzarayı oku',
|
|
54
|
+
labelGardenArea: 'Yetiştirme alanı',
|
|
55
|
+
labelDepth: 'Toprak derinliği',
|
|
56
|
+
labelCollectionArea: 'Toplama alanı',
|
|
57
|
+
labelRainfall: 'Yağış olayı',
|
|
58
|
+
unitSquareMeters: 'm²',
|
|
59
|
+
unitCentimeters: 'cm',
|
|
60
|
+
unitMillimeters: 'mm',
|
|
61
|
+
unitLiters: 'L',
|
|
62
|
+
helpGardenArea: 'Yatak, balkon veya saksının kapladığı alan.',
|
|
63
|
+
helpDepth: 'Doldurmak istediğiniz toprak katmanı.',
|
|
64
|
+
helpCollectionArea: 'Suyu deponuza gönderen yüzey.',
|
|
65
|
+
helpRainfall: 'Yakın zamanda yağan yağmuru veya yerel tasarım yağışını deneyin.',
|
|
66
|
+
presetsTitle: 'Bir şekille başlayın',
|
|
67
|
+
presetBalcony: 'Balkon yatağı',
|
|
68
|
+
presetRaisedBed: 'Yükseltilmiş yatak',
|
|
69
|
+
presetCommunity: 'Topluluk bahçesi',
|
|
70
|
+
labelSoilNeeded: 'Gerekli toprak',
|
|
71
|
+
labelWaterCaptured: 'Toplanan su',
|
|
72
|
+
labelGardenDepth: 'Bu bahçe alanına yayılırsa',
|
|
73
|
+
labelWateringArea: '10 mm suyla',
|
|
74
|
+
sceneCatchment: 'Toplama alanı',
|
|
75
|
+
sceneGardenBed: 'Yetiştirme alanı',
|
|
76
|
+
sceneSoil: 'Toprak katmanı',
|
|
77
|
+
sceneWater: 'Toplanan su',
|
|
78
|
+
statusBalanced: 'Planlama için yararlı bir eşleşme',
|
|
79
|
+
statusLightCapture: 'Hafif bir yağış olayı',
|
|
80
|
+
statusDeepBed: 'Derin bir toprak profili',
|
|
81
|
+
statusNoRain: 'Yağış olayı bekleniyor',
|
|
82
|
+
statusNote: 'Malzeme miktarını belirlemek ve senaryoları karşılaştırmak için bu özeti kullanın. Bu bir sulama reçetesi değildir.',
|
|
83
|
+
assumptionTitle: 'Planlama varsayımları',
|
|
84
|
+
assumptionText: 'Tahmin, yağışın yüzde 85 ini akış ve toplama kayıplarından sonra yüzde 90 ını korur. Bir metrekareye yayılan bir litre su, bir milimetre suya eşittir.',
|
|
85
|
+
limitationTitle: 'Bahçeyi güvenli tutun',
|
|
86
|
+
limitationText: 'Drenaj sağlayın, kirlenmiş toplama yüzeylerinden kaçının ve toplanan suyu yenilebilir ürünlerde kullanmadan önce yerel kuralları kontrol edin.',
|
|
87
|
+
},
|
|
88
|
+
seo: [
|
|
89
|
+
{ type: 'title', text: 'Şehir bahçesi için toprak hacmi ve yağmur suyu hesaplayın', level: 2 },
|
|
90
|
+
{ type: 'paragraph', html: 'Yükseltilmiş bir yatak, balkon veya topluluk bahçesi iki pratik soru doğurur: yetiştirme alanını doldurmak için kaç litre toprak gerekir ve yakındaki bir çatı ya da tente ne kadar yağmur suyu toplayabilir? Bu planlayıcı iki tahmini küçük bahçeler, saksılar, balkonlar ve ortak bahçeler için yan yana sunar.' },
|
|
91
|
+
{ type: 'title', text: 'Yükseltilmiş yatak toprak hacmi formülü', level: 3 },
|
|
92
|
+
{ type: 'paragraph', html: 'Hesaplama yerel olarak <code>metrekare cinsinden alan x santimetre cinsinden derinlik x 10 = litre toprak</code> formülüyle yapılır. Örneğin 12 m² alana ve 30 cm derinliğe sahip bir yatak, oturma, drenaj katmanları veya dikim planı hesaba katılmadan önce 3.600 litre gerektirir.' },
|
|
93
|
+
{ type: 'list', items: ['Uzunluk, genişlik ve derinliği metre cinsinden girin.', 'Sonucu litre olarak kontrol edin.', 'Farklı yatak ölçülerini kayıtlı senaryolarla karşılaştırın.'] },
|
|
94
|
+
{ type: 'title', text: 'Yağmur suyu toplama tahmini', level: 3 },
|
|
95
|
+
{ type: 'paragraph', html: 'Su tahmini <code>toplama alanı x yağış miktarı</code> ile başlar, ardından akış için yüzde 85 ve toplama kayıplarından sonra yüzde 90 kullanılır. Bir metrekareye yayılan bir litre su bir milimetreye eşittir; bu da sonucu yetiştirme alanıyla kolayca karşılaştırmayı sağlar.' },
|
|
96
|
+
{ type: 'title', text: 'Bahçe seçeneklerini çevrimdışı karşılaştırın', level: 3 },
|
|
97
|
+
{ type: 'paragraph', html: 'Balkon yatağı, yükseltilmiş yatak ve topluluk bahçesi ön ayarlarını deneyin, sonra bunları kendi ölçülerinizle değiştirin. Araç adres, harita veya hava durumu bağlantısı istemez; senaryolar tarayıcıda kalır ve aynı sayfada karşılaştırılabilir.' },
|
|
98
|
+
{ type: 'tip', title: 'Önemli sınırlar', html: 'Drenaj, su kalitesi, buharlaşma, bitki seçimi ve yerel kurallar insan değerlendirmesi gerektirir. Kirlenmiş çatılar veya depolar, yenilebilir bitkiler için otomatik olarak uygun değildir. Yağış miktarı için bölgenizdeki güvenilir meteoroloji verilerini kullanın.' },
|
|
99
|
+
],
|
|
100
|
+
faq: faqData,
|
|
101
|
+
howTo: howToData,
|
|
102
|
+
bibliography,
|
|
103
|
+
schemas: [faqSchema, howToSchema, appSchema],
|
|
104
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
2
|
+
import { bibliography } from '../bibliography';
|
|
3
|
+
import type { UrbanGardenPlannerLocaleContent } from '../entry';
|
|
4
|
+
|
|
5
|
+
const slug = 'urban-garden-rainwater-and-soil-planner';
|
|
6
|
+
const title = '城市花园土壤与雨水规划器';
|
|
7
|
+
const description = '计算高架种植床或盆栽花园所需的土壤体积,并估算可以收集的雨水量。';
|
|
8
|
+
|
|
9
|
+
const faqData = [
|
|
10
|
+
{ question: '如何计算土壤体积?', answer: '将长度乘以宽度得到种植床面积,再乘以土壤深度。结果乘以 1000 即可换算为升。' },
|
|
11
|
+
{ question: '可以收集多少雨水?', answer: '估算水量等于收集面积、降雨量和径流系数的乘积。规划器将降雨量按每平方米的升数进行计算。' },
|
|
12
|
+
{ question: '径流系数是什么意思?', answer: '径流系数用于估算有多少降雨真正流入储水容器。选择小于 1 的数值,可以反映叶片、表面条件和飞溅造成的损失。' },
|
|
13
|
+
{ question: '这些计算可以离线使用吗?', answer: '可以。所有数值都在浏览器中计算,保存的方案会存放在设备的本地存储中。' },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
const howToData = [
|
|
17
|
+
{ name: '输入种植床或花盆尺寸', text: '输入长度、宽度和土壤深度,单位使用米。' },
|
|
18
|
+
{ name: '设置雨水参数', text: '输入收集面积、降雨量和径流系数。' },
|
|
19
|
+
{ name: '比较结果', text: '同时查看所需土壤体积和预计收集的雨水量。' },
|
|
20
|
+
{ name: '保存方案', text: '为方案命名并保存,以便在同一页面比较不同的城市花园配置。' },
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const faqSchema: WithContext<FAQPage> = {
|
|
24
|
+
'@context': 'https://schema.org',
|
|
25
|
+
'@type': 'FAQPage',
|
|
26
|
+
mainEntity: faqData.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const howToSchema: WithContext<HowTo> = {
|
|
30
|
+
'@context': 'https://schema.org',
|
|
31
|
+
'@type': 'HowTo',
|
|
32
|
+
name: '计算城市花园的土壤和雨水',
|
|
33
|
+
step: howToData.map((item) => ({ '@type': 'HowToStep', name: item.name, text: item.text })),
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const appSchema: WithContext<SoftwareApplication> = {
|
|
37
|
+
'@context': 'https://schema.org',
|
|
38
|
+
'@type': 'SoftwareApplication',
|
|
39
|
+
name: title,
|
|
40
|
+
description,
|
|
41
|
+
applicationCategory: 'UtilitiesApplication',
|
|
42
|
+
operatingSystem: 'Any',
|
|
43
|
+
isAccessibleForFree: true,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const content: UrbanGardenPlannerLocaleContent = {
|
|
47
|
+
slug,
|
|
48
|
+
title,
|
|
49
|
+
description,
|
|
50
|
+
ui: {
|
|
51
|
+
eyebrow: '用有生命的层次测量一座小花园',
|
|
52
|
+
headInputs: '设置花园条件',
|
|
53
|
+
headScene: '阅读这片景观',
|
|
54
|
+
labelGardenArea: '种植面积',
|
|
55
|
+
labelDepth: '土壤深度',
|
|
56
|
+
labelCollectionArea: '收集面积',
|
|
57
|
+
labelRainfall: '降雨事件',
|
|
58
|
+
unitSquareMeters: 'm²',
|
|
59
|
+
unitCentimeters: 'cm',
|
|
60
|
+
unitMillimeters: 'mm',
|
|
61
|
+
unitLiters: 'L',
|
|
62
|
+
helpGardenArea: '种植床、阳台或花盆的占地面积。',
|
|
63
|
+
helpDepth: '准备填入的土壤层厚度。',
|
|
64
|
+
helpCollectionArea: '将水送入储水容器的表面面积。',
|
|
65
|
+
helpRainfall: '可以尝试最近的一场降雨或当地设计降雨量。',
|
|
66
|
+
presetsTitle: '从一种形状开始',
|
|
67
|
+
presetBalcony: '阳台种植床',
|
|
68
|
+
presetRaisedBed: '高架种植床',
|
|
69
|
+
presetCommunity: '社区花园',
|
|
70
|
+
labelSoilNeeded: '所需土壤',
|
|
71
|
+
labelWaterCaptured: '收集到的水',
|
|
72
|
+
labelGardenDepth: '铺满这片花园',
|
|
73
|
+
labelWateringArea: '降雨 10 mm 时',
|
|
74
|
+
sceneCatchment: '收集区',
|
|
75
|
+
sceneGardenBed: '种植空间',
|
|
76
|
+
sceneSoil: '土壤层',
|
|
77
|
+
sceneWater: '收集到的水',
|
|
78
|
+
statusBalanced: '适合规划的组合',
|
|
79
|
+
statusLightCapture: '一次小雨事件',
|
|
80
|
+
statusDeepBed: '较深的土壤剖面',
|
|
81
|
+
statusNoRain: '等待输入降雨事件',
|
|
82
|
+
statusNote: '用这个快照估算材料数量并比较方案。它不是灌溉处方。',
|
|
83
|
+
assumptionTitle: '规划假设',
|
|
84
|
+
assumptionText: '估算将降雨的 85% 作为径流,并在收集损失后保留 90%。一升水铺在一平方米上等于一毫米水深。',
|
|
85
|
+
limitationTitle: '安全使用花园',
|
|
86
|
+
limitationText: '请做好排水,避开受污染的收集表面,并在将收集的雨水用于食用作物前查看当地规定。',
|
|
87
|
+
},
|
|
88
|
+
seo: [
|
|
89
|
+
{ type: 'title', text: '计算城市花园的土壤体积和雨水收集量', level: 2 },
|
|
90
|
+
{ type: 'paragraph', html: '高架种植床、阳台或社区花园都会提出两个实际问题:填满种植空间需要多少升土壤,附近的屋顶、雨棚或阳台在一次降雨中可以收集多少水?这个规划器将两个估算放在一起,适用于小型花园、容器、阳台和社区种植地。' },
|
|
91
|
+
{ type: 'title', text: '高架种植床土壤体积公式', level: 3 },
|
|
92
|
+
{ type: 'paragraph', html: '计算在浏览器本地完成,公式为 <code>面积(平方米)x 深度(厘米)x 10 = 土壤升数</code>。例如,面积为 12 m²、深度为 30 cm 的种植床,在考虑沉降、排水层或种植设计前需要 3600 升。' },
|
|
93
|
+
{ type: 'list', items: ['输入以米为单位的长度、宽度和深度。', '查看以升为单位的结果。', '使用保存的方案比较不同种植床尺寸。'] },
|
|
94
|
+
{ type: 'title', text: '雨水收集估算', level: 3 },
|
|
95
|
+
{ type: 'paragraph', html: '水量估算从 <code>收集面积 x 降雨量</code> 开始,再使用 85% 的径流比例和收集损失后的 90%。一升水铺在一平方米上等于一毫米水深,因此结果可以直接与种植面积比较。' },
|
|
96
|
+
{ type: 'title', text: '离线比较花园方案', level: 3 },
|
|
97
|
+
{ type: 'paragraph', html: '先尝试阳台种植床、高架种植床和社区花园预设,再替换为实测尺寸。计算不需要地址、地图或天气连接,方案保存在浏览器中,可以在同一页面上比较。' },
|
|
98
|
+
{ type: 'tip', title: '重要限制', html: '排水、水质、蒸发、植物选择和当地规定仍然需要人工判断。受到污染的屋顶或储水容器并不自动适合食用作物。降雨量应尽量使用当地可靠的气象数据。' },
|
|
99
|
+
],
|
|
100
|
+
faq: faqData,
|
|
101
|
+
howTo: howToData,
|
|
102
|
+
bibliography,
|
|
103
|
+
schemas: [faqSchema, howToSchema, appSchema],
|
|
104
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ToolDefinition } from '../../types';
|
|
2
|
+
import { urbanGardenPlanner } from './entry';
|
|
3
|
+
|
|
4
|
+
export * from './entry';
|
|
5
|
+
|
|
6
|
+
export const URBAN_GARDEN_PLANNER_TOOL: ToolDefinition = {
|
|
7
|
+
entry: urbanGardenPlanner,
|
|
8
|
+
Component: () => import('./component.astro'),
|
|
9
|
+
SEOComponent: () => import('./seo.astro'),
|
|
10
|
+
BibliographyComponent: () => import('./bibliography.astro'),
|
|
11
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
calculateGardenPlan,
|
|
4
|
+
COLLECTION_FACTOR,
|
|
5
|
+
DEFAULT_INPUTS,
|
|
6
|
+
RUNOFF_FACTOR,
|
|
7
|
+
} from './logic';
|
|
8
|
+
|
|
9
|
+
describe('Urban garden planner logic', () => {
|
|
10
|
+
it('calculates soil, gross water, captured water, and equivalent coverage', () => {
|
|
11
|
+
const result = calculateGardenPlan(DEFAULT_INPUTS);
|
|
12
|
+
|
|
13
|
+
expect(result.soilVolumeLiters).toBe(3600);
|
|
14
|
+
expect(result.grossRainwaterLiters).toBe(500);
|
|
15
|
+
expect(result.harvestedWaterLiters).toBe(382.5);
|
|
16
|
+
expect(result.gardenWaterDepthMm).toBe(31.875);
|
|
17
|
+
expect(result.wateringAreaAt10Mm).toBe(38.25);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('applies runoff and collection factors separately', () => {
|
|
21
|
+
const result = calculateGardenPlan({
|
|
22
|
+
gardenAreaM2: 1,
|
|
23
|
+
substrateDepthCm: 1,
|
|
24
|
+
collectionAreaM2: 2,
|
|
25
|
+
rainfallMm: 10,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
expect(result.harvestedWaterLiters).toBe(20 * RUNOFF_FACTOR * COLLECTION_FACTOR);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('turns invalid or negative measurements into zero', () => {
|
|
32
|
+
const result = calculateGardenPlan({
|
|
33
|
+
gardenAreaM2: -2,
|
|
34
|
+
substrateDepthCm: Number.NaN,
|
|
35
|
+
collectionAreaM2: Number.POSITIVE_INFINITY,
|
|
36
|
+
rainfallMm: 0,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
expect(result.gardenAreaM2).toBe(0);
|
|
40
|
+
expect(result.substrateDepthCm).toBe(0);
|
|
41
|
+
expect(result.collectionAreaM2).toBe(0);
|
|
42
|
+
expect(result.rainfallMm).toBe(0);
|
|
43
|
+
expect(result.gardenWaterDepthMm).toBe(0);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export interface GardenPlanInput {
|
|
2
|
+
gardenAreaM2: number;
|
|
3
|
+
substrateDepthCm: number;
|
|
4
|
+
collectionAreaM2: number;
|
|
5
|
+
rainfallMm: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface GardenPlanResult {
|
|
9
|
+
gardenAreaM2: number;
|
|
10
|
+
substrateDepthCm: number;
|
|
11
|
+
collectionAreaM2: number;
|
|
12
|
+
rainfallMm: number;
|
|
13
|
+
soilVolumeLiters: number;
|
|
14
|
+
grossRainwaterLiters: number;
|
|
15
|
+
harvestedWaterLiters: number;
|
|
16
|
+
gardenWaterDepthMm: number;
|
|
17
|
+
wateringAreaAt10Mm: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const DEFAULT_INPUTS: GardenPlanInput = {
|
|
21
|
+
gardenAreaM2: 12,
|
|
22
|
+
substrateDepthCm: 30,
|
|
23
|
+
collectionAreaM2: 25,
|
|
24
|
+
rainfallMm: 20,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const RUNOFF_FACTOR = 0.85;
|
|
28
|
+
export const COLLECTION_FACTOR = 0.9;
|
|
29
|
+
|
|
30
|
+
function positive(value: number): number {
|
|
31
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function calculateGardenPlan(input: GardenPlanInput): GardenPlanResult {
|
|
35
|
+
const gardenAreaM2 = positive(input.gardenAreaM2);
|
|
36
|
+
const substrateDepthCm = positive(input.substrateDepthCm);
|
|
37
|
+
const collectionAreaM2 = positive(input.collectionAreaM2);
|
|
38
|
+
const rainfallMm = positive(input.rainfallMm);
|
|
39
|
+
const grossRainwaterLiters = collectionAreaM2 * rainfallMm;
|
|
40
|
+
const harvestedWaterLiters = grossRainwaterLiters * RUNOFF_FACTOR * COLLECTION_FACTOR;
|
|
41
|
+
const soilVolumeLiters = gardenAreaM2 * substrateDepthCm * 10;
|
|
42
|
+
const gardenWaterDepthMm = gardenAreaM2 > 0 ? harvestedWaterLiters / gardenAreaM2 : 0;
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
gardenAreaM2,
|
|
46
|
+
substrateDepthCm,
|
|
47
|
+
collectionAreaM2,
|
|
48
|
+
rainfallMm,
|
|
49
|
+
soilVolumeLiters,
|
|
50
|
+
grossRainwaterLiters,
|
|
51
|
+
harvestedWaterLiters,
|
|
52
|
+
gardenWaterDepthMm,
|
|
53
|
+
wateringAreaAt10Mm: harvestedWaterLiters / 10,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { SEORenderer } from '@jjlmoya/utils-shared';
|
|
3
|
+
import { urbanGardenPlanner } from './index';
|
|
4
|
+
import type { KnownLocale } from '../../types';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
locale?: KnownLocale;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const { locale = 'en' } = Astro.props;
|
|
11
|
+
const content = await urbanGardenPlanner.i18n[locale]?.();
|
|
12
|
+
if (!content) return null;
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
{content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { GardenPlanInput } from './logic';
|
|
2
|
+
|
|
3
|
+
const STORAGE_KEY = 'jjlmoya-urban-garden-planner';
|
|
4
|
+
|
|
5
|
+
export function loadGardenPlan(): Partial<GardenPlanInput> | null {
|
|
6
|
+
if (typeof window === 'undefined') return null;
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
const raw = window.localStorage.getItem(STORAGE_KEY);
|
|
10
|
+
if (!raw) return null;
|
|
11
|
+
const parsed: unknown = JSON.parse(raw);
|
|
12
|
+
if (!parsed || typeof parsed !== 'object') return null;
|
|
13
|
+
return parsed as Partial<GardenPlanInput>;
|
|
14
|
+
} catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function saveGardenPlan(input: GardenPlanInput): void {
|
|
20
|
+
if (typeof window === 'undefined') return;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(input));
|
|
24
|
+
} catch {}
|
|
25
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export interface UrbanGardenPlannerUI {
|
|
2
|
+
eyebrow: string;
|
|
3
|
+
headInputs: string;
|
|
4
|
+
headScene: string;
|
|
5
|
+
labelGardenArea: string;
|
|
6
|
+
labelDepth: string;
|
|
7
|
+
labelCollectionArea: string;
|
|
8
|
+
labelRainfall: string;
|
|
9
|
+
unitSquareMeters: string;
|
|
10
|
+
unitCentimeters: string;
|
|
11
|
+
unitMillimeters: string;
|
|
12
|
+
unitLiters: string;
|
|
13
|
+
helpGardenArea: string;
|
|
14
|
+
helpDepth: string;
|
|
15
|
+
helpCollectionArea: string;
|
|
16
|
+
helpRainfall: string;
|
|
17
|
+
presetsTitle: string;
|
|
18
|
+
presetBalcony: string;
|
|
19
|
+
presetRaisedBed: string;
|
|
20
|
+
presetCommunity: string;
|
|
21
|
+
labelSoilNeeded: string;
|
|
22
|
+
labelWaterCaptured: string;
|
|
23
|
+
labelGardenDepth: string;
|
|
24
|
+
labelWateringArea: string;
|
|
25
|
+
sceneCatchment: string;
|
|
26
|
+
sceneGardenBed: string;
|
|
27
|
+
sceneSoil: string;
|
|
28
|
+
sceneWater: string;
|
|
29
|
+
statusBalanced: string;
|
|
30
|
+
statusLightCapture: string;
|
|
31
|
+
statusDeepBed: string;
|
|
32
|
+
statusNoRain: string;
|
|
33
|
+
statusNote: string;
|
|
34
|
+
assumptionTitle: string;
|
|
35
|
+
assumptionText: string;
|
|
36
|
+
limitationTitle: string;
|
|
37
|
+
limitationText: string;
|
|
38
|
+
}
|