Jak powstał Avia Weather (cz. 3): jak rozszyfrować METAR na ludzki język

10.10.2026 · 3 min czytania

W części 2 aplikacja w końcu pokazała prawdziwe dane. Problem? Wyglądały tak:

EPWA 081200Z 24008KT 9999 BKN020 15/09 Q1018

Ja to jeszcze rozszyfruję, bo na co dzień mam z tym do czynienia w pracy. Jednak zwykły użytkownik / nowy pracownik w branży widzi ciąg przypadkowych znaków. Więc wypadało to przetłumaczyć.

Decyzja: kod ORAZ opis, nie opis ZAMIAST kodu#

Pierwsza pokusa to zamienić BKN020 na „zachmurzenie duże, 2000 ft” i tyle. Tylko, że to by zabolało kogoś, kto te kody zna lub kogoś, kto chce je zrozumieć. Więc ustaliłem zasadę:

Dekodery — mały słownik + bezpieczny fallback#

Każdy typ kodu dostał swoją małą funkcję-tłumacza. Wzorzec jest zawsze ten sam: słownik plus zabezpieczenie na nieznany kod.

Przykład — zachmurzenie (src/utils/clouds.ts):

const CLOUD_COVER: Record<string, string> = {
  SKC: "bezchmurnie",
  CLR: "bezchmurnie",
  FEW: "zachmurzenie małe",
  SCT: "zachmurzenie umiarkowane",
  BKN: "zachmurzenie duże",
  OVC: "zachmurzenie całkowite",
};

export function describeCloudCover(code: string): string {
  return CLOUD_COVER[code.toUpperCase()] ?? code;
}

Trzy rzeczy, które tu robię świadomie:

Tym samym wzorcem zrobiłem resztę: reguły lotów (VFR, MVFR, IFR, LIFR), typy prognozy w TAF-ie (BECMG, TEMPO, FROM), a wiatr VRB zamieniam na „zmienny”. Jeden pomysł, cztery małe pliki, zero kopiuj-wklej logiki.

A skąd mam pewność, że to działa?#

Mógłbym po każdej zmianie ręcznie klikać po aplikacji i sprawdzać. Mógłbym — ale jestem leniwy w dobrym sensie. Napisałem testy w Vitest.

import { describe, it, expect } from "vitest";
import { describeCloudCover } from "./clouds";

describe("describeCloudCover", () => {
  it("tłumaczy znany kod", () => {
    expect(describeCloudCover("BKN")).toBe("zachmurzenie duże");
  });

  it("działa niezależnie od wielkości liter", () => {
    expect(describeCloudCover("bkn")).toBe("zachmurzenie duże");
  });

  it("zwraca surowy kod, gdy go nie zna", () => {
    expect(describeCloudCover("XYZ")).toBe("XYZ");
  });
});

Pilnuję trzech rodzajów przypadków: typowy (znany kod), brzegowy (inna wielkość liter) i awaryjny (nieznany kod → fallback). To właśnie te „dziwne” przypadki najczęściej psują aplikację w praniu.

To tyle, jeśli chodzi o „jak powstał” — od pomysłu, przez dane, po tłumacza. Dalej już tylko kolejne usprawnienia: tryb ciemny, SEO, rebranding na Avia Weather… ale to historie na osobne wpisy.

Więcej z tej serii

  1. 1.Jak powstał mój METAR (cz. 1): pomysł i stack
  2. 2.Jak powstał Avia Weather (cz. 2): skąd brać dane i jak ukryć klucz API
  3. 3.Jak powstał Avia Weather (cz. 3): jak rozszyfrować METAR na ludzki język