Compare commits

..

No commits in common. "main" and "translation" have entirely different histories.

7 changed files with 177 additions and 270 deletions

View File

@ -1,7 +1,5 @@
# RattenheimRechner # RattenheimRechner
**[rechner.vdrd.de](https://rechner.vdrd.de)**
Ein Rechner für die minimale Größe eines Rattenkäfigs nach Standard des [VdRD e.V.](https://vdrd.de) Ein Rechner für die minimale Größe eines Rattenkäfigs nach Standard des [VdRD e.V.](https://vdrd.de)
## CI ## CI

View File

@ -62,7 +62,6 @@ ul {
label { label {
font-weight: bold; font-weight: bold;
word-break: break-word; word-break: break-word;
font-size: x-large;
} }
.slidecontainer { .slidecontainer {
@ -200,31 +199,15 @@ input.measurement {
flex-wrap: wrap; flex-wrap: wrap;
} }
.top-navigation { .navigation-sticky {
background-color: var(--secondary-light-one);
color: var(--primary-light-one);
padding: 16px;
margin: 0; margin: 0;
border: none;
width: 100%;
display: flex;
}
.homebutton {
background-color: var(--secondary-light-one);
color: var(--primary-light-one);
border-bottom-right-radius: 8px; border-bottom-right-radius: 8px;
font-weight: bold;
padding: 16px;
width: 20%;
}
.language-switcher {
background-color: var(--secondary-light-one);
color: var(--primary-light-one);
padding: 16px;
border-bottom-left-radius: 8px;
border: none; border: none;
font-weight: bold; font-weight: bold;
width: 15%; width: 20%;
margin-left: auto;
} }
@ -248,12 +231,4 @@ input.measurement {
.tooltip:hover .tooltiptext { .tooltip:hover .tooltiptext {
visibility: visible; visibility: visible;
}
select, option {
background-color: var(--primary-light-one);
border-radius: 0.2rem;
border: none;
color: var(--text-one);
width: 100%;
} }

View File

@ -0,0 +1,85 @@
const MINIMUM_BASE_AREA = 0.5;
const MINIMUM_AREA_THREE_RATS = 1.5;
const AREA_PER_ADDITIONAL_RAT = 0.25;
const MAXIMUM_FALL_HEIGHT = 0.5;
const MINIMUM_LENGTH_LONG_SIDE = 0.8;
const MINIMUM_LENGTH_SHORT_SIDE = 0.5;
const MINIMUM_FLOOR_HEIGHT = 0.3;
const FAILED_BASE_AREA = "base_area";
const FAILED_OVERALL_AREA = "overall_area";
const FAILED_FALL_HEIGHT = "fall_height";
const FAILED_NUM_RATS = "num_rats";
const FAILED_MINIMUM_LENGTH_LONG_SIDE = "length_long_side";
const FAILED_MINIMUM_LENGTH_SHORT_SIDE= "length_short_side";
const FAILED_FLOOR_HEIGHT = "floor_height"
const FAIL_CRITERIA = {
[FAILED_BASE_AREA]: `Die Mindestgrundfläche des Käfigs muss ${MINIMUM_BASE_AREA}m² (also z.B. 100x50cm) betragen.`,
[FAILED_OVERALL_AREA]: "Die Gesamtfläche im Käfig ist zu klein.",
[FAILED_FALL_HEIGHT]: `Die mögliche Fallhöhe darf nicht mehr als ${(MAXIMUM_FALL_HEIGHT * 100).toFixed(0)}cm betragen.`,
[FAILED_FLOOR_HEIGHT]: `Der Mindestabstand zwischen Ebenen muss ${(MINIMUM_FLOOR_HEIGHT * 100).toFixed(0)}cm betragen.`,
[FAILED_NUM_RATS]: "Es müssen mindestens 3 Ratten zusammenleben, Paarhaltung ist nicht artgerecht.",
[FAILED_MINIMUM_LENGTH_LONG_SIDE]: `Die lange Seite des Käfig muss mindestens ${(MINIMUM_LENGTH_LONG_SIDE * 100).toFixed(0)}cm lang sein um Rennen zu ermöglichen.`,
[FAILED_MINIMUM_LENGTH_SHORT_SIDE]: `Die kurze Seite des Käfig muss mindestens ${(MINIMUM_LENGTH_SHORT_SIDE * 100).toFixed(0)}cm lang sein.`,
};
class Dimensions {
constructor(width, depth, height) {
this.width = width;
this.depth = depth;
this.height = height;
}
toString() {
return `${this.width}x${this.depth}x${this.height}`;
}
static fromDict(data) {
const { width, depth, height } = data;
return new Dimensions(width, depth, height);
}
}
function overallAreaNeeded(numOfRats) {
if (numOfRats < 3 || numOfRats > 15) {
throw new Error("This formula works only from 3 to 15 rats");
}
return MINIMUM_AREA_THREE_RATS + (numOfRats - 3) * AREA_PER_ADDITIONAL_RAT;
}
function cageCheck(dimensions, numRats, numFullFloors) {
let failedCriteria = {};
if (numRats < 2 || numRats > 15) {
failedCriteria[FAILED_NUM_RATS] = FAIL_CRITERIA[FAILED_NUM_RATS];
}
const baseArea = dimensions.depth * dimensions.width;
if (baseArea < MINIMUM_BASE_AREA) {
failedCriteria[FAILED_BASE_AREA] = FAIL_CRITERIA[FAILED_BASE_AREA];
}
const areaNeeded = overallAreaNeeded(numRats);
if (baseArea * numFullFloors < areaNeeded) {
failedCriteria[FAILED_OVERALL_AREA] = FAIL_CRITERIA[FAILED_OVERALL_AREA];
}
if (dimensions.height / numFullFloors > MAXIMUM_FALL_HEIGHT) {
failedCriteria[FAILED_FALL_HEIGHT] = FAIL_CRITERIA[FAILED_FALL_HEIGHT];
}
if (dimensions.width < MINIMUM_LENGTH_LONG_SIDE && dimensions.depth < MINIMUM_LENGTH_LONG_SIDE) {
failedCriteria[FAILED_MINIMUM_LENGTH_LONG_SIDE] = FAIL_CRITERIA[FAILED_MINIMUM_LENGTH_LONG_SIDE];
}
if (dimensions.width < MINIMUM_LENGTH_SHORT_SIDE || dimensions.depth < MINIMUM_LENGTH_SHORT_SIDE) {
failedCriteria[FAILED_MINIMUM_LENGTH_SHORT_SIDE] = FAIL_CRITERIA[FAILED_MINIMUM_LENGTH_SHORT_SIDE];
}
if (dimensions.height / numFullFloors < MINIMUM_FLOOR_HEIGHT) {
failedCriteria[FAILED_FLOOR_HEIGHT] = FAIL_CRITERIA[FAILED_FLOOR_HEIGHT];
}
return failedCriteria;
}

View File

@ -4,6 +4,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Käfigrechner</title> <title>Käfigrechner</title>
<link rel="stylesheet" href="assets/css/style.css"> <link rel="stylesheet" href="assets/css/style.css">
<script src="assets/js/calculator.js"></script>
<link rel="apple-touch-icon" sizes="180x180" href="assets/favicon/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="assets/favicon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="assets/favicon/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="32x32" href="assets/favicon/favicon-32x32.png">
@ -11,23 +12,18 @@
</head> </head>
<body> <body>
<div class="top-navigation"> <div class="navigation-sticky">
<div class="homebutton"> <a href="https://notfellchen.org">
<a href="https://vdrd.de"> <b data-i18n-key="back-to-home">zurück zur Homepage</b>
<b data-i18n-key="back-to-home">zurück zur Homepage</b> </a>
</a>
</div>
<div class="language-switcher">
<label aria-hidden="false" style="display: none" data-i18n-key="change-language"></label>
<select data-i18n-switcher class="locale-switcher" id="locale-switcher">
<option value="en">English</option>
<option value="de">Deutsch</option>
</select>
</div>
</div> </div>
<img src="img/translation-icon@2x.png" class="translation-icon" / >
<select data-i18n-switcher class="locale-switcher">
<option value="en">English</option>
<option value="de">Deutsch</option>
</select>
<div class="content"> <div class="content">
<h1 data-i18n-key="app-name">Käfigrechner</h1> <h1 data-i18n-key="app-name">Käfigrechner</h1>
<div class="container-form"> <div class="container-form">
@ -36,7 +32,7 @@
<label for="SavicSuiteRoyaleXL"> <label for="SavicSuiteRoyaleXL">
<input type="checkbox" id="SavicSuiteRoyaleXL"/> <input type="checkbox" id="SavicSuiteRoyaleXL"/>
<div class="card-photo"> <div class="card-photo">
<img alt-i18n-key="alt-savic-xl" src="assets/img/savic-xl.jpeg"> <img src="assets/img/savic-xl.jpeg">
</div> </div>
<div class="info-container"> <div class="info-container">
<h4><b>Savic Suite Royale XL</b></h4> <h4><b>Savic Suite Royale XL</b></h4>
@ -49,7 +45,7 @@
<input type="checkbox" id="SavicSuiteRoyale95Double"/> <input type="checkbox" id="SavicSuiteRoyale95Double"/>
<div class="card-photo"> <div class="card-photo">
<div> <div>
<img alt-i18n-key="alt-savic-95-double" src="assets/img/savic-95-double.jpg"> <img src="assets/img/savic-95-double.jpg">
</div> </div>
<div class="info-container"> <div class="info-container">
<h4><b>Savic Suite Royale 95 Double</b></h4> <h4><b>Savic Suite Royale 95 Double</b></h4>
@ -62,7 +58,7 @@
<label for="TiakiKleintierkäfigEtagere"> <label for="TiakiKleintierkäfigEtagere">
<input type="checkbox" id="TiakiKleintierkäfigEtagere"/> <input type="checkbox" id="TiakiKleintierkäfigEtagere"/>
<div class="card-photo"> <div class="card-photo">
<img alt-i18n-key="alt-tiaki" src="assets/img/tiaki.jpeg"> <img src="assets/img/tiaki.jpeg">
</div> </div>
<div class="info-container"> <div class="info-container">
<h4><b>TIAKI Kleintierkäfig Étagère</b></h4> <h4><b>TIAKI Kleintierkäfig Étagère</b></h4>
@ -71,7 +67,7 @@
</div> </div>
<div class="card" id="card-ManualMeasurements"> <div class="card" id="card-ManualMeasurements">
<label data-i18n-key="cage-measurements" for="form-cage-measurements">Käfigmaße</label> <label for="form-cage-measurements">Käfigmaße</label>
<form id="form-cage-measurements" class="form-measurements"> <form id="form-cage-measurements" class="form-measurements">
<div class="input-measurement"> <div class="input-measurement">
<label for="width" data-i18n-key="width-cm">Breite (cm)</label> <label for="width" data-i18n-key="width-cm">Breite (cm)</label>
@ -94,16 +90,7 @@
<div class="input-element"> <div class="input-element">
<label for="numFullFloors" data-i18n-key="full-floors">Vollebenen</label> <label for="numFullFloors" data-i18n-key="full-floors">Vollebenen</label>
<div class="tooltip"> <div class="tooltip">
<svg class="text-grey-dark" width="18" height="18" viewBox="0 0 18 18" fill="none" <svg class="text-grey-dark" width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor"><path d="M9.00026 12.6C9.00026 12.6 9.00026 12.1224 9.00026 11.5333V8.86666C9.00026 8.57211 8.76148 8.33333 8.46693 8.33333H7.93359" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M8.73346 5.26666C8.58619 5.26666 8.4668 5.38605 8.4668 5.53333C8.4668 5.68061 8.58619 5.8 8.73346 5.8C8.88074 5.8 9.00013 5.68061 9.00013 5.53333C9.00013 5.38605 8.88074 5.26666 8.73346 5.26666V5.26666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M9 17C13.4183 17 17 13.4183 17 9C17 4.58172 13.4183 1 9 1C4.58172 1 1 4.58172 1 9C1 13.4183 4.58172 17 9 17Z" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
stroke="currentColor">
<path d="M9.00026 12.6C9.00026 12.6 9.00026 12.1224 9.00026 11.5333V8.86666C9.00026 8.57211 8.76148 8.33333 8.46693 8.33333H7.93359"
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M8.73346 5.26666C8.58619 5.26666 8.4668 5.38605 8.4668 5.53333C8.4668 5.68061 8.58619 5.8 8.73346 5.8C8.88074 5.8 9.00013 5.68061 9.00013 5.53333C9.00013 5.38605 8.88074 5.26666 8.73346 5.26666V5.26666"
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
<path fill-rule="evenodd" clip-rule="evenodd"
d="M9 17C13.4183 17 17 13.4183 17 9C17 4.58172 13.4183 1 9 1C4.58172 1 1 4.58172 1 9C1 13.4183 4.58172 17 9 17Z"
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
<span class="tooltiptext" data-i18n-key="full-floors-tooltip">Als Vollebenen zählen alle Ebenen die größer als 0.5m² sind, inklusive des Käfigbodens.</span> <span class="tooltiptext" data-i18n-key="full-floors-tooltip">Als Vollebenen zählen alle Ebenen die größer als 0.5m² sind, inklusive des Käfigbodens.</span>
</div> </div>
<div class="ncontainer"> <div class="ncontainer">
@ -117,17 +104,16 @@
<div class="input-element"> <div class="input-element">
<div class="slidecontainer"> <div class="slidecontainer">
<label for="numRats" id="labelNumRats"></label> <label for="numRats" id="labelNumRats" data-i18n-key="number-of-rats">Anzahl an Ratten ?</label>
<input type="range" min="3" max="15" value="4" class="slider" id="numRats"> <input type="range" min="3" max="15" value="4" class="slider" id="numRats">
</div> </div>
</div> </div>
</div> </div>
<div class="container output-element"> <div class="container output-element" id="resultsDiv">
<strong data-i18n-key="result">Ergebnis</strong>
<div id="resultsDiv"></div>
</div> </div>
</div> </div>
</div>
<script src="./bundle.js"></script> <script src="./bundle.js"></script>

View File

@ -6,20 +6,5 @@
"width-cm": "Breite (cm)", "width-cm": "Breite (cm)",
"depth-cm": "Tiefe (cm)", "depth-cm": "Tiefe (cm)",
"height-cm": "Höhe (cm)", "height-cm": "Höhe (cm)",
"full-floors-tooltip": "Als Vollebenen zählen alle Ebenen die größer als 0.5m² sind, inklusive des Käfigbodens.", "full-floors-tooltip": "Als Vollebenen zählen alle Ebenen die größer als 0.5m² sind, inklusive des Käfigbodens."
"failed-base-area": "Die Mindestgrundfläche des Käfigs muss {{ MINIMUM_BASE_AREA }}m² (also z.B. 100x50cm) betragen.",
"failed-overall-area": "Die Gesamtfläche im Käfig ist zu klein.",
"failed-fall-height": "Die mögliche Fallhöhe darf nicht mehr als {{ maximum_fall_height }}cm betragen.",
"failed-floor-height": "Der Mindestabstand zwischen Ebenen muss {{ minimum_floor_height }}cm betragen.",
"failed-num-rats": "Es müssen mindestens 3 Ratten zusammenleben, Paarhaltung ist nicht artgerecht.",
"failed-minimum-length-long-side": "Die lange Seite des Käfig muss mindestens {{ minimum_length_long_side }}cm lang sein um Rennen zu ermöglichen.",
"failed-minimum-length-short-side": "Die kurze Seite des Käfig muss mindestens {{ minimum_length_short_side }}cm lang sein.",
"alt-savic-xl": "Bild des Käfigs Savic Suite Royal XL, ein Drahtkäfig mit vier Türen die erlauben die gesamte Vorderseite zu öffnen. Auf halber Höhe ist eine weitere Vollebene.",
"alt-savic-95-double": "Bild eines dekorierten Käfigs, des Savic Suite Royale 95 Double. Auf insgesamt vie Vollebenen sind Holz- und Papphäusschen, Hängematten, Futterschalen und mehr.",
"alt-tiaki": "Bild des Tiaki-Käfigs, ein Drahtkäfig mit vier Türen die erlauben die gesamte Vorderseite zu öffnen. Auf halber Höhe ist eine weitere Vollebene.",
"cage-measurements": "Käfigmaße",
"cage-complies-with-all-criteria": "Der Käfig erfüllt alle Kriterien!",
"cage-for-x-rats": "Käfig für {{ num_rats }} Ratten",
"change-language": "Sprache ändern",
"result": "Ergebnis"
} }

View File

@ -6,20 +6,5 @@
"width-cm": "Width (cm)", "width-cm": "Width (cm)",
"depth-cm": "Depth (cm)", "depth-cm": "Depth (cm)",
"height-cm": "Height (cm)", "height-cm": "Height (cm)",
"full-floors-tooltip": "A full floor is each floor with a area greater than XXm², including the bottom of the cage.", "full-floors-tooltip": "A full floor is each floor with a area greater than 0.5m², including the bottom of the cage."
"failed-base-area": "The base area of the cage must not be below {{ MINIMUM_BASE_AREA }}m².",
"failed-overall-area": "The overall area in the cage is to small.",
"failed-fall-height": "The possible fall height between floors must not be above {{ maximum_fall_height }}cm.",
"failed-floor-height": "The height between floors must be above {{ minimum_floor_height }}cm.",
"failed-num-rats": "Rats must live in a group of at least three rats, pairs or lone rats are not species-appropriate.",
"failed-minimum-length-long-side": "The long side of the cage must be at least {{ minimum_length_long_side }}cm long to enable running.",
"failed-minimum-length-short-side": "The short side of the cage must be at least {{ minimum_length_short_side }}cm.",
"alt-savic-xl": "A picture of a wire bar cage with four doors that allow to open the full front of the cage. In the middle of the cage is a additional full floor.",
"alt-savic-95-double": "A picture of a decorated wire bar cage with four doors that allow to open the full front of the cage. Inside there are hammocks, toys and four full floors with lots of hides",
"alt-tiaki": "A picture of a decorated wire bar cage with four doors that allow to open the full front of the cage.",
"cage-measurements": "Cage measurements",
"cage-complies-with-all-criteria": "This cage complies with all criteria!",
"cage-for-x-rats": "Cage for {{ num_rats }} rats",
"change-language": "Change language",
"result": "Result"
} }

View File

@ -1,169 +1,3 @@
import i18next from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import HttpApi from "i18next-http-backend";
/////////////////
// TRANSLATION //
/////////////////
async function initI18next() {
await i18next
.use(HttpApi)
.use(LanguageDetector)
.init({
supportedLngs: ["en", "de"],
nonExplicitSupportedLngs: true,
fallbackLng: "en",
debug: true,
backend: {
loadPath: "/lang/{{lng}}.json",
},
});
}
function translatePageElements() {
// Translate content inside a tag
const translatableElements = document.querySelectorAll(
"[data-i18n-key]",
);
translatableElements.forEach((el) => {
const key = el.getAttribute("data-i18n-key");
el.innerHTML = i18next.t(key);
});
// Translate alt texts
const translatableAltTexts = document.querySelectorAll(
"[alt-i18n-key]",
);
translatableAltTexts.forEach((el) => {
const translation_key = el.getAttribute("alt-i18n-key");
el.setAttribute("alt", i18next.t(translation_key));
});
}
function bindLocaleSwitcher(initialValue) {
const switcher = document.querySelector(
"[data-i18n-switcher]",
);
switcher.value = initialValue;
switcher.onchange = (e) => {
i18next
.changeLanguage(e.target.value)
.then(translatePageElements)
.then(update);
};
}
(async function () {
await initI18next();
translatePageElements();
bindLocaleSwitcher(i18next.resolvedLanguage);
update();
})();
////////////////
// CALCULATOR //
////////////////
const MINIMUM_BASE_AREA = 0.5;
const MINIMUM_AREA_THREE_RATS = 1.5;
const AREA_PER_ADDITIONAL_RAT = 0.25;
const MAXIMUM_FALL_HEIGHT = 0.5;
const MINIMUM_LENGTH_LONG_SIDE = 0.8;
const MINIMUM_LENGTH_SHORT_SIDE = 0.5;
const MINIMUM_FLOOR_HEIGHT = 0.25;
const FAILED_BASE_AREA = "base_area";
const FAILED_OVERALL_AREA = "overall_area";
const FAILED_FALL_HEIGHT = "fall_height";
const FAILED_NUM_RATS = "num_rats";
const FAILED_MINIMUM_LENGTH_LONG_SIDE = "length_long_side";
const FAILED_MINIMUM_LENGTH_SHORT_SIDE= "length_short_side";
const FAILED_FLOOR_HEIGHT = "floor_height"
class Validator {
constructor() {
this.FAIL_CRITERIA = {
[FAILED_BASE_AREA]: i18next.t('failed-base-area', {"MINIMUM_BASE_AREA": MINIMUM_BASE_AREA}),
[FAILED_OVERALL_AREA]: i18next.t("failed-overall-area"),
[FAILED_FALL_HEIGHT]: i18next.t("failed-fall-height", {"maximum_fall_height": (MAXIMUM_FALL_HEIGHT * 100).toFixed(0)}),
[FAILED_FLOOR_HEIGHT]: i18next.t("failed-floor-height", {"minimum_floor_height": (MINIMUM_FLOOR_HEIGHT * 100).toFixed(0)}),
[FAILED_NUM_RATS]: i18next.t("failed-num-rats"),
[FAILED_MINIMUM_LENGTH_LONG_SIDE]: i18next.t("failed-minimum-length-long-side", {"minimum_length_long_side": (MINIMUM_LENGTH_LONG_SIDE * 100).toFixed(0)}),
[FAILED_MINIMUM_LENGTH_SHORT_SIDE]: i18next.t("failed-minimum-length-short-side", {"minimum_length_short_side": (MINIMUM_LENGTH_SHORT_SIDE * 100).toFixed(0)}),
};
}
overallAreaNeeded(numOfRats) {
if (numOfRats < 3 || numOfRats > 15) {
throw new Error("This formula works only from 3 to 15 rats");
}
return MINIMUM_AREA_THREE_RATS + (numOfRats - 3) * AREA_PER_ADDITIONAL_RAT;
}
cageCheck(dimensions, numRats, numFullFloors) {
let failedCriteria = {};
if (numRats < 2 || numRats > 15) {
failedCriteria[FAILED_NUM_RATS] = this.FAIL_CRITERIA[FAILED_NUM_RATS];
}
const baseArea = dimensions.depth * dimensions.width;
if (baseArea < MINIMUM_BASE_AREA) {
failedCriteria[FAILED_BASE_AREA] = this.FAIL_CRITERIA[FAILED_BASE_AREA];
}
const areaNeeded = this.overallAreaNeeded(numRats);
if (baseArea * numFullFloors < areaNeeded) {
failedCriteria[FAILED_OVERALL_AREA] = this.FAIL_CRITERIA[FAILED_OVERALL_AREA];
}
if (dimensions.height / numFullFloors > MAXIMUM_FALL_HEIGHT) {
failedCriteria[FAILED_FALL_HEIGHT] = this.FAIL_CRITERIA[FAILED_FALL_HEIGHT];
}
if (dimensions.width < MINIMUM_LENGTH_LONG_SIDE && dimensions.depth < MINIMUM_LENGTH_LONG_SIDE) {
failedCriteria[FAILED_MINIMUM_LENGTH_LONG_SIDE] = this.FAIL_CRITERIA[FAILED_MINIMUM_LENGTH_LONG_SIDE];
}
if (dimensions.width < MINIMUM_LENGTH_SHORT_SIDE || dimensions.depth < MINIMUM_LENGTH_SHORT_SIDE) {
failedCriteria[FAILED_MINIMUM_LENGTH_SHORT_SIDE] = this.FAIL_CRITERIA[FAILED_MINIMUM_LENGTH_SHORT_SIDE];
}
if (dimensions.height / numFullFloors < MINIMUM_FLOOR_HEIGHT) {
failedCriteria[FAILED_FLOOR_HEIGHT] = this.FAIL_CRITERIA[FAILED_FLOOR_HEIGHT];
}
return failedCriteria;
}
}
class Dimensions {
constructor(width, depth, height) {
this.width = width;
this.depth = depth;
this.height = height;
}
toString() {
return `${this.width}x${this.depth}x${this.height}`;
}
static fromDict(data) {
const { width, depth, height } = data;
return new Dimensions(width, depth, height);
}
}
//////////////////////////
// DOCUMENT INTERACTION //
//////////////////////////
const inputDecreaseFloorNum = document.getElementById("decreaseFloorNum"); const inputDecreaseFloorNum = document.getElementById("decreaseFloorNum");
inputDecreaseFloorNum.onclick = decreaseFloorNum; inputDecreaseFloorNum.onclick = decreaseFloorNum;
@ -208,6 +42,7 @@ function updateCage(event) {
selectedCage.checked = true; selectedCage.checked = true;
const cageName = selectedCage.id; const cageName = selectedCage.id;
console.log(cageName);
var dim = getCageDimensions(cageName); var dim = getCageDimensions(cageName);
inputWidth.value = dim.width; inputWidth.value = dim.width;
inputDepth.value = dim.depth; inputDepth.value = dim.depth;
@ -227,7 +62,10 @@ var labelNumRats = document.getElementById("labelNumRats");
var ratSlider = document.getElementById("numRats"); var ratSlider = document.getElementById("numRats");
labelNumRats.innerHTML = `Anzahl an Ratten: ` + ratSlider.value;
ratSlider.oninput = function () { ratSlider.oninput = function () {
labelNumRats.innerHTML = `Anzahl an Ratten: ` + this.value;
update(); update();
} }
@ -235,6 +73,7 @@ ratSlider.oninput = function () {
var fullFloorNum = document.getElementById("numFullFloors"); var fullFloorNum = document.getElementById("numFullFloors");
function getCageDimensions(cageName) { function getCageDimensions(cageName) {
console.log(cageName);
if (cageName == "SavicSuiteRoyaleXL") { if (cageName == "SavicSuiteRoyaleXL") {
return new Dimensions(115, 67.5, 153); return new Dimensions(115, 67.5, 153);
} }
@ -247,17 +86,18 @@ function getCageDimensions(cageName) {
} }
function getResultFromChecks(checks) { function getResultFromChecks(checks) {
console.log(checks.length)
if (Object.keys(checks).length > 0) { if (Object.keys(checks).length > 0) {
const ul = document.createElement('ul'); const ul = document.createElement('ul');
for (const key in checks) { for (const key in checks) {
const li = document.createElement('li'); const li = document.createElement('li');
li.textContent = ` ` + checks[key]; li.textContent = `` + checks[key];
ul.appendChild(li); ul.appendChild(li);
} }
return ul; return ul;
} else { } else {
const p = document.createElement('p'); const p = document.createElement('p');
p.innerHTML = "✅ " + i18next.t("cage-complies-with-all-criteria") p.innerHTML = "✅ Der Käfig erfüllt alle Kriterien!"
return p; return p;
} }
@ -269,19 +109,17 @@ function updateViaManualMeasurements() {
} }
function update() { function update() {
labelNumRats.innerHTML = i18next.t("cage-for-x-rats", {"num_rats": ratSlider.value});
const width = inputWidth.value const width = inputWidth.value
const depth = inputDepth.value const depth = inputDepth.value
const height = inputHeight.value const height = inputHeight.value
const dimensions = new Dimensions(width / 100, depth / 100, height / 100); const dimensions = new Dimensions(width / 100, depth / 100, height / 100);
const validator = new Validator(); const failed_checks = cageCheck(dimensions, ratSlider.value, fullFloorNum.value);
const failed_checks = validator.cageCheck(dimensions, ratSlider.value, fullFloorNum.value); console.log(failed_checks);
let resultsDiv = document.getElementById("resultsDiv"); let resultsDiv = document.getElementById("resultsDiv");
resultsDiv.innerHTML = `<strong>Ergebnis</strong>`;
const result = getResultFromChecks(failed_checks); const result = getResultFromChecks(failed_checks);
resultsDiv.innerHTML = "";
resultsDiv.appendChild(result); resultsDiv.appendChild(result);
} }
@ -301,3 +139,58 @@ function increaseFloorNum() {
input.value = value + 1; input.value = value + 1;
update(); update();
} }
update();
import i18next from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import HttpApi from "i18next-http-backend";
async function initI18next() {
// We use() the backend and await it to load
// the translations from the network
await i18next
.use(HttpApi)
.use(LanguageDetector)
.init({
lng: "en",
supportedLngs: ["en", "de"],
nonExplicitSupportedLngs: true,
fallbackLng: "en",
debug: true,
backend: {
loadPath: "/lang/{{lng}}.json",
},
});
}
function translatePageElements() {
const translatableElements = document.querySelectorAll(
"[data-i18n-key]",
);
translatableElements.forEach((el) => {
const key = el.getAttribute("data-i18n-key");
el.innerHTML = i18next.t(key);
});
}
// ...
function bindLocaleSwitcher(initialValue) {
const switcher = document.querySelector(
"[data-i18n-switcher]",
);
switcher.value = initialValue;
switcher.onchange = (e) => {
i18next
.changeLanguage(e.target.value)
.then(translatePageElements);
};
}
(async function () {
await initI18next();
translatePageElements();
bindLocaleSwitcher(i18next.resolvedLanguage);
})();