This page was machine-translated. Spotted a mistake?Help improve it.
Skip to content

Przewodnik po tłumaczeniach

SnapOtter dostarczany jest z 21 językami od razu po instalacji. System i18n korzysta z lekkiego, własnego środowiska uruchomieniowego z wymuszaną przez TypeScript kompletnością lokalizacji oraz dynamicznym dzieleniem kodu.

Obsługiwane języki

CodeLanguageNative NameDirection
enangielskiEnglishLTR
zh-CNchiński (uproszczony)简体中文LTR
zh-TWchiński (tradycyjny)繁體中文LTR
jajapoński日本語LTR
kokoreański한국어LTR
eshiszpańskiEspañolLTR
frfrancuskiFrançaisLTR
itwłoskiItalianoLTR
pt-BRportugalski (Brazylia)Português (Brasil)LTR
deniemieckiDeutschLTR
nlniderlandzkiNederlandsLTR
svszwedzkiSvenskaLTR
rurosyjskiРусскийLTR
plpolskiPolskiLTR
ukukraińskiУкраїнськаLTR
ararabskiالعربيةRTL
trtureckiTürkçeLTR
hihindiहिन्दीLTR
viwietnamskiTiếng ViệtLTR
idindonezyjskiBahasa IndonesiaLTR
thtajskiไทยLTR

Jak działa wykrywanie języka

SnapOtter stosuje trzypoziomową kolejność rozstrzygania:

  1. Preferencja użytkownika - przechowywana w localStorage("snapotter-locale") i synchronizowana z ustawieniami użytkownika po zalogowaniu
  2. Automatyczne wykrywanie przeglądarki - przechodzi przez tablicę navigator.languages z dopasowywaniem prefiksów BCP 47
  3. Domyślny język instancji - zmienna środowiskowa administratora DEFAULT_LOCALE (pobierana z GET /api/v1/config/locale)
  4. Awaryjny język angielski - zawsze dostępny

Użytkownicy mogą zmienić język w:

  • selektorze Globe w stopce (na komputerze, zawsze widoczny)
  • selektorze języka na stronie logowania (przed uwierzytelnieniem)
  • sekcji Ustawienia > Ogólne (preferencja dla danego użytkownika)
  • rozwijanej liście języków w mobilnym pasku bocznym
  • sekcji Ustawienia > System, która ustawia domyślny język dla całej instancji (tylko administrator)

Jak działają tłumaczenia

Wszystkie napisy interfejsu znajdują się w packages/shared/src/i18n/. Plikiem referencyjnym jest en.ts, który eksportuje typowany obiekt zawierający każdy napis używany przez aplikację (~1500 kluczy). Pozostałe języki to osobne pliki (np. de.ts, fr.ts), które eksportują ten sam kształt.

Typ TranslationKeys wykorzystuje DeepStringRecord, aby przyjmować dowolną wartość tekstową, wymuszając jednocześnie strukturę kluczy. TypeScript wychwytuje brakujące klucze w dowolnym pliku tłumaczenia na etapie kompilacji.

W czasie działania ładowana jest tylko aktywna lokalizacja poprzez dynamiczny import(), dzięki czemu główny pakiet pozostaje niewielki.

Używanie tłumaczeń w komponentach

tsx
import { useTranslation } from "@/contexts/i18n-context";
import { format, plural } from "@/lib/format";

function MyComponent() {
  const { t, locale, setLocale } = useTranslation();
  
  return (
    <div>
      <h1>{t.common.settings}</h1>
      <p>{format(t.settings.people.deleteConfirm, { username: "admin" })}</p>
      <p>{plural(count, t.automate.fileCount, t.automate.fileCountPlural)}</p>
    </div>
  );
}

Współtworzenie tłumaczenia

Chętnie przyjmujemy PR-y z tłumaczeniami bezpośrednio. Możesz ulepszyć istniejącą lokalizację lub dodać nową.

Aby zgłosić błędne tłumaczenie bez przesyłania kodu, otwórz zgłoszenie na GitHubie z podaniem języka, nieprawidłowego napisu oraz proponowanej poprawki.

TIP

PR-y z tłumaczeniami nie wymagają wcześniejszej akceptacji. Rozgałęź repozytorium, wprowadź zmiany i otwórz PR. Zajrzyj do przewodnika dla współtwórców, aby poznać pełny proces PR oraz wymóg CLA.

Jak utworzyć lub zaktualizować tłumaczenie

1. Rozgałęź i sklonuj

bash
git clone https://github.com/<your-username>/snapotter.git
cd snapotter
pnpm install

2. Skopiuj plik referencyjny (tylko nowy język)

Pomiń ten krok, jeśli ulepszasz istniejące tłumaczenie.

bash
cp packages/shared/src/i18n/en.ts packages/shared/src/i18n/XX.ts

3. Przetłumacz napisy

Otwórz swój nowy plik i przetłumacz każdą wartość tekstową. Zachowaj strukturę obiektu i klucze dokładnie takie same.

ts
import type { TranslationKeys } from "./en.js";

export const xx: TranslationKeys = {
  common: {
    upload: "Your translation here",
    // ... translate all entries
  },
  // ... translate all sections
} as const;

Zasady:

  • Nie tłumacz kluczy obiektu, tylko wartości tekstowe
  • Zachowaj as const na końcu
  • Zaimportuj TranslationKeys z ./en.js i otypuj swój eksport
  • Zachowaj symbole zastępcze {variable} dokładnie w takiej samej postaci
  • Tablice (rotatingPhrases, progressMessages) muszą mieć tę samą liczbę wpisów
  • Nie tłumacz: SnapOtter, JPEG, PNG, WebP, EXIF, API oraz innych terminów technicznych

4. Zarejestruj lokalizację (tylko nowy język)

Dodaj swoją lokalizację do SUPPORTED_LOCALES w packages/shared/src/i18n/index.ts:

ts
{ code: "xx", name: "Language Name", nativeName: "Native Name", dir: "ltr" },

5. Zweryfikuj

bash
pnpm typecheck    # catches missing or mistyped keys
pnpm lint         # formatting check
pnpm dev          # manually verify strings appear correctly

6. Prześlij

Otwórz PR wobec main z tytułem w rodzaju feat(i18n): add Swedish translation lub fix(i18n): correct German typos. Bot CLA poprosi Cię o podpis przy pierwszym wkładzie.

Dodawanie nowych kluczy tłumaczeń

Dodając nową funkcję, która wymaga nowych napisów interfejsu:

  1. Najpierw dodaj nowe klucze do en.ts (plik referencyjny)
  2. Uruchom pnpm typecheck - każdy plik lokalizacji zgłosi błąd, jeśli brakuje w nim nowego klucza
  3. Dodaj nowy klucz do wszystkich plików lokalizacji (jako tymczasowego zastępstwa użyj języka angielskiego)

Konfiguracja

Ustaw domyślny język instancji za pomocą zmiennej środowiskowej:

yaml
DEFAULT_LOCALE: "de"  # German as the default for all new users

Zestawienie plików

FilePurpose
packages/shared/src/i18n/en.tsnapisy angielskie (lokalizacja referencyjna, ~1500 kluczy)
packages/shared/src/i18n/index.tsSUPPORTED_LOCALES, loadTranslations(), eksporty typów
packages/shared/src/i18n/<locale>.tspliki tłumaczeń dla poszczególnych języków
apps/web/src/contexts/i18n-context.tsxI18nProvider, hook useTranslation()
apps/web/src/lib/format.tspomocnicze format(), plural(), formatFileSize()
apps/api/src/routes/config.tspubliczny punkt końcowy GET /api/v1/config/locale

Tłumaczenie witryny, dokumentacji i dokumentacji API

Opisane powyżej wsparcie dla 21 języków obejmuje aplikację. Publiczna witryna (snapotter.com), ta strona z dokumentacją oraz dokumentacja REST API również są tłumaczone na wszystkie 21 języków przez osobny, sterowany hashem potok, który ponownie wykorzystuje te same nazwy i opisy narzędzi z packages/shared/src/i18n, dzięki czemu terminologia pozostaje spójna wszędzie.

Domyślnie tłumaczone maszynowo

Każda nieanglojęzyczna strona witryny i dokumentacji jest tłumaczona maszynowo przy pierwszym przejściu (przez sesję Claude Code, a nie usługę firm trzecich) i zawiera niewielki, możliwy do zamknięcia baner informujący o tym, wraz z odnośnikiem z powrotem tutaj. Jest to celowe: pozwala szybko i uczciwie dostarczyć wszystkie 21 języków, a następnie zaprasza społeczność do dopracowania stron, które mają największe znaczenie. Tłumaczenie maszynowe przekazuje sens; dopiero weryfikacja przez człowieka sprawia, że tekst czyta się naturalnie.

Jak potok decyduje, co przetłumaczyć

Każda tłumaczalna jednostka źródła angielskiego jest hashowana, a hash przechowywany jest obok jej tłumaczenia. Przy każdym uruchomieniu potok:

  • tłumaczy każdą jednostkę, która nie ma jeszcze tłumaczenia,
  • pomija każdą jednostkę, której przechowywany hash wciąż zgadza się ze źródłem angielskim,
  • ponownie tłumaczy jednostkę maszynową, gdy zmieni się jej źródło angielskie,
  • oraz oznacza jednostkę dopracowaną przez człowieka jako stale (wymaga weryfikacji), gdy jej źródło angielskie ulegnie zmianie, zamiast nadpisywać Twoją pracę.

Dopracowanie tłumaczenia strony internetowej przez PR

Tłumaczenie witryny, dokumentacji lub dokumentacji API ulepszasz w ten sam sposób, w jaki ulepszasz lokalizację aplikacji: edytując wygenerowany plik i otwierając PR.

  1. Znajdź wygenerowane tłumaczenie dla swojego języka:
    • napisy interfejsu witryny: apps/landing/src/i18n/<locale>.json
    • strona dokumentacji: apps/docs/<locale>/**.md
    • dokumentacja API: apps/api/src/openapi.<locale>.yaml
  2. Zredaguj tekst. Zachowaj kod, odnośniki, {placeholders} oraz wszelkie znaczniki ⸤I18N…⸥ dokładnie w takiej postaci, w jakiej są; walidator potoku odrzuca tłumaczenie, które pomija lub zmienia ich kolejność.
  3. Otwórz PR. Edycja jednostki zmienia jej pochodzenie z machine na human, dzięki czemu potok nigdy jej nie nadpisze przy późniejszym uruchomieniu. Jeśli źródło angielskie zmieni się później, Twoja jednostka zostanie oznaczona jako stale do weryfikacji, zamiast zostać po cichu zastąpiona.

Aby zgłosić błędne tłumaczenie bez przesyłania kodu, otwórz zgłoszenie na GitHubie z podaniem adresu URL strony, języka, nieprawidłowego tekstu oraz proponowanej poprawki.

TIP

Potok tłumaczeń uruchamiają opiekunowie projektu; do wniesienia wkładu nie potrzebujesz klucza API. Wystarczy, że zredagujesz wygenerowany plik i otworzysz PR. Zajrzyj do scripts/i18n/README.md, aby dowiedzieć się, jak działa potok.