Visitar URL original
[FEAT] Localized module keys without freezing the default structure · Issue #2503 · fastfetch-cli/fastfetch · GitHub
Skip to content

[FEAT] Localized module keys without freezing the default structure #2503

Closed

Description

@wehrwolfmann

Description

Module keys are always English — OS, Kernel, Memory, Local IP and so on. That is a deliberate and defensible default, and I am not asking to change it. What I would like to discuss is whether fastfetch could optionally supply translated default keys while leaving everything else exactly as it is.

Concretely, something along these lines:

  • a per-language table mapping module type to its default key string, either embedded at build time or shipped as plain JSON next to the presets (presets/locale/ru.jsonc etc.), read with yyjson like any other config — no new dependency, nothing beyond libc and yyjson;
  • opt-in and explicitly selectable, e.g. --key-language ru, or picked up from LC_MESSAGES only if the user asks for that;
  • an explicit key in a user config always wins, so nothing changes for anyone who has one;
  • placeholders untouched — the table would substitute only the literal part of the key, so {1} / {2} semantics stay owned by the module code.

I am aware this is not as trivial as it sounds from the outside: FF_OS_MODULE_NAME "OS" is used both as the printed key and as the module's identity in the registry (src/modules/os/os.c, .name = FF_OS_MODULE_NAME), so any translation would first require separating "name of the module" from "label shown to the user". That is exactly why I am opening a discussion rather than a pull request — the cost lands in your code, not mine, and you may well decide it is not worth it.

Motivation

Why not the Command module? Because this is not about detecting anything new. The information is already there and already correct; only its label is in the wrong language. Reimplementing os, gpu, disk, battery and the rest through Command would mean throwing away all the platform detection and formatting that makes fastfetch worth using, in order to change a handful of words.

Why not just set key per module? That does work, and it is what I do today:

{
    "modules": [
        "title",
        "separator",
        { "type": "os",      "key": "Система" },
        { "type": "host",    "key": "Устройство" },
        { "type": "kernel",  "key": "Ядро" },
        { "type": "uptime",  "key": "Время работы" },
        { "type": "display", "key": "Экран ({2})" },
        { "type": "wm",      "key": "Оконный менеджер" },
        // ... every remaining module spelled out by hand ...
        { "type": "disk",    "key": "Диск ({1})" },
        { "type": "localip", "key": "Локальный адрес ({2})" },
        { "type": "locale",  "key": "Язык" }
    ]
}

The catch is the array itself. To rename the keys I have to enumerate modules by hand, and from that moment my config is pinned to whatever the default structure was on the day I wrote it. Every later change you make to the default structure silently passes me by — I traded staying current for having readable labels. A plain localized preset in presets/ would have exactly the same problem, which is why I am asking about default keys specifically rather than about shipping more presets.

Two smaller points on top of that:

  • the placeholders differ per module — {1} is the mount point for disk but the card index for gpu, and the interface name is {2} for localip — so hand-writing them is easy to get subtly wrong, and everyone rediscovers this separately;
  • out of the box a non-English user gets an English fetch, and fastfetch output travels further than most program output: it is the thing people put in screenshots, forum posts and bug reports when they show their system.

Additional context

Tested on fastfetch 2.67.0 (x86_64), Linux, KDE Plasma — the config above is what I actually run, so the workaround is proven; it is only its maintenance cost I am raising.

If the idea is acceptable in principle, I am happy to prepare the first implementation along with the Russian set of labels, in whatever shape you prefer. And if the answer is "the manual key override is the intended solution and that is enough", that is a perfectly good answer too — better heard now than after a pull request.

Activity

  1. added a commit that references this issue on Aug 14, 2026
    f95167e
  2. CarterLi commented on Aug 14, 2026

    @CarterLi
    Member

    Please test

  3. wehrwolfmann commented on Aug 15, 2026

    @wehrwolfmann
    ContributorAuthor

    Built dev (233c481) and tested ru on CachyOS/KDE. It does exactly what I hoped for, thank you — and the .name / .displayName split is a nicer answer than the external table I suggested.

    What I checked: --key-language ru and display.key.language in the config both work; an explicit key still wins; placeholders survive (Дисплей (CMN1629), Диск (/), Локальный IP (wlan0)); --structure OS:Kernel still matches by English name; --format json keeps "type": "OS", so scripts are unaffected; module errors use the translated key too. With --key-width the column stays straight, since padding is \e[NG rather than byte counting. On -c all almost every key came out Russian.

    Two things I ran into:

    1. Auto-detection aborts instead of falling back. LC_ALL=C fastfetch --key-language (or "language": null in the config) exits 477 with Error: Language 'C' is not supported. That makes a config with auto-detection fail in scripts, CI and plain LC_ALL=C shells, and for every user outside the 12 supported locales. An explicit --key-language ar erroring is right; silently falling back to en when the language was auto-detected seems safer.

    2. pt and zh are rejected while pt_BR and zh_CN work. The prefix pass checks startsWith(language, table_key), so ru_RU → ru works but a bare pt never matches pt_BR.

    Minor, on the Russian set only: Bluetooth -> Блютус should be Блютуз, and CPU appears three ways (CPU, Кэш процессора, Использование ЦП). Happy to send a small PR for the Russian wording if you want it.

  4. CarterLi commented on Aug 16, 2026

    @CarterLi
    Member

    2. pt and zh are rejected while pt_BR and zh_CN work. The prefix pass checks startsWith(language, table_key), so ru_RU → ru works but a bare pt never matches pt_BR.

    pt_BR is now migrated to pt. As for zh, as a native Chinese speaker, I think it's still better not to choose a default one.

    on the Russian set only: Bluetooth -> Блютус should be Блютуз

    They are translated by LLM, and LLM insists that Блютуз is a common typo of Блютус. But I'll trust you.

  5. wehrwolfmann commented on Aug 16, 2026

    @wehrwolfmann
    ContributorAuthor

    Thanks for the quick turnaround on pt. Agreed on zh — leaving it unset is the safer call.

    On Блютуз: it is the standard rendering, it follows the English pronunciation. Блютус is the typo, not the other way round.

    One thing from my earlier comment did not come up, and it is the one I would still worry about: auto-detection aborts instead of falling back. LC_ALL=C fastfetch --key-language exits 477 with Error: Language 'C' is not supported, and so does "language": null in the config. An explicit --key-language ar erroring is right, but a config with auto-detection then fails in scripts, in CI, and for every user whose locale is not one of the twelve. Should I open a separate issue for it, or is it already on your list?

    Also: if the other sets were machine-translated too, I am happy to go through the whole Russian one properly — all 75 keys, not just the two I tripped over. Say the word and I will send a PR.

  6. wehrwolfmann commented on Aug 16, 2026

    @wehrwolfmann
    ContributorAuthor

    Correction to what I just wrote — I gave you the wrong answer. The right fix is neither Блютуз nor Блютус: leave it as Bluetooth, in Latin script.

    Russian UIs do not transliterate it. Windows, Android, KDE, GNOME and the Russian Arch Wiki all write Bluetooth. The transliterations exist in speech, not in labels — it is a technology name and a trademark.

    Your own set already does this, which is the real argument: Wi-Fi is left in Latin, and so are BIOS, CPU, DNS, GPU, OpenCL, OpenGL, TPM, Vulkan, BTRFS and Zpool. Wi-Fi and Bluetooth are the same category, so the Russian entry is just inconsistent with the other ten.

    Sorry for the detour — the LLM and I were arguing about the wrong question.

  7. CarterLi commented on Aug 16, 2026

    @CarterLi
    Member

    PR welcome

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions