@jjlmoya/utils-pets 1.28.0 → 1.30.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 +2 -2
- package/scripts/validate-icons.mjs +57 -0
- package/src/category/index.ts +2 -1
- package/src/data.ts +2 -0
- package/src/entries.ts +4 -1
- package/src/index.ts +1 -0
- package/src/tests/i18n_coverage.test.ts +1 -1
- package/src/tests/locale_completeness.test.ts +1 -1
- package/src/tests/mfe_assets_contract.test.ts +54 -0
- package/src/tests/tool_validation.test.ts +3 -3
- package/src/tool/petCollarSizeCalculator/bibliography.astro +6 -0
- package/src/tool/petCollarSizeCalculator/bibliography.ts +12 -0
- package/src/tool/petCollarSizeCalculator/component.astro +65 -0
- package/src/tool/petCollarSizeCalculator/controller.ts +160 -0
- package/src/tool/petCollarSizeCalculator/dom-views.ts +111 -0
- package/src/tool/petCollarSizeCalculator/entry.ts +32 -0
- package/src/tool/petCollarSizeCalculator/evaluator.ts +18 -0
- package/src/tool/petCollarSizeCalculator/i18n/de.ts +44 -0
- package/src/tool/petCollarSizeCalculator/i18n/en.ts +153 -0
- package/src/tool/petCollarSizeCalculator/i18n/es.ts +44 -0
- package/src/tool/petCollarSizeCalculator/i18n/fr.ts +44 -0
- package/src/tool/petCollarSizeCalculator/i18n/id.ts +44 -0
- package/src/tool/petCollarSizeCalculator/i18n/it.ts +44 -0
- package/src/tool/petCollarSizeCalculator/i18n/ja.ts +44 -0
- package/src/tool/petCollarSizeCalculator/i18n/ko.ts +44 -0
- package/src/tool/petCollarSizeCalculator/i18n/nl.ts +44 -0
- package/src/tool/petCollarSizeCalculator/i18n/pl.ts +44 -0
- package/src/tool/petCollarSizeCalculator/i18n/pt.ts +44 -0
- package/src/tool/petCollarSizeCalculator/i18n/ru.ts +44 -0
- package/src/tool/petCollarSizeCalculator/i18n/sv.ts +44 -0
- package/src/tool/petCollarSizeCalculator/i18n/tr.ts +44 -0
- package/src/tool/petCollarSizeCalculator/i18n/zh.ts +44 -0
- package/src/tool/petCollarSizeCalculator/index.ts +11 -0
- package/src/tool/petCollarSizeCalculator/logic.test.ts +63 -0
- package/src/tool/petCollarSizeCalculator/logic.ts +72 -0
- package/src/tool/petCollarSizeCalculator/pet-collar-size-calculator.css +631 -0
- package/src/tool/petCollarSizeCalculator/seo.astro +14 -0
- package/src/tool/petCollarSizeCalculator/storage.ts +29 -0
- package/src/tool/petCollarSizeCalculator/ui.ts +33 -0
- package/src/tools.ts +3 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
2
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
3
|
+
import type { PetCollarSizeCalculatorLocaleContent } from '../entry';
|
|
4
|
+
import type { PetCollarSizeCalculatorUI } from '../ui';
|
|
5
|
+
|
|
6
|
+
const slug = 'halsbandmaat-huisdier-berekenen';
|
|
7
|
+
const title = 'Halsbandmaat voor huisdieren berekenen';
|
|
8
|
+
const description = 'Meet de hals, voeg bewegingsruimte toe en vind een verstelbaar bereik om met de hand te controleren.';
|
|
9
|
+
const ui: PetCollarSizeCalculatorUI = {
|
|
10
|
+
neckCircumferenceLabel: 'Halsomtrek', unitLabel: 'Weergave', centimetres: 'Centimeter', inches: 'Inches', allowanceLabel: 'Bewegingsruimte', collarTypeLabel: 'Type halsband', flatCollar: 'Plat', breakawayCollar: 'Veiligheidssluiting', martingaleCollar: 'Martingale', statusTight: 'Voeg ruimte toe', statusBalanced: 'Klaar om te controleren', statusLoose: 'Controleer de veiligheid', statusTightDetail: 'Voeg ruimte toe.', statusBalancedDetail: 'Controleer dit bereik met de hand.', statusLooseDetail: 'Controleer of hij niet kan afglijden.', fitStudyLabel: 'Pasvormstudie van de halsband', fitWindowLabel: 'Zoek dit bereik', measuredLabel: 'Gemeten hals', roomLabel: 'Bewegingsruimte', checkLabel: 'Handmatige controle', sceneAria: 'Pasvormstudie met halscirkel en verstelbaar halsbandbereik', neckMarker: 'hals', easeMarker: 'ruimte', rangeMarker: 'halsbandbereik', minimumMarker: 'begin', maximumMarker: 'einde', checkFlat: 'Comfortabel, veilig en zonder schuren.', checkBreakaway: 'Controleer de pasvorm en het ontgrendelingsmechanisme.', checkMartingale: 'De aantreklus mag de hals niet afknellen.', invalidInput: 'Voer een geldige halsomtrek en bewegingsruimte in.',
|
|
11
|
+
};
|
|
12
|
+
const faq: PetCollarSizeCalculatorLocaleContent['faq'] = [
|
|
13
|
+
{ question: 'Hoe meet ik de hals van mijn huisdier?', answer: 'Leg een flexibel meetlint rond de plek waar de halsband komt. Houd het recht en dicht bij de vacht zonder huid of vacht samen te drukken. Meet opnieuw als de positie van de halsband, de vacht of de houding verandert.' },
|
|
14
|
+
{ question: 'Waarom geeft de berekening een bereik?', answer: 'Verstelbare halsbanden hebben verschillende lengtes en maten zijn niet gelijk bij alle fabrikanten. De berekening telt de gekozen ruimte op en maakt een klein vergelijkingsbereik. Daarna moet je de echte halsband bij het dier controleren.' },
|
|
15
|
+
{ question: 'Hoeveel bewegingsruimte moet ik kiezen?', answer: 'Er is geen universele waarde. Vacht, breedte, materiaal en activiteit veranderen de pasvorm. Gebruik het getal als zichtbare aanname en bevestig comfort en veiligheid daarna met een rustige handcontrole.' },
|
|
16
|
+
{ question: 'Werkt dit ook voor een martingale halsband?', answer: 'De eerste schatting gebruikt dezelfde halsomtrek. De eindcontrole is anders: de aantreklus moet begrensd zijn en mag nooit knellen. Volg de instructies van de fabrikant als het mechanisme onbekend is.' },
|
|
17
|
+
{ question: 'Kan ik dit bereik gebruiken voor een jong dier?', answer: 'Ja, als momentopname van de huidige pasvorm. Jonge dieren groeien en hun vacht verandert, dus meet regelmatig opnieuw en controleer de halsband zorgvuldig.' },
|
|
18
|
+
];
|
|
19
|
+
const howTo: PetCollarSizeCalculatorLocaleContent['howTo'] = [
|
|
20
|
+
{ name: 'Meet de hals', text: 'Meet een rustig dier dat natuurlijk staat, op de plek waar de halsband komt. Het lint moet plat liggen en niet trekken.' },
|
|
21
|
+
{ name: 'Kies de ruimte', text: 'Stel de ruimte tussen hals en halsband in met de zichtbare regelaar. De eerste 2 cm zijn alleen een voorbeeld.' },
|
|
22
|
+
{ name: 'Kies het type', text: 'Selecteer plat, veiligheidssluiting of martingale zodat de herinnering bij het mechanisme past.' },
|
|
23
|
+
{ name: 'Vergelijk de instelling', text: 'Zoek een verstelbare halsband die het hele bereik bedekt en doe daarna een fysieke controle.' },
|
|
24
|
+
];
|
|
25
|
+
const seo: PetCollarSizeCalculatorLocaleContent['seo'] = [
|
|
26
|
+
{ type: 'summary', title: 'Van halsmeting naar een aankoopbereik', items: ['Meet waar de halsband echt komt te liggen.', 'Maak bewegingsruimte zichtbaar in plaats van op ras te gokken.', 'Vergelijk het resultaat met de echte verstelruimte van het product.', 'Sluit af met een rustige controle bij het dier.'] },
|
|
27
|
+
{ type: 'title', text: 'Welke keuze helpt deze berekening maken', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: 'Maattabellen zijn lastig als een dier tussen twee maten valt, een dikke vacht heeft of nog groeit. Deze tool begint met een meetwaarde die je zelf kunt controleren: de omtrek op de plek waar de halsband rust. Daarna voeg je de gekozen bewegingsruimte toe. Het resultaat kiest geen commercieel label zoals klein, middel of groot, maar maakt een concreet bereik om met productmaten te vergelijken.' },
|
|
29
|
+
{ type: 'paragraph', html: 'Het bereik is bewust klein en bedoeld als startpunt voor het zoeken. Verstelbare halsbanden hebben geen wereldwijde standaard en de bruikbare lengte kan afwijken van de maatnaam in een winkel. Een product past in de selectie wanneer de verstelruimte het hele bereik afdekt. Het getal bevestigt echter niet vanzelf dat rand, gesp, vacht of mechanisme geschikt zijn.' },
|
|
30
|
+
{ type: 'title', text: 'Meten voordat je koopt', level: 2 },
|
|
31
|
+
{ type: 'list', items: ['Meet als het dier rustig en natuurlijk staat.', 'Houd het lint recht zonder vacht of huid samen te drukken.', 'Meet opnieuw als de halsband hoger of lager moet komen.', 'Noteer bij een jong dier de datum en controleer de pasvorm tijdens de groei.'] },
|
|
32
|
+
{ type: 'paragraph', html: 'De bewegingsruimte is een expliciete aanname, geen veiligheidsgarantie. De juiste waarde hangt af van dier, vacht, breedte, materiaal en gebruik. Een vingercontrole kan richting geven, maar maakt van een getal geen regel voor elk dier. Bij schuren, hoesten, pijn, ademproblemen, stress of beperkte beweging neem je de halsband af en vraag je deskundig advies.' },
|
|
33
|
+
{ type: 'title', text: 'Lees de pasvormcirkel', level: 2 },
|
|
34
|
+
{ type: 'table', headers: ['Signaal', 'Betekenis', 'Volgende stap'], rows: [['Gemeten hals', 'Omtrek vóór de ruimte.', 'Meet opnieuw als het lint schuin of strak zat.'], ['Begin', 'Hals plus gekozen ruimte.', 'Gebruik als ondergrens van de verstelruimte.'], ['Einde', 'Kleine vergelijkingswindow.', 'Zoek een verstelruimte die alles bedekt.'], ['Controle', 'Herinnering bij de gekozen ruimte.', 'Bevestig dit bij het dier.']] },
|
|
35
|
+
{ type: 'title', text: 'Het type halsband verandert de eindcontrole', level: 2 },
|
|
36
|
+
{ type: 'paragraph', html: 'Een platte halsband vraagt om een controle van comfort en veiligheid, terwijl een veiligheidssluiting of martingale extra aandacht voor het mechanisme nodig heeft. Controleer rand, gesp, vacht en aantreklus. Het getal helpt bij het filteren van producten, maar de rustige controle bij het dier en de fabrikant bepalen de uiteindelijke keuze.' },
|
|
37
|
+
{ type: 'tip', title: 'Rustig met de hand controleren', html: 'Doe de halsband om terwijl het dier ontspannen is. Het moet kunnen bewegen, ademen, eten, drinken en de kop draaien zonder schuren. Controleer ook of de halsband niet over de kop kan glijden wanneer hij moet blijven zitten. Controleer opnieuw na trimmen, groei, gewichtsverandering of een andere positie.' },
|
|
38
|
+
];
|
|
39
|
+
const schemas: PetCollarSizeCalculatorLocaleContent['schemas'] = [
|
|
40
|
+
{ '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'LifestyleApplication', operatingSystem: 'Web', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' } } as WithContext<SoftwareApplication>,
|
|
41
|
+
{ '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) } as WithContext<FAQPage>,
|
|
42
|
+
{ '@context': 'https://schema.org', '@type': 'HowTo', name: title, step: howTo.map((step) => ({ '@type': 'HowToStep', name: step.name, text: step.text })) } as WithContext<HowTo>,
|
|
43
|
+
];
|
|
44
|
+
export const content: PetCollarSizeCalculatorLocaleContent = { slug, title, description, ui, seo, faq, bibliography, howTo, schemas };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
2
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
3
|
+
import type { PetCollarSizeCalculatorLocaleContent } from '../entry';
|
|
4
|
+
import type { PetCollarSizeCalculatorUI } from '../ui';
|
|
5
|
+
|
|
6
|
+
const slug = 'kalkulator-rozmiaru-obrozy-dla-zwierzat';
|
|
7
|
+
const title = 'Kalkulator rozmiaru obroży dla zwierząt';
|
|
8
|
+
const description = 'Zmierz szyję, dodaj luz i znajdź regulowany zakres obroży do sprawdzenia na zwierzęciu.';
|
|
9
|
+
const ui: PetCollarSizeCalculatorUI = {
|
|
10
|
+
neckCircumferenceLabel: 'Obwód szyi', unitLabel: 'Wyświetlaj', centimetres: 'Centymetry', inches: 'Cale', allowanceLabel: 'Luz', collarTypeLabel: 'Rodzaj obroży', flatCollar: 'Zwykła', breakawayCollar: 'Bezpieczna', martingaleCollar: 'Martingale', statusTight: 'Dodaj więcej luzu', statusBalanced: 'Gotowe do sprawdzenia', statusLoose: 'Sprawdź bezpieczeństwo', statusTightDetail: 'Dodaj więcej luzu.', statusBalancedDetail: 'Sprawdź ten zakres ręcznie.', statusLooseDetail: 'Sprawdź, czy obroża nie zsuwa się.', fitStudyLabel: 'Badanie dopasowania obroży', fitWindowLabel: 'Znajdź ten zakres', measuredLabel: 'Zmierzona szyja', roomLabel: 'Luz', checkLabel: 'Sprawdzenie ręczne', sceneAria: 'Badanie dopasowania z okręgiem szyi i regulowanym zakresem obroży', neckMarker: 'szyja', easeMarker: 'luz', rangeMarker: 'zakres obroży', minimumMarker: 'początek', maximumMarker: 'koniec', checkFlat: 'Wygodna, bezpieczna i bez otarć.', checkBreakaway: 'Sprawdź dopasowanie i mechanizm otwierania.', checkMartingale: 'Pętla zaciskająca nie może uciskać szyi.', invalidInput: 'Wpisz prawidłowy obwód szyi i luz.',
|
|
11
|
+
};
|
|
12
|
+
const faq: PetCollarSizeCalculatorLocaleContent['faq'] = [
|
|
13
|
+
{ question: 'Jak zmierzyć szyję zwierzęcia?', answer: 'Owiń miękką taśmę w miejscu, w którym będzie leżeć obroża. Trzymaj ją prosto i blisko sierści, ale nie ściskaj skóry ani sierści. Powtórz pomiar, jeśli zmieni się położenie obroży, sierść lub postawa zwierzęcia.' },
|
|
14
|
+
{ question: 'Dlaczego wynik jest zakresem?', answer: 'Regulowane obroże mają różne zakresy i rozmiary nie są takie same u wszystkich producentów. Kalkulator dodaje wybrany luz i tworzy małe okno do porównania. Później trzeba sprawdzić konkretną obrożę na zwierzęciu.' },
|
|
15
|
+
{ question: 'Ile luzu wybrać?', answer: 'Nie ma jednej wartości dla każdego zwierzęcia. Sierść, szerokość, materiał i aktywność zmieniają dopasowanie. Potraktuj liczbę jako widoczne założenie, a komfort i bezpieczeństwo potwierdź spokojnym sprawdzeniem ręcznym.' },
|
|
16
|
+
{ question: 'Czy obliczenie pasuje do obroży martingale?', answer: 'Pierwszy szacunek zaczyna się od tego samego obwodu szyi. Końcowa kontrola jest inna: pętla zaciskająca musi być ograniczona i nie może dusić. Stosuj instrukcję producenta, jeśli konstrukcja jest nieznana.' },
|
|
17
|
+
{ question: 'Czy mogę użyć wyniku dla szczeniaka?', answer: 'Tak, jako obrazu obecnego dopasowania. Młode zwierzęta rosną i zmienia się ich sierść, dlatego pomiar trzeba regularnie powtarzać i uważnie kontrolować.' },
|
|
18
|
+
];
|
|
19
|
+
const howTo: PetCollarSizeCalculatorLocaleContent['howTo'] = [
|
|
20
|
+
{ name: 'Zmierz szyję', text: 'Zmierz spokojne zwierzę stojące naturalnie, w miejscu ułożenia obroży. Taśma powinna być płaska i nie może ciągnąć.' },
|
|
21
|
+
{ name: 'Wybierz luz', text: 'Ustaw odstęp między szyją a obrożą za pomocą widocznego suwaka. Początkowe 2 cm to tylko przykład.' },
|
|
22
|
+
{ name: 'Wybierz rodzaj', text: 'Wybierz obrożę zwykłą, bezpieczną lub martingale, aby przypomnienie pasowało do mechanizmu.' },
|
|
23
|
+
{ name: 'Porównaj regulację', text: 'Znajdź obrożę, której regulacja obejmuje cały wynik, a następnie wykonaj próbę na zwierzęciu.' },
|
|
24
|
+
];
|
|
25
|
+
const seo: PetCollarSizeCalculatorLocaleContent['seo'] = [
|
|
26
|
+
{ type: 'summary', title: 'Od pomiaru do zakresu zakupowego', items: ['Mierz w miejscu, w którym obroża naprawdę będzie leżeć.', 'Pokaż luz zamiast zgadywać na podstawie rasy.', 'Porównaj wynik z rzeczywistym zakresem regulacji produktu.', 'Zakończ spokojną kontrolą na zwierzęciu.'] },
|
|
27
|
+
{ type: 'title', text: 'Jaką decyzję pomaga podjąć kalkulator', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: 'Tabele rozmiarów są niejasne, gdy zwierzę znajduje się między dwoma rozmiarami, ma gęstą sierść albo rośnie. To narzędzie zaczyna od pomiaru, który możesz sprawdzić: obwodu szyi w miejscu ułożenia obroży. Następnie dodajesz wybrany luz. Wynik nie próbuje odgadnąć etykiety handlowej mała, średnia lub duża, tylko tworzy konkretny zakres do porównania z regulacją produktów.' },
|
|
29
|
+
{ type: 'paragraph', html: 'Zakres jest celowo krótki i służy jako punkt wyjścia do zakupów. Regulowane obroże nie mają jednej światowej normy, a użyteczna długość może różnić się od nazwy rozmiaru w sklepie. Produkt pasuje do wyboru, gdy jego regulacja obejmuje cały zakres. Sama liczba nie potwierdza jednak, że odpowiednie są krawędź, klamra, sierść lub mechanizm.' },
|
|
30
|
+
{ type: 'title', text: 'Jak mierzyć przed zakupem', level: 2 },
|
|
31
|
+
{ type: 'list', items: ['Mierz, gdy zwierzę jest spokojne i stoi naturalnie.', 'Trzymaj taśmę poziomo i nie ściskaj sierści ani skóry.', 'Powtórz pomiar, jeśli obroża ma leżeć wyżej lub niżej.', 'U młodego zwierzęcia zapisz datę i kontroluj dopasowanie podczas wzrostu.'] },
|
|
32
|
+
{ type: 'paragraph', html: 'Luz jest jawnym założeniem, a nie gwarancją bezpieczeństwa. Właściwa wartość zależy od zwierzęcia, sierści, szerokości, materiału i sposobu użycia. Próba z palcami może być wskazówką, lecz liczba nie staje się przez to regułą dla każdego. Przy otarciach, kaszlu, bólu, trudnościach z oddychaniem, stresie lub ograniczeniu ruchu zdejmij obrożę i skonsultuj się ze specjalistą.' },
|
|
33
|
+
{ type: 'title', text: 'Czytaj okrąg dopasowania', level: 2 },
|
|
34
|
+
{ type: 'table', headers: ['Sygnał', 'Znaczenie', 'Następny krok'], rows: [['Zmierzona szyja', 'Obwód przed dodaniem luzu.', 'Powtórz pomiar, jeśli taśma była krzywo lub za ciasno.'], ['Początek', 'Szyja plus wybrany luz.', 'Użyj jako dolnej granicy regulacji.'], ['Koniec', 'Małe okno do porównania.', 'Szukaj regulacji obejmującej całe okno.'], ['Kontrola', 'Przypomnienie o wybranym luzie.', 'Potwierdź na zwierzęciu.']] },
|
|
35
|
+
{ type: 'title', text: 'Rodzaj obroży zmienia końcową kontrolę', level: 2 },
|
|
36
|
+
{ type: 'paragraph', html: 'Zwykła obroża wymaga sprawdzenia wygody i bezpieczeństwa, natomiast model bezpieczny lub martingale dodaje pytanie o mechanizm. Sprawdź krawędź, klamrę, sierść i pętlę zaciskającą. Liczba pomaga odfiltrować produkty, ale ostateczna decyzja zależy od spokojnego zwierzęcia i instrukcji producenta.' },
|
|
37
|
+
{ type: 'tip', title: 'Sprawdź spokojnie ręką', html: 'Załóż obrożę, gdy zwierzę jest spokojne. Powinno móc się poruszać, oddychać, jeść, pić i obracać głowę bez otarć. Sprawdź też, czy obroża nie przechodzi przez głowę, gdy ma pozostać na miejscu. Kontroluj ponownie po strzyżeniu, wzroście, zmianie masy lub położenia.' },
|
|
38
|
+
];
|
|
39
|
+
const schemas: PetCollarSizeCalculatorLocaleContent['schemas'] = [
|
|
40
|
+
{ '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'LifestyleApplication', operatingSystem: 'Web', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' } } as WithContext<SoftwareApplication>,
|
|
41
|
+
{ '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) } as WithContext<FAQPage>,
|
|
42
|
+
{ '@context': 'https://schema.org', '@type': 'HowTo', name: title, step: howTo.map((step) => ({ '@type': 'HowToStep', name: step.name, text: step.text })) } as WithContext<HowTo>,
|
|
43
|
+
];
|
|
44
|
+
export const content: PetCollarSizeCalculatorLocaleContent = { slug, title, description, ui, seo, faq, bibliography, howTo, schemas };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
2
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
3
|
+
import type { PetCollarSizeCalculatorLocaleContent } from '../entry';
|
|
4
|
+
import type { PetCollarSizeCalculatorUI } from '../ui';
|
|
5
|
+
|
|
6
|
+
const slug = 'calculadora-tamanho-coleira-animal';
|
|
7
|
+
const title = 'Calculadora de tamanho de coleira para animais';
|
|
8
|
+
const description = 'Meça o pescoço, acrescente espaço de conforto e encontre uma faixa ajustável para conferir manualmente.';
|
|
9
|
+
const ui: PetCollarSizeCalculatorUI = {
|
|
10
|
+
neckCircumferenceLabel: 'Circunferência do pescoço', unitLabel: 'Mostrar', centimetres: 'Centímetros', inches: 'Polegadas', allowanceLabel: 'Espaço de conforto', collarTypeLabel: 'Tipo de coleira', flatCollar: 'Tradicional', breakawayCollar: 'Com abertura', martingaleCollar: 'Martingale', statusTight: 'Acrescente espaço', statusBalanced: 'Pronto para conferir', statusLoose: 'Confira a segurança', statusTightDetail: 'Acrescente espaço.', statusBalancedDetail: 'Confira esta faixa à mão.', statusLooseDetail: 'Confira se não pode escorregar.', fitStudyLabel: 'Estudo de ajuste da coleira', fitWindowLabel: 'Encontre esta faixa', measuredLabel: 'Pescoço medido', roomLabel: 'Espaço de conforto', checkLabel: 'Conferência manual', sceneAria: 'Estudo de ajuste com o círculo do pescoço e a faixa ajustável', neckMarker: 'pescoço', easeMarker: 'espaço', rangeMarker: 'faixa da coleira', minimumMarker: 'início', maximumMarker: 'fim', checkFlat: 'Confortável, segura e sem atrito.', checkBreakaway: 'Confira o ajuste e o mecanismo de abertura.', checkMartingale: 'O laço de tensão não deve apertar o pescoço.', invalidInput: 'Digite uma circunferência e um espaço válidos.',
|
|
11
|
+
};
|
|
12
|
+
const faq: PetCollarSizeCalculatorLocaleContent['faq'] = [
|
|
13
|
+
{ question: 'Como medir o pescoço do meu animal?', answer: 'Passe uma fita flexível no local onde a coleira ficará. Mantenha-a nivelada e próxima do pelo, sem apertar a pele ou o manto. Repita a medição se mudarem a posição da coleira, o pelo ou a postura do animal.' },
|
|
14
|
+
{ question: 'Por que o resultado é uma faixa?', answer: 'Coleiras ajustáveis têm percursos diferentes e os tamanhos não são iguais entre fabricantes. A calculadora soma o espaço escolhido e cria uma pequena faixa de comparação. Depois é preciso testar a coleira real no animal.' },
|
|
15
|
+
{ question: 'Quanto espaço de conforto devo usar?', answer: 'Não existe um número universal. O pelo, a largura, o material e a atividade mudam o ajuste. Use o valor como uma hipótese visível e confirme conforto e segurança com uma conferência manual tranquila.' },
|
|
16
|
+
{ question: 'A fórmula serve para uma coleira martingale?', answer: 'A primeira estimativa parte da mesma circunferência. A verificação final muda: o laço de tensão deve ser limitado e nunca pode sufocar. Siga as instruções do fabricante quando o mecanismo não for familiar.' },
|
|
17
|
+
{ question: 'Posso usar o resultado para um filhote?', answer: 'Sim, como uma fotografia do ajuste atual. Animais jovens crescem e mudam de pelo, por isso a medida deve ser repetida com frequência e conferida com cuidado.' },
|
|
18
|
+
];
|
|
19
|
+
const howTo: PetCollarSizeCalculatorLocaleContent['howTo'] = [
|
|
20
|
+
{ name: 'Meça o pescoço', text: 'Meça o animal calmo e em pé, no ponto onde a coleira ficará. A fita deve permanecer plana e sem apertar.' },
|
|
21
|
+
{ name: 'Escolha o espaço', text: 'Ajuste o espaço entre pescoço e coleira no controle visível. Os 2 cm iniciais são apenas um exemplo.' },
|
|
22
|
+
{ name: 'Escolha o tipo', text: 'Selecione tradicional, com abertura ou martingale para receber o lembrete adequado ao mecanismo.' },
|
|
23
|
+
{ name: 'Compare a regulagem', text: 'Procure uma coleira cuja faixa ajustável cubra todo o resultado e termine com um teste físico.' },
|
|
24
|
+
];
|
|
25
|
+
const seo: PetCollarSizeCalculatorLocaleContent['seo'] = [
|
|
26
|
+
{ type: 'summary', title: 'Da medida a uma faixa para comprar', items: ['Meça onde a coleira ficará de verdade.', 'Deixe o espaço de conforto visível em vez de adivinhar pela raça.', 'Compare o resultado com a regulagem real do produto.', 'Finalize com uma conferência tranquila no animal.'] },
|
|
27
|
+
{ type: 'title', text: 'Que decisão esta calculadora ajuda a tomar', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: 'Tabelas de tamanho ficam confusas quando o animal está entre duas medidas, tem pelo espesso ou ainda está crescendo. Esta ferramenta começa com um dado que você pode conferir: a circunferência no ponto onde a coleira ficará. Depois soma o espaço de conforto escolhido. O resultado não tenta adivinhar um rótulo comercial como pequeno, médio ou grande; cria uma faixa concreta para comparar com a regulagem dos produtos.' },
|
|
29
|
+
{ type: 'paragraph', html: 'A faixa é curta de propósito e funciona como ponto de partida para a compra. Coleiras ajustáveis não seguem uma norma mundial e o comprimento útil pode ser diferente do nome do tamanho anunciado. Um produto entra na seleção quando sua regulagem cobre toda a faixa. Mesmo assim, o número não confirma sozinho a borda, a fivela, o pelo ou o funcionamento do modelo.' },
|
|
30
|
+
{ type: 'title', text: 'Como medir antes de comprar', level: 2 },
|
|
31
|
+
{ type: 'list', items: ['Meça quando o animal estiver calmo e em pé naturalmente.', 'Mantenha a fita nivelada sem comprimir pelo ou pele.', 'Repita se a coleira for ficar mais acima ou mais abaixo.', 'Para animais jovens, anote a data e confira o ajuste durante o crescimento.'] },
|
|
32
|
+
{ type: 'paragraph', html: 'O espaço de conforto é uma hipótese explícita, não uma garantia de segurança. O valor depende do animal, do manto, da largura, do material e do uso. A conferência com os dedos pode servir de referência, mas não transforma um número em regra para todos. Se houver atrito, tosse, dor, dificuldade para respirar, angústia ou movimento limitado, retire a coleira e procure orientação qualificada.' },
|
|
33
|
+
{ type: 'title', text: 'Leia a roda de ajuste', level: 2 },
|
|
34
|
+
{ type: 'table', headers: ['Sinal', 'O que significa', 'Próximo passo'], rows: [['Pescoço medido', 'Circunferência antes do espaço.', 'Repita se a fita estava inclinada ou apertada.'], ['Início', 'Pescoço mais o espaço escolhido.', 'Use como limite inferior da regulagem.'], ['Fim', 'Pequena janela para comparar.', 'Procure uma regulagem que cubra toda a janela.'], ['Conferência', 'Lembrete ligado ao espaço escolhido.', 'Confirme no animal.']] },
|
|
35
|
+
{ type: 'title', text: 'O tipo de coleira muda a revisão final', level: 2 },
|
|
36
|
+
{ type: 'paragraph', html: 'Uma coleira tradicional pede uma revisão de conforto e segurança, enquanto os modelos com abertura ou martingale acrescentam uma pergunta sobre o mecanismo. Confira bordas, fivela, pelo e laços de tensão. O número ajuda a filtrar produtos, mas a decisão final depende do animal calmo e das instruções do fabricante.' },
|
|
37
|
+
{ type: 'tip', title: 'Faça uma conferência tranquila', html: 'Coloque a coleira com o animal relaxado. Ele deve conseguir se mover, respirar, comer, beber e virar a cabeça sem atrito. Confira também se não pode passar pela cabeça quando deve permanecer no lugar. Repita após tosa, crescimento, alteração de peso ou mudança de posição.' },
|
|
38
|
+
];
|
|
39
|
+
const schemas: PetCollarSizeCalculatorLocaleContent['schemas'] = [
|
|
40
|
+
{ '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'LifestyleApplication', operatingSystem: 'Web', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' } } as WithContext<SoftwareApplication>,
|
|
41
|
+
{ '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) } as WithContext<FAQPage>,
|
|
42
|
+
{ '@context': 'https://schema.org', '@type': 'HowTo', name: title, step: howTo.map((step) => ({ '@type': 'HowToStep', name: step.name, text: step.text })) } as WithContext<HowTo>,
|
|
43
|
+
];
|
|
44
|
+
export const content: PetCollarSizeCalculatorLocaleContent = { slug, title, description, ui, seo, faq, bibliography, howTo, schemas };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
2
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
3
|
+
import type { PetCollarSizeCalculatorLocaleContent } from '../entry';
|
|
4
|
+
import type { PetCollarSizeCalculatorUI } from '../ui';
|
|
5
|
+
|
|
6
|
+
const slug = 'kalkulyator-razmera-osheynika-dlya-pitomca';
|
|
7
|
+
const title = 'Калькулятор размера ошейника для питомца';
|
|
8
|
+
const description = 'Измерьте шею, добавьте запас и найдите диапазон регулируемого ошейника для ручной проверки.';
|
|
9
|
+
const ui: PetCollarSizeCalculatorUI = {
|
|
10
|
+
neckCircumferenceLabel: 'Обхват шеи', unitLabel: 'Показать', centimetres: 'Сантиметры', inches: 'Дюймы', allowanceLabel: 'Запас свободы', collarTypeLabel: 'Тип ошейника', flatCollar: 'Обычный', breakawayCollar: 'Безопасный', martingaleCollar: 'Мартингейл', statusTight: 'Добавьте запас', statusBalanced: 'Готово к проверке', statusLoose: 'Проверьте безопасность', statusTightDetail: 'Добавьте запас.', statusBalancedDetail: 'Проверьте этот диапазон вручную.', statusLooseDetail: 'Убедитесь, что ошейник не соскользнёт.', fitStudyLabel: 'Исследование посадки ошейника', fitWindowLabel: 'Ищите этот диапазон', measuredLabel: 'Измеренная шея', roomLabel: 'Запас свободы', checkLabel: 'Ручная проверка', sceneAria: 'Исследование посадки с окружностью шеи и диапазоном регулировки ошейника', neckMarker: 'шея', easeMarker: 'запас', rangeMarker: 'диапазон ошейника', minimumMarker: 'начало', maximumMarker: 'конец', checkFlat: 'Удобно, безопасно, без натирания.', checkBreakaway: 'Проверьте посадку и механизм расстёгивания.', checkMartingale: 'Затягивающая петля не должна сдавливать шею.', invalidInput: 'Введите допустимый обхват шеи и запас.',
|
|
11
|
+
};
|
|
12
|
+
const faq: PetCollarSizeCalculatorLocaleContent['faq'] = [
|
|
13
|
+
{ question: 'Как измерить шею питомца?', answer: 'Оберните мягкую измерительную ленту вокруг места, где будет лежать ошейник. Держите её ровно и близко к шерсти, не сжимая кожу и шерсть. Повторите измерение, если изменились положение ошейника, шерсть или поза животного.' },
|
|
14
|
+
{ question: 'Почему результатом является диапазон?', answer: 'Регулируемые ошейники имеют разный ход, а обозначения размеров отличаются у производителей. Калькулятор добавляет выбранный запас и создаёт небольшой диапазон для сравнения. Затем настоящий ошейник нужно проверить на животном.' },
|
|
15
|
+
{ question: 'Какой запас выбрать?', answer: 'Одного значения для всех животных нет. На посадку влияют шерсть, ширина, материал и активность. Используйте число как видимое предположение, а комфорт и безопасность подтвердите спокойной ручной проверкой.' },
|
|
16
|
+
{ question: 'Подходит ли расчёт для ошейника мартингейл?', answer: 'Первая оценка начинается с того же обхвата шеи. Финальная проверка отличается: затягивающая петля должна иметь ограничение и не может душить. Если конструкция незнакома, следуйте инструкции производителя.' },
|
|
17
|
+
{ question: 'Можно ли использовать результат для щенка или котёнка?', answer: 'Да, как снимок текущей посадки. Молодые животные растут, а шерсть меняется, поэтому измерение нужно регулярно повторять и каждый раз проверять внимательно.' },
|
|
18
|
+
];
|
|
19
|
+
const howTo: PetCollarSizeCalculatorLocaleContent['howTo'] = [
|
|
20
|
+
{ name: 'Измерьте шею', text: 'Измерьте спокойное животное в естественной стойке там, где будет лежать ошейник. Лента должна быть ровной и не натянутой.' },
|
|
21
|
+
{ name: 'Выберите запас', text: 'Настройте расстояние между шеей и ошейником с помощью видимого регулятора. Начальные 2 сантиметра являются только примером.' },
|
|
22
|
+
{ name: 'Выберите тип', text: 'Выберите обычный, безопасный или мартингейл, чтобы получить напоминание для нужного механизма.' },
|
|
23
|
+
{ name: 'Сравните регулировку', text: 'Найдите ошейник, диапазон которого покрывает весь результат, и затем проверьте его на животном.' },
|
|
24
|
+
];
|
|
25
|
+
const seo: PetCollarSizeCalculatorLocaleContent['seo'] = [
|
|
26
|
+
{ type: 'summary', title: 'От измерения к диапазону покупки', items: ['Измеряйте там, где ошейник действительно будет лежать.', 'Покажите запас вместо догадок по породе.', 'Сравните результат с настоящим диапазоном регулировки.', 'Завершите выбор спокойной проверкой на животном.'] },
|
|
27
|
+
{ type: 'title', text: 'Какое решение поддерживает калькулятор', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: 'Таблицы размеров становятся неясными, если животное находится между двумя размерами, имеет густую шерсть или растёт. Этот инструмент начинает с измерения, которое можно проверить: с обхвата шеи в месте расположения ошейника. Затем вы добавляете выбранный запас. Результат не угадывает торговую метку вроде маленький, средний или большой, а создаёт конкретный диапазон для сравнения с регулировкой товара.' },
|
|
29
|
+
{ type: 'paragraph', html: 'Диапазон намеренно короткий и служит отправной точкой для покупки. Для регулируемых ошейников нет единого мирового стандарта, а рабочая длина может отличаться от названия размера в магазине. Товар подходит для дальнейшего сравнения, если его регулировка покрывает весь диапазон. Однако число само по себе не подтверждает пригодность края, пряжки, шерсти или механизма.' },
|
|
30
|
+
{ type: 'title', text: 'Как измерить перед покупкой', level: 2 },
|
|
31
|
+
{ type: 'list', items: ['Измеряйте спокойное животное, стоящее естественно.', 'Держите ленту горизонтально и не сжимайте шерсть или кожу.', 'Повторите измерение, если ошейник должен лежать выше или ниже.', 'Для молодого животного запишите дату и проверяйте посадку во время роста.'] },
|
|
32
|
+
{ type: 'paragraph', html: 'Запас является явным предположением, а не гарантией безопасности. Правильное значение зависит от животного, шерсти, ширины, материала и применения. Проверка пальцами может быть ориентиром, но число не становится правилом для всех. При натирании, кашле, боли, затруднённом дыхании, стрессе или ограничении движений снимите ошейник и обратитесь к специалисту.' },
|
|
33
|
+
{ type: 'title', text: 'Читайте круг посадки', level: 2 },
|
|
34
|
+
{ type: 'table', headers: ['Сигнал', 'Значение', 'Следующий шаг'], rows: [['Измеренная шея', 'Обхват до добавления запаса.', 'Повторите, если лента была наклонена или затянута.'], ['Начало', 'Шея плюс выбранный запас.', 'Используйте как нижнюю границу регулировки.'], ['Конец', 'Небольшое окно для сравнения.', 'Ищите регулировку, покрывающую всё окно.'], ['Проверка', 'Напоминание о выбранном запасе.', 'Подтвердите на животном.']] },
|
|
35
|
+
{ type: 'title', text: 'Тип ошейника меняет финальную проверку', level: 2 },
|
|
36
|
+
{ type: 'paragraph', html: 'Для обычного ошейника нужно проверить комфорт и безопасность, а для безопасной модели или мартингейла дополнительно изучить механизм. Проверьте край, пряжку, шерсть и затягивающую петлю. Число помогает отобрать товары, но окончательное решение зависит от спокойного животного и инструкции производителя.' },
|
|
37
|
+
{ type: 'tip', title: 'Проверьте спокойно руками', html: 'Наденьте ошейник, когда животное расслаблено. Оно должно двигаться, дышать, есть, пить и поворачивать голову без натирания. Убедитесь также, что ошейник не соскальзывает через голову, если он должен оставаться на месте. Повторите проверку после стрижки, роста, изменения веса или положения.' },
|
|
38
|
+
];
|
|
39
|
+
const schemas: PetCollarSizeCalculatorLocaleContent['schemas'] = [
|
|
40
|
+
{ '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'LifestyleApplication', operatingSystem: 'Web', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' } } as WithContext<SoftwareApplication>,
|
|
41
|
+
{ '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) } as WithContext<FAQPage>,
|
|
42
|
+
{ '@context': 'https://schema.org', '@type': 'HowTo', name: title, step: howTo.map((step) => ({ '@type': 'HowToStep', name: step.name, text: step.text })) } as WithContext<HowTo>,
|
|
43
|
+
];
|
|
44
|
+
export const content: PetCollarSizeCalculatorLocaleContent = { slug, title, description, ui, seo, faq, bibliography, howTo, schemas };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
2
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
3
|
+
import type { PetCollarSizeCalculatorLocaleContent } from '../entry';
|
|
4
|
+
import type { PetCollarSizeCalculatorUI } from '../ui';
|
|
5
|
+
|
|
6
|
+
const slug = 'berakna-halsbandsstorlek-husdjur';
|
|
7
|
+
const title = 'Beräkna halsbandsstorlek för husdjur';
|
|
8
|
+
const description = 'Mät halsen, lägg till rörelseutrymme och hitta ett justerbart intervall att kontrollera för hand.';
|
|
9
|
+
const ui: PetCollarSizeCalculatorUI = {
|
|
10
|
+
neckCircumferenceLabel: 'Halsomkrets', unitLabel: 'Visa', centimetres: 'Centimeter', inches: 'Tum', allowanceLabel: 'Rörelseutrymme', collarTypeLabel: 'Halsbandstyp', flatCollar: 'Vanligt', breakawayCollar: 'Säkerhetsöppning', martingaleCollar: 'Martingale', statusTight: 'Lägg till mer utrymme', statusBalanced: 'Redo att kontrollera', statusLoose: 'Kontrollera säkerheten', statusTightDetail: 'Lägg till mer utrymme.', statusBalancedDetail: 'Kontrollera intervallet för hand.', statusLooseDetail: 'Kontrollera att det inte kan glida av.', fitStudyLabel: 'Passformsstudie för halsband', fitWindowLabel: 'Hitta detta intervall', measuredLabel: 'Mätt hals', roomLabel: 'Rörelseutrymme', checkLabel: 'Manuell kontroll', sceneAria: 'Passformsstudie med halsring och justerbart halsbandsintervall', neckMarker: 'hals', easeMarker: 'utrymme', rangeMarker: 'halsbandsintervall', minimumMarker: 'start', maximumMarker: 'slut', checkFlat: 'Bekvämt, säkert och utan skav.', checkBreakaway: 'Kontrollera passform och öppningsmekanism.', checkMartingale: 'Åtdragningsöglan får inte trycka mot halsen.', invalidInput: 'Ange en giltig halsomkrets och ett giltigt utrymme.',
|
|
11
|
+
};
|
|
12
|
+
const faq: PetCollarSizeCalculatorLocaleContent['faq'] = [
|
|
13
|
+
{ question: 'Hur mäter jag halsen på mitt djur?', answer: 'Lägg ett mjukt måttband runt den plats där halsbandet ska sitta. Håll bandet rakt och nära pälsen utan att trycka ihop hud eller päls. Mät igen om halsbandets placering, pälsen eller djurets hållning ändras.' },
|
|
14
|
+
{ question: 'Varför blir resultatet ett intervall?', answer: 'Justerbara halsband har olika långa justeringsvägar och storlekarna är inte enhetliga mellan tillverkare. Verktyget lägger till det utrymme du väljer och skapar ett litet jämförelseintervall. Det riktiga halsbandet måste sedan kontrolleras på djuret.' },
|
|
15
|
+
{ question: 'Hur mycket rörelseutrymme ska jag välja?', answer: 'Det finns inget värde som passar alla. Päls, bredd, material och aktivitet påverkar passformen. Använd talet som ett synligt antagande och bekräfta sedan komfort och säkerhet med en lugn handkontroll.' },
|
|
16
|
+
{ question: 'Fungerar beräkningen för martingalehalsband?', answer: 'Den första uppskattningen utgår från samma halsomkrets. Slutkontrollen är annorlunda: åtdragningsöglan måste begränsas och får aldrig strypa. Följ alltid tillverkarens instruktioner om konstruktionen är obekant.' },
|
|
17
|
+
{ question: 'Kan jag använda resultatet för en valp eller kattunge?', answer: 'Ja, som en bild av den aktuella passformen. Unga djur växer och pälsen förändras, så måttet bör upprepas regelbundet och kontrolleras noggrant.' },
|
|
18
|
+
];
|
|
19
|
+
const howTo: PetCollarSizeCalculatorLocaleContent['howTo'] = [
|
|
20
|
+
{ name: 'Mät halsen', text: 'Mät ett lugnt djur som står naturligt, på platsen där halsbandet ska ligga. Bandet ska vara plant och inte spänt.' },
|
|
21
|
+
{ name: 'Välj utrymmet', text: 'Ställ in utrymmet mellan hals och halsband med det synliga reglaget. De första 2 cm är bara ett exempel.' },
|
|
22
|
+
{ name: 'Välj typ', text: 'Välj vanligt, säkerhetsöppning eller martingale så att påminnelsen passar mekanismen.' },
|
|
23
|
+
{ name: 'Jämför justeringen', text: 'Leta efter ett halsband vars intervall täcker hela resultatet och gör sedan en fysisk kontroll.' },
|
|
24
|
+
];
|
|
25
|
+
const seo: PetCollarSizeCalculatorLocaleContent['seo'] = [
|
|
26
|
+
{ type: 'summary', title: 'Från mätning till ett köpintervall', items: ['Mät där halsbandet verkligen ska sitta.', 'Gör rörelseutrymmet synligt i stället för att gissa efter ras.', 'Jämför resultatet med produktens faktiska justeringsintervall.', 'Avsluta med en lugn kontroll på djuret.'] },
|
|
27
|
+
{ type: 'title', text: 'Vilket beslut beräkningen hjälper dig med', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: 'Storlekstabeller blir svåra när ett djur ligger mellan två mått, har tjock päls eller fortfarande växer. Det här verktyget börjar med ett mått du kan kontrollera: omkretsen på platsen där halsbandet ska vila. Sedan lägger du till det rörelseutrymme du själv väljer. Resultatet försöker inte gissa en kommersiell etikett som liten, medium eller stor, utan skapar ett konkret intervall att jämföra med produkter.' },
|
|
29
|
+
{ type: 'paragraph', html: 'Intervallet är medvetet kort och fungerar som en startpunkt för sökningen. Justerbara halsband följer ingen global standard och den användbara längden kan skilja sig från storleksnamnet i en butik. En produkt passar in i urvalet när justeringen täcker hela intervallet. Talet bekräftar ändå inte automatiskt att kant, spänne, päls eller mekanism passar.' },
|
|
30
|
+
{ type: 'title', text: 'Mät före köpet', level: 2 },
|
|
31
|
+
{ type: 'list', items: ['Mät när djuret är lugnt och står naturligt.', 'Håll bandet vågrätt utan att trycka ihop päls eller hud.', 'Mät igen om halsbandet ska sitta högre eller lägre.', 'Skriv upp datumet för unga djur och kontrollera passformen under tillväxten.'] },
|
|
32
|
+
{ type: 'paragraph', html: 'Rörelseutrymmet är ett tydligt antagande, inte en säkerhetsgaranti. Rätt värde beror på djuret, pälsen, bredden, materialet och användningen. Ett fingerprov kan ge vägledning men gör inte ett tal till en regel för alla. Vid skav, hosta, smärta, andningssvårigheter, stress eller begränsad rörelse ska halsbandet tas av och kvalificerad hjälp sökas.' },
|
|
33
|
+
{ type: 'title', text: 'Läs passformsringen', level: 2 },
|
|
34
|
+
{ type: 'table', headers: ['Signal', 'Betyder', 'Nästa steg'], rows: [['Mätt hals', 'Omkrets före utrymmet.', 'Mät om bandet var snett eller spänt.'], ['Start', 'Hals plus valt utrymme.', 'Använd som nedre gräns för justeringen.'], ['Slut', 'Ett kort jämförelsefönster.', 'Sök en justering som täcker hela fönstret.'], ['Kontroll', 'Påminnelse om valt utrymme.', 'Bekräfta på djuret.']] },
|
|
35
|
+
{ type: 'title', text: 'Halsbandstypen ändrar den sista kontrollen', level: 2 },
|
|
36
|
+
{ type: 'paragraph', html: 'Ett vanligt halsband kräver en kontroll av komfort och säkerhet, medan säkerhetsöppning eller martingale också kräver uppmärksamhet på mekanismen. Kontrollera kant, spänne, päls och åtdragningsögla. Talet hjälper dig att filtrera produkter, men det lugna djuret och tillverkarens instruktioner avgör den slutliga användningen.' },
|
|
37
|
+
{ type: 'tip', title: 'Gör en lugn handkontroll', html: 'Sätt på halsbandet när djuret är avslappnat. Det ska kunna röra sig, andas, äta, dricka och vrida huvudet utan skav. Kontrollera också att det inte kan glida över huvudet när det ska sitta kvar. Kontrollera igen efter pälsvård, tillväxt, viktförändring eller ny placering.' },
|
|
38
|
+
];
|
|
39
|
+
const schemas: PetCollarSizeCalculatorLocaleContent['schemas'] = [
|
|
40
|
+
{ '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'LifestyleApplication', operatingSystem: 'Web', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' } } as WithContext<SoftwareApplication>,
|
|
41
|
+
{ '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) } as WithContext<FAQPage>,
|
|
42
|
+
{ '@context': 'https://schema.org', '@type': 'HowTo', name: title, step: howTo.map((step) => ({ '@type': 'HowToStep', name: step.name, text: step.text })) } as WithContext<HowTo>,
|
|
43
|
+
];
|
|
44
|
+
export const content: PetCollarSizeCalculatorLocaleContent = { slug, title, description, ui, seo, faq, bibliography, howTo, schemas };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
2
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
3
|
+
import type { PetCollarSizeCalculatorLocaleContent } from '../entry';
|
|
4
|
+
import type { PetCollarSizeCalculatorUI } from '../ui';
|
|
5
|
+
|
|
6
|
+
const slug = 'evcil-hayvan-tasma-boyutu-hesaplama';
|
|
7
|
+
const title = 'Evcil hayvan tasma boyutu hesaplama';
|
|
8
|
+
const description = 'Boyun çevresini ölçün, rahatlık payı ekleyin ve elle kontrol edilecek ayarlanabilir tasma aralığını bulun.';
|
|
9
|
+
const ui: PetCollarSizeCalculatorUI = {
|
|
10
|
+
neckCircumferenceLabel: 'Boyun çevresi', unitLabel: 'Göster', centimetres: 'Santimetre', inches: 'İnç', allowanceLabel: 'Rahatlık payı', collarTypeLabel: 'Tasma türü', flatCollar: 'Düz', breakawayCollar: 'Güvenlik açılır', martingaleCollar: 'Martingale', statusTight: 'Daha fazla pay ekleyin', statusBalanced: 'Kontrole hazır', statusLoose: 'Güvenliği kontrol edin', statusTightDetail: 'Daha fazla pay ekleyin.', statusBalancedDetail: 'Bu aralığı elle kontrol edin.', statusLooseDetail: 'Kayarak çıkamayacağını kontrol edin.', fitStudyLabel: 'Tasma uyum çalışması', fitWindowLabel: 'Bu aralığı bulun', measuredLabel: 'Ölçülen boyun', roomLabel: 'Rahatlık payı', checkLabel: 'Elle kontrol', sceneAria: 'Boyun halkasını ve ayarlanabilir tasma aralığını gösteren uyum çalışması', neckMarker: 'boyun', easeMarker: 'pay', rangeMarker: 'tasma aralığı', minimumMarker: 'başlangıç', maximumMarker: 'bitiş', checkFlat: 'Rahat, güvenli ve sürtünmesiz.', checkBreakaway: 'Uyumu ve açılma mekanizmasını kontrol edin.', checkMartingale: 'Sıkma halkası boynu sıkmamalıdır.', invalidInput: 'Geçerli bir boyun çevresi ve rahatlık payı girin.',
|
|
11
|
+
};
|
|
12
|
+
const faq: PetCollarSizeCalculatorLocaleContent['faq'] = [
|
|
13
|
+
{ question: 'Evcil hayvanımın boynunu nasıl ölçerim?', answer: 'Esnek bir mezurayı tasmanın duracağı yere sarın. Deriyi veya tüyleri sıkıştırmadan mezurayı düz ve tüylere yakın tutun. Tasma konumu, tüyler veya hayvanın duruşu değişirse ölçümü tekrarlayın.' },
|
|
14
|
+
{ question: 'Neden tek beden yerine aralık veriliyor?', answer: 'Ayarlanabilir tasmaların ayar mesafeleri farklıdır ve beden etiketleri üreticiler arasında aynı değildir. Hesaplama seçtiğiniz payı ekleyerek küçük bir karşılaştırma aralığı oluşturur. Ardından gerçek tasma hayvan üzerinde kontrol edilmelidir.' },
|
|
15
|
+
{ question: 'Ne kadar rahatlık payı seçmeliyim?', answer: 'Herkes için geçerli tek bir değer yoktur. Tüy, genişlik, malzeme ve aktivite uyumu değiştirir. Sayıyı görünür bir varsayım olarak kullanın ve rahatlığı sakin bir elle kontrol ederek doğrulayın.' },
|
|
16
|
+
{ question: 'Martingale tasma için de kullanılabilir mi?', answer: 'İlk ölçüm aynı boyun çevresinden başlar. Son kontrol farklıdır: sıkma halkası sınırlandırılmalı ve asla boğmamalıdır. Mekanizmayı bilmiyorsanız üretici talimatlarını izleyin.' },
|
|
17
|
+
{ question: 'Sonucu yavru hayvan için kullanabilir miyim?', answer: 'Evet, mevcut uyumun bir görüntüsü olarak kullanabilirsiniz. Yavru hayvanlar büyür ve tüyleri değişir; bu nedenle ölçümü düzenli olarak tekrarlayın.' },
|
|
18
|
+
];
|
|
19
|
+
const howTo: PetCollarSizeCalculatorLocaleContent['howTo'] = [
|
|
20
|
+
{ name: 'Boynu ölçün', text: 'Sakin ve doğal duran hayvanı, tasmanın duracağı yerden ölçün. Mezura düz olmalı ve çekmemelidir.' },
|
|
21
|
+
{ name: 'Payı seçin', text: 'Boyun ile tasma arasındaki payı görünür ayarla değiştirin. Başlangıçtaki 2 cm yalnızca bir örnektir.' },
|
|
22
|
+
{ name: 'Türü seçin', text: 'Düz, güvenlik açılır veya martingale seçerek mekanizmaya uygun kontrol notunu görün.' },
|
|
23
|
+
{ name: 'Ayar aralığını karşılaştırın', text: 'Sonucun tamamını kapsayan bir tasma bulun ve ardından hayvan üzerinde fiziksel kontrol yapın.' },
|
|
24
|
+
];
|
|
25
|
+
const seo: PetCollarSizeCalculatorLocaleContent['seo'] = [
|
|
26
|
+
{ type: 'summary', title: 'Ölçümden alışveriş aralığına', items: ['Tasmanın gerçekten duracağı yerden ölçün.', 'Irka göre tahmin etmek yerine rahatlık payını görünür yapın.', 'Sonucu ürünün gerçek ayar aralığıyla karşılaştırın.', 'Seçimi hayvan üzerinde sakin bir kontrolle bitirin.'] },
|
|
27
|
+
{ type: 'title', text: 'Bu hesaplama hangi kararı destekler', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: 'Beden tabloları, hayvan iki ölçünün arasındaysa, tüyleri yoğunsa veya büyümeye devam ediyorsa zorlaşır. Bu araç sizin kontrol edebileceğiniz bir ölçümle başlar: tasmanın duracağı yerdeki boyun çevresi. Sonra seçtiğiniz rahatlık payını ekler. Sonuç küçük, orta veya büyük gibi ticari bir etiketi tahmin etmez; ürünlerin ayarlanabilir ölçüleriyle karşılaştırılabilecek somut bir aralık oluşturur.' },
|
|
29
|
+
{ type: 'paragraph', html: 'Aralık bilerek kısa tutulur ve alışveriş için başlangıç noktası olarak kullanılır. Ayarlanabilir tasmalar için dünya çapında tek bir standart yoktur; kullanılabilir uzunluk mağazadaki beden adından farklı olabilir. Bir ürün, ayarı aralığın tamamını kapsıyorsa seçime girer. Yine de sayı tek başına kenarın, tokaların, tüylerin veya mekanizmanın uygunluğunu doğrulamaz.' },
|
|
30
|
+
{ type: 'title', text: 'Satın almadan önce nasıl ölçülür', level: 2 },
|
|
31
|
+
{ type: 'list', items: ['Hayvan sakin ve doğal dururken ölçün.', 'Tüyleri veya deriyi sıkıştırmadan mezurayı yatay tutun.', 'Tasma daha yukarıda veya aşağıda duracaksa ölçümü tekrarlayın.', 'Yavru hayvanlarda tarihi not edin ve büyüme boyunca uyumu kontrol edin.'] },
|
|
32
|
+
{ type: 'paragraph', html: 'Rahatlık payı açık bir varsayımdır, güvenlik garantisi değildir. Doğru değer hayvana, tüylere, genişliğe, malzemeye ve kullanıma bağlıdır. Parmak kontrolü yol gösterebilir ama bir sayıyı herkes için kurala dönüştürmez. Sürtünme, öksürük, ağrı, nefes alma güçlüğü, stres veya kısıtlı hareket görülürse tasmayı çıkarın ve uzman görüşü alın.' },
|
|
33
|
+
{ type: 'title', text: 'Uyum halkasını okuyun', level: 2 },
|
|
34
|
+
{ type: 'table', headers: ['Sinyal', 'Anlamı', 'Sonraki adım'], rows: [['Ölçülen boyun', 'Pay eklenmeden önceki çevre.', 'Mezura eğri veya sıkıysa tekrar ölçün.'], ['Başlangıç', 'Boyun ve seçilen pay.', 'Ayarlanabilir aralığın alt sınırı olarak kullanın.'], ['Bitiş', 'Karşılaştırma için kısa pencere.', 'Pencerenin tamamını kapsayan ayar arayın.'], ['Kontrol', 'Seçilen pay için hatırlatma.', 'Hayvan üzerinde doğrulayın.']] },
|
|
35
|
+
{ type: 'title', text: 'Tasma türü son kontrolü değiştirir', level: 2 },
|
|
36
|
+
{ type: 'paragraph', html: 'Düz tasma konfor ve güvenlik kontrolü ister; güvenlik açılır veya martingale modellerinde mekanizma ayrıca incelenmelidir. Kenarı, tokayı, tüyleri ve sıkma halkasını kontrol edin. Sayı ürünleri filtrelemeye yardım eder, ancak son karar sakin hayvana ve üretici talimatlarına bağlıdır.' },
|
|
37
|
+
{ type: 'tip', title: 'Sakin bir elle kontrol yapın', html: 'Tasmayı hayvan rahatlarken takın. Hayvan sürtünme olmadan hareket edebilmeli, nefes alabilmeli, yiyebilmeli, içebilmeli ve başını çevirebilmelidir. Yerinde kalması gerekiyorsa başın üzerinden çıkmadığını da kontrol edin. Tıraş, büyüme, kilo değişimi veya konum değişiminden sonra yeniden bakın.' },
|
|
38
|
+
];
|
|
39
|
+
const schemas: PetCollarSizeCalculatorLocaleContent['schemas'] = [
|
|
40
|
+
{ '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'LifestyleApplication', operatingSystem: 'Web', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' } } as WithContext<SoftwareApplication>,
|
|
41
|
+
{ '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) } as WithContext<FAQPage>,
|
|
42
|
+
{ '@context': 'https://schema.org', '@type': 'HowTo', name: title, step: howTo.map((step) => ({ '@type': 'HowToStep', name: step.name, text: step.text })) } as WithContext<HowTo>,
|
|
43
|
+
];
|
|
44
|
+
export const content: PetCollarSizeCalculatorLocaleContent = { slug, title, description, ui, seo, faq, bibliography, howTo, schemas };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
2
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
3
|
+
import type { PetCollarSizeCalculatorLocaleContent } from '../entry';
|
|
4
|
+
import type { PetCollarSizeCalculatorUI } from '../ui';
|
|
5
|
+
|
|
6
|
+
const slug = 'pet-collar-size-calculator';
|
|
7
|
+
const title = '宠物项圈尺寸计算器';
|
|
8
|
+
const description = '测量颈围,加入舒适余量,找到可以在宠物身上手动检查的可调项圈范围。';
|
|
9
|
+
const ui: PetCollarSizeCalculatorUI = {
|
|
10
|
+
neckCircumferenceLabel: '颈围', unitLabel: '显示', centimetres: '厘米', inches: '英寸', allowanceLabel: '舒适余量', collarTypeLabel: '项圈类型', flatCollar: '普通项圈', breakawayCollar: '安全脱扣', martingaleCollar: '马丁格尔', statusTight: '增加余量', statusBalanced: '可以检查', statusLoose: '检查安全性', statusTightDetail: '请增加余量。', statusBalancedDetail: '请用手检查这个范围。', statusLooseDetail: '确认不会滑脱。', fitStudyLabel: '项圈贴合研究', fitWindowLabel: '寻找这个范围', measuredLabel: '测得颈围', roomLabel: '舒适余量', checkLabel: '手动检查', sceneAria: '显示颈部圆环和可调项圈范围的贴合研究', neckMarker: '颈部', easeMarker: '余量', rangeMarker: '项圈范围', minimumMarker: '起点', maximumMarker: '终点', checkFlat: '舒适、安全,没有摩擦。', checkBreakaway: '检查贴合度和脱扣装置。', checkMartingale: '收紧环不能压迫颈部。', invalidInput: '请输入有效的颈围和余量。',
|
|
11
|
+
};
|
|
12
|
+
const faq: PetCollarSizeCalculatorLocaleContent['faq'] = [
|
|
13
|
+
{ question: '如何测量宠物的颈围?', answer: '将柔软的软尺绕在项圈实际放置的位置。保持软尺水平并靠近毛发,不要压紧皮肤或毛发。如果项圈位置、毛发或宠物姿势发生变化,请重新测量。' },
|
|
14
|
+
{ question: '为什么结果是一个范围而不是单一尺寸?', answer: '可调项圈的调节长度不同,不同制造商的尺寸标签也不统一。计算器会加入你选择的余量,并生成一个小的比较范围。最后仍要把实际项圈戴在宠物身上检查。' },
|
|
15
|
+
{ question: '应该选择多少舒适余量?', answer: '没有适合所有宠物的固定数值。毛发、宽度、材料和活动都会改变贴合度。把数字当作可见的假设,再通过平静的手动检查确认舒适和安全。' },
|
|
16
|
+
{ question: '马丁格尔项圈也可以使用吗?', answer: '初步估算使用同一个颈围。最后的检查不同:收紧环必须有限制,不能造成勒压。如果不了解结构,请遵循制造商说明。' },
|
|
17
|
+
{ question: '幼年宠物也可以使用这个结果吗?', answer: '可以把它作为当前贴合度的参考。幼年宠物会成长,毛发也会变化,因此要定期重新测量并仔细检查。' },
|
|
18
|
+
];
|
|
19
|
+
const howTo: PetCollarSizeCalculatorLocaleContent['howTo'] = [
|
|
20
|
+
{ name: '测量颈围', text: '宠物平静并自然站立时,在项圈放置的位置测量。软尺应保持平整,不要拉紧。' },
|
|
21
|
+
{ name: '选择余量', text: '用可见的滑块设置颈部与项圈之间的空间。初始的2厘米只是示例。' },
|
|
22
|
+
{ name: '选择类型', text: '选择普通项圈、安全脱扣或马丁格尔,查看对应结构的检查提示。' },
|
|
23
|
+
{ name: '比较调节范围', text: '寻找能够覆盖整个结果的项圈,然后在宠物身上实际检查。' },
|
|
24
|
+
];
|
|
25
|
+
const seo: PetCollarSizeCalculatorLocaleContent['seo'] = [
|
|
26
|
+
{ type: 'summary', title: '把测量值变成购买范围', items: ['在项圈实际放置的位置测量。', '让舒适余量可见,不要只按品种猜测。', '把结果和产品真实的调节范围比较。', '最后在宠物身上平静地检查。'] },
|
|
27
|
+
{ type: 'title', text: '这个计算器帮助你做什么决定', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: '当宠物处于两个尺寸之间、毛发较厚或仍在成长时,尺寸表会变得含糊。这个工具从一个可以自己确认的数值开始:项圈放置位置的颈围。然后加入你选择的舒适余量。结果不会猜测小号、中号或大号等商品标签,而是生成可以和产品可调尺寸比较的具体范围。' },
|
|
29
|
+
{ type: 'paragraph', html: '范围有意保持较短,用作购物时的起点。可调项圈没有全球统一标准,实际可用长度也可能和商品页面上的尺寸名称不同。当产品的调节范围覆盖整个结果时,它才适合进入候选列表。不过,数字本身不能证明边缘、扣件、毛发、材料或结构一定合适。' },
|
|
30
|
+
{ type: 'title', text: '购买前如何测量', level: 2 },
|
|
31
|
+
{ type: 'list', items: ['宠物平静并自然站立时测量。', '保持软尺水平,不要压紧毛发或皮肤。', '如果项圈要放得更高或更低,请重新测量。', '幼年宠物要记录日期,并在成长过程中持续检查贴合度。'] },
|
|
32
|
+
{ type: 'paragraph', html: '舒适余量是明确的假设,不是安全保证。合适的数值取决于宠物、毛发、宽度、材料和使用方式。手指检查可以提供参考,但不能把一个数字变成适用于所有宠物的规则。如果出现摩擦、咳嗽、疼痛、呼吸困难、紧张或活动受限,请取下项圈并咨询专业人士。' },
|
|
33
|
+
{ type: 'title', text: '阅读贴合圆环', level: 2 },
|
|
34
|
+
{ type: 'table', headers: ['信号', '含义', '下一步'], rows: [['测得颈围', '加入余量前的周长。', '如果软尺倾斜或太紧,请重新测量。'], ['起点', '颈围加上选择的余量。', '作为调节范围的下限。'], ['终点', '用于比较的小窗口。', '寻找覆盖整个窗口的调节范围。'], ['检查', '关于所选余量的提示。', '在宠物身上确认。']] },
|
|
35
|
+
{ type: 'title', text: '项圈类型会改变最后的检查', level: 2 },
|
|
36
|
+
{ type: 'paragraph', html: '普通项圈需要检查舒适度和安全性,安全脱扣或马丁格尔则还要检查结构。请观察边缘、扣件、毛发和收紧环。数字可以帮助筛选产品,但最后要结合放松的宠物状态和制造商说明来决定。' },
|
|
37
|
+
{ type: 'tip', title: '安静地用手检查', html: '宠物放松时戴上项圈。它应该能够无摩擦地移动、呼吸、进食、饮水和转动头部。如果项圈需要保持在原位,也要确认它不会从头部滑脱。美容、成长、体重变化或位置变化后都要重新检查。' },
|
|
38
|
+
];
|
|
39
|
+
const schemas: PetCollarSizeCalculatorLocaleContent['schemas'] = [
|
|
40
|
+
{ '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'LifestyleApplication', operatingSystem: 'Web', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' } } as WithContext<SoftwareApplication>,
|
|
41
|
+
{ '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) } as WithContext<FAQPage>,
|
|
42
|
+
{ '@context': 'https://schema.org', '@type': 'HowTo', name: title, step: howTo.map((step) => ({ '@type': 'HowToStep', name: step.name, text: step.text })) } as WithContext<HowTo>,
|
|
43
|
+
];
|
|
44
|
+
export const content: PetCollarSizeCalculatorLocaleContent = { slug, title, description, ui, seo, faq, bibliography, howTo, schemas };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ToolDefinition } from '../../types';
|
|
2
|
+
import { petCollarSizeCalculator } from './entry';
|
|
3
|
+
|
|
4
|
+
export * from './entry';
|
|
5
|
+
|
|
6
|
+
export const PET_COLLAR_SIZE_CALCULATOR_TOOL: ToolDefinition = {
|
|
7
|
+
entry: petCollarSizeCalculator,
|
|
8
|
+
Component: () => import('./component.astro'),
|
|
9
|
+
SEOComponent: () => import('./seo.astro'),
|
|
10
|
+
BibliographyComponent: () => import('./bibliography.astro'),
|
|
11
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
calculatePetCollarSize,
|
|
4
|
+
evaluateAllowance,
|
|
5
|
+
fromCentimetres,
|
|
6
|
+
toCentimetres,
|
|
7
|
+
} from './logic';
|
|
8
|
+
|
|
9
|
+
describe('pet collar size calculator', () => {
|
|
10
|
+
it('converts inches and centimetres without changing the physical value', () => {
|
|
11
|
+
expect(toCentimetres(10, 'in')).toBeCloseTo(25.4);
|
|
12
|
+
expect(fromCentimetres(25.4, 'in')).toBeCloseTo(10);
|
|
13
|
+
expect(toCentimetres(25.4, 'cm')).toBe(25.4);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('adds the selected allowance and returns a two centimetre search window', () => {
|
|
17
|
+
const result = calculatePetCollarSize({
|
|
18
|
+
neckCircumference: 32,
|
|
19
|
+
allowance: 2,
|
|
20
|
+
unit: 'cm',
|
|
21
|
+
collarType: 'flat',
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
expect(result.valid).toBe(true);
|
|
25
|
+
expect(result.minimumCm).toBe(34);
|
|
26
|
+
expect(result.targetCm).toBe(35);
|
|
27
|
+
expect(result.maximumCm).toBe(36);
|
|
28
|
+
expect(result.status).toBe('balanced');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('keeps the calculation in centimetres when the user enters inches', () => {
|
|
32
|
+
const result = calculatePetCollarSize({
|
|
33
|
+
neckCircumference: 12.5984,
|
|
34
|
+
allowance: 0.7874,
|
|
35
|
+
unit: 'in',
|
|
36
|
+
collarType: 'breakaway',
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
expect(result.valid).toBe(true);
|
|
40
|
+
expect(result.neckCm).toBeCloseTo(32);
|
|
41
|
+
expect(result.allowanceCm).toBeCloseTo(2);
|
|
42
|
+
expect(result.minimumCm).toBeCloseTo(34);
|
|
43
|
+
expect(result.collarType).toBe('breakaway');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('rejects impossible measurements while preserving a diagnostic result', () => {
|
|
47
|
+
const result = calculatePetCollarSize({
|
|
48
|
+
neckCircumference: 0,
|
|
49
|
+
allowance: 2,
|
|
50
|
+
unit: 'cm',
|
|
51
|
+
collarType: 'martingale',
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
expect(result.valid).toBe(false);
|
|
55
|
+
expect(result.minimumCm).toBe(2);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('classifies the selected allowance for the visual review', () => {
|
|
59
|
+
expect(evaluateAllowance(1)).toBe('tight');
|
|
60
|
+
expect(evaluateAllowance(2)).toBe('balanced');
|
|
61
|
+
expect(evaluateAllowance(5)).toBe('loose');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export type CollarUnit = 'cm' | 'in';
|
|
2
|
+
export type CollarType = 'flat' | 'breakaway' | 'martingale';
|
|
3
|
+
export type AllowanceStatus = 'tight' | 'balanced' | 'loose';
|
|
4
|
+
|
|
5
|
+
export interface PetCollarSizeInput {
|
|
6
|
+
neckCircumference: number;
|
|
7
|
+
allowance: number;
|
|
8
|
+
unit: CollarUnit;
|
|
9
|
+
collarType: CollarType;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface PetCollarSizeResult {
|
|
13
|
+
valid: boolean;
|
|
14
|
+
unit: CollarUnit;
|
|
15
|
+
collarType: CollarType;
|
|
16
|
+
neckCm: number;
|
|
17
|
+
allowanceCm: number;
|
|
18
|
+
minimumCm: number;
|
|
19
|
+
targetCm: number;
|
|
20
|
+
maximumCm: number;
|
|
21
|
+
status: AllowanceStatus;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const INCH_TO_CM = 2.54;
|
|
25
|
+
const RANGE_WINDOW_CM = 2;
|
|
26
|
+
const MIN_NECK_CM = 5;
|
|
27
|
+
const MAX_NECK_CM = 250;
|
|
28
|
+
const MIN_ALLOWANCE_CM = 0.5;
|
|
29
|
+
const MAX_ALLOWANCE_CM = 10;
|
|
30
|
+
|
|
31
|
+
export function toCentimetres(value: number, unit: CollarUnit): number {
|
|
32
|
+
return unit === 'in' ? value * INCH_TO_CM : value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function fromCentimetres(value: number, unit: CollarUnit): number {
|
|
36
|
+
return unit === 'in' ? value / INCH_TO_CM : value;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function evaluateAllowance(allowanceCm: number): AllowanceStatus {
|
|
40
|
+
if (allowanceCm < 1.5) return 'tight';
|
|
41
|
+
if (allowanceCm > 3.5) return 'loose';
|
|
42
|
+
return 'balanced';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function isValidInput(input: PetCollarSizeInput, neckCm: number, allowanceCm: number): boolean {
|
|
46
|
+
return Number.isFinite(input.neckCircumference)
|
|
47
|
+
&& Number.isFinite(input.allowance)
|
|
48
|
+
&& neckCm >= MIN_NECK_CM
|
|
49
|
+
&& neckCm <= MAX_NECK_CM
|
|
50
|
+
&& allowanceCm >= MIN_ALLOWANCE_CM
|
|
51
|
+
&& allowanceCm <= MAX_ALLOWANCE_CM;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function calculatePetCollarSize(input: PetCollarSizeInput): PetCollarSizeResult {
|
|
55
|
+
const neckCm = toCentimetres(input.neckCircumference, input.unit);
|
|
56
|
+
const allowanceCm = toCentimetres(input.allowance, input.unit);
|
|
57
|
+
const valid = isValidInput(input, neckCm, allowanceCm);
|
|
58
|
+
const minimumCm = neckCm + allowanceCm;
|
|
59
|
+
const maximumCm = minimumCm + RANGE_WINDOW_CM;
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
valid,
|
|
63
|
+
unit: input.unit,
|
|
64
|
+
collarType: input.collarType,
|
|
65
|
+
neckCm,
|
|
66
|
+
allowanceCm,
|
|
67
|
+
minimumCm,
|
|
68
|
+
targetCm: minimumCm + (RANGE_WINDOW_CM / 2),
|
|
69
|
+
maximumCm,
|
|
70
|
+
status: evaluateAllowance(allowanceCm),
|
|
71
|
+
};
|
|
72
|
+
}
|