npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rithien/factorio-translate

v0.1.4

Published

Plugin Clusterio: tłumaczenie czatu Factorio en↔pl przez LibreTranslate lub Google Cloud Translate (wybór backendu w configu). Czyta czat z wyjścia serwera, odsyła tłumaczenie przez RCON jako custom command /fp (zachowuje achievementy, wymaga scenariusza

Readme

@rithien/factorio-translate — tłumacz czatu Factorio (en↔pl)

Plugin Clusterio: tłumaczy czat w obie strony en↔pl przez wybrany backend — LibreTranslate albo Google Cloud Translate (v2 Basic). Backend wybiera się jednym polem konfiguracji (translator_backend — dropdown w web panelu clusterio). Plugin czyta wiadomości czatu z wyjścia serwera, wykrywa język (/detect), i jeśli confidence > min_confidence — tłumaczy (/translate) i odsyła wynik na serwer przez RCON jako:

<player> [<lang>] <tłumaczenie>

gdzie <lang> (en lub pl) to język, w którym jest <tłumaczenie>. Przykład: gracz pisze po polsku „cześć" → na czacie pojawia się Bob [en] hi.

Bez patchowania save'a — brak folderu module/, działa niezależnie od factorio.enable_save_patching.

Wysyłka tłumaczenia idzie przez RCON jako custom command /fp <text> (zdefiniowany w scenariuszu factorio-polska w commands/fp.lua). W przeciwieństwie do wbudowanego /sc (silent-command), custom commandy nie wyłączają achievementów w save'ie.

Wymaga scenariusza factorio-polska 0.1.0+ — bez niego RCON dostanie "Unknown command: fp" i tłumaczenia nie pojawią się na czacie. Plugin nie ubije serwera — sytuacja jest po prostu logowana.

Opis kanałów komunikacji z grą: Plugin_comunication.md. Wytyczne implementacyjne: CLAUDE.md.

Struktura

factorio-translate/
├── index.js                 # eksport `plugin` (nazwa, entrypointy, instanceConfigFields)
├── instance.js              # InstancePlugin: onOutput ([CHAT]) -> detect/translate -> sendRcon(/fp ...); sanitizeForFp
├── translators/             # warstwa backendów (wspólny kontrakt: configured / detect / translate)
│   ├── index.js             #   createTranslator(opts) — fabryka wybierająca backend wg translator_backend
│   ├── http.js              #   wspólny postJson() — fetch + timeout + normalizacja błędów (nie loguje klucza)
│   ├── libretranslate.js    #   klient LibreTranslate
│   └── google.js            #   klient Google Cloud Translation API v2 (Basic)
├── controller.js            # ControllerPlugin — stub (na razie nic istotnego)
├── package.json             # Node >= 18 (globalny fetch)
├── test/plugin.js           # mocha
├── Plugin_comunication.md   # dokumentacja kanałów komunikacji z grą
├── CLAUDE.md                # wytyczne implementacyjne
└── (CELOWO brak module/)    # save NIE jest patchowany

Instalacja

Wymagania wstępne

  • Działający klaster Clusterio 2.x (kontroler + co najmniej jeden host z instancją Factorio).
  • Node.js ≥ 18 (plugin używa globalnego fetch).
  • Scenariusz factorio-polska 0.1.0+ na danej instancji — definiuje komendę /fp.
  • Dostęp do jednego z backendów tłumaczeń:
    • LibreTranslate — własna instancja albo publiczna/płatna z kluczem, lub
    • Google Cloud Translate — projekt Google Cloud z włączonym Cloud Translation API i kluczem API.
  • Plugin nie wymaga factorio.enable_save_patching — działa niezależnie od tej opcji.

1. Zainstaluj plugin z npm

W katalogu instalacji Clusterio (ten z node_modules/@clusterio/..., config-controller.json itd.):

npm install @rithien/factorio-translate

2. Zarejestruj plugin w każdym komponencie

Uruchamiane z katalogu instalacji Clusterio:

npx clusteriocontroller plugin add @rithien/factorio-translate
npx clusteriohost       plugin add @rithien/factorio-translate
npx clusterioctl        plugin add @rithien/factorio-translate

(clusterioctl rejestruj tylko jeśli używasz go z tej samej maszyny — przyda się do ustawiania konfiguracji w kroku 4.)

3. Zrestartuj kontroler i hosta

Zatrzymaj i uruchom ponownie procesy kontrolera oraz hosta, żeby załadowały plugin — np. przez swój menedżer usług (systemctl restart clusterio-controller / ...-host), albo Ctrl+C i ponownie npx clusteriocontroller run / npx clusteriohost run. Instancje Factorio nie muszą być wyłączone podczas restartu hosta, ale plugin „wejdzie" do działającej instancji dopiero przy jej restarcie (krok 5).

Sprawdź, że plugin się załadował — w logu kontrolera/hosta powinno pojawić się odwołanie do factorio-translate, a controller.js zaloguje (na poziomie verbose) factorio-translate (chat translator): kontroler zainicjowany. Plugin widać też na liście pluginów w web UI.

4. Skonfiguruj instancję

Wybierz backend polem factorio-translate.translator_backend (libretranslate — domyślny — albo google) i uzupełnij pola odpowiednie dla wybranego backendu. W web UI to pole jest dropdownem.

Backend LibreTranslate (minimum to translator_api_url — dopóki jest puste, backend nieaktywny):

npx clusterioctl instance config set <instancja> factorio-translate.translator_backend libretranslate
npx clusterioctl instance config set <instancja> factorio-translate.translator_api_url https://libretranslate.example
# jeśli Twoja instancja LibreTranslate wymaga klucza:
npx clusterioctl instance config set <instancja> factorio-translate.translator_api_key <klucz>

Backend Google Cloud Translate (minimum to google_api_key — dopóki jest puste, backend nieaktywny):

npx clusterioctl instance config set <instancja> factorio-translate.translator_backend google
npx clusterioctl instance config set <instancja> factorio-translate.google_api_key <klucz-google-cloud>
# (opcjonalnie, wspólne dla obu backendów) pozostałe pola — zob. tabela "Konfiguracja" niżej, np.:
npx clusterioctl instance config set <instancja> factorio-translate.min_confidence 90

Zmiany backendu / URL / kluczy / timeoutu są podchwytywane na żywo (bez restartu instancji). Konfigurację można też edytować w web UI w ustawieniach instancji.

5. Uruchom (lub zrestartuj) instancję ze scenariuszem factorio-polska

npx clusterioctl instance start <instancja>

Od tego momentu wiadomości z czatu w obsługiwanych językach (en/pl) z confidence > min_confidence będą tłumaczone i wysyłane na czat w formacie <player> [<lang>] <tłumaczenie>.

Aktualizacja / odinstalowanie

  • Aktualizacja: npm install @rithien/factorio-translate@latest w katalogu Clusterio, zrestartuj kontroler i hosta, zrestartuj instancję.
  • Odinstalowanie: plugin remove @rithien/factorio-translate w każdym komponencie (analogicznie do plugin add), zrestartuj kontroler i hosta.

Konfiguracja (instancja, prefiks factorio-translate.)

| Pole | Typ | Domyślnie | Opis | |---|---|---|---| | enabled | boolean | true | Czy plugin jest aktywny na tej instancji | | translator_backend | enum | libretranslate | Backend tłumaczeń: libretranslate lub google (dropdown w web panelu) | | translator_api_url | string | "" | [libretranslate] Bazowy URL LibreTranslate, bez końcowego /. Puste = backend nieaktywny | | translator_api_key | string | "" | [libretranslate] Klucz API; puste = bez klucza. Nie jest logowany | | google_api_key | string | "" | [google] Klucz Google Cloud (Cloud Translation API). Puste = backend nieaktywny. Nie jest logowany | | min_confidence | number | 90 | Próg confidence z /detect (0–100); tłumaczymy gdy confidence > min_confidence. Google: 0–1 → ×100, brak → 100 | | request_timeout_ms | number | 5000 | Timeout pojedynczego żądania HTTP | | min_message_length | number | 1 | Minimalna długość wiadomości, by ją tłumaczyć | | translate_server_messages | boolean | false | Czy tłumaczyć też wiadomości od <server> | | max_output_length | number | 500 | Sanity-cap na długość /fp <text> (anti-flood + RCON line) |

Zmiana translator_backend / translator_api_url / translator_api_key / google_api_key / request_timeout_ms jest podchwytywana na żywo (bez restartu instancji).

Jak to działa (przepływ jednej wiadomości)

  1. onOutput dostaje linię z parsed.type === "action" && parsed.action === "CHAT"; treść to "<player>: <text>" — rozdzielana na pierwszym ": ".
  2. Guardy: aktywny? text niepusty i ≥ min_message_length? nadawca ≠ <server> (chyba że translate_server_messages)? text nie pasuje do ^\S+ \[(en|pl)\] (anty-pętla)?
  3. POST /detect{ language, confidence }. confidence <= min_confidence → koniec.
  4. language === "pl"target = "en"; language === "en"target = "pl"; inny język → koniec.
  5. POST /translate (source, target, format: "text") → translatedText.
  6. sendRcon('/fp <player> [<target>] <translatedText>', true). Linia przepuszczona przez sanitizeForFp() (strip znaków sterujących + cap długości) — /fp po stronie Lua robi tylko game.print(cmd.parameter), więc nie ma interpretacji Lua i nie potrzeba escape'owania.

Błąd backendu tłumaczeń (sieć, timeout, 4xx/5xx) → log warn i pomięcie tej wiadomości; serwer nieruszony. Krok 3–5 wykonuje wybrany backend (LibreTranslate /detect + /translate, albo Google Cloud Translation v2 /detect + /translate) — instance.js widzi tylko wspólny kontrakt detect() / translate().

Dlaczego /fp zamiast /sc

Wbudowane /sc (silent-command) i /c ustawiają trwałą flagę "Cheats have been enabled" na save'ie — permanentnie wyłączają achievementy. Custom commandy zarejestrowane przez commands.add_command w Lua nie liczą się jako cheats. Scenariusz factorio-polska rejestruje /fp (server-only, RCON-only) jako trywialny alias dla game.print(cmd.parameter). Plugin po prostu wysyła /fp <text> i tekst trafia do czatu bez setowania cheat flagi.

Patrz scenario/commands/fp.lua w repo factorio-polska.

Uwagi

  • Plugin nie kasuje oryginalnej wiadomości — dokłada tłumaczenie obok.
  • Kolejność wysłanych tłumaczeń może odbiegać od kolejności wpisania (różna latencja API + długie komendy RCON). Dla czatu akceptowalne.
  • LibreTranslate: dla sensownego limitu zapytań użyj własnej instancji albo płatnego klucza — publiczne instancje bywają mocno rate-limitowane (HTTP 429 → wiadomość zostanie pominięta).
  • Google Cloud Translate: używany jest API v2 (Basic) z uwierzytelnianiem kluczem API (?key=), nie v3 (OAuth2 / konto serwisowe). Cloud Translation to usługa płatna — pilnuj limitów/budżetu w Google Cloud. Klucz najlepiej ogranicz (restrict key) do Cloud Translation API.

Testy

npm install
npm test