Skip to content

Languages

Ryan McAfee edited this page Sep 20, 2026 · 2 revisions

Languages

BakaLoader can show itself in a language other than English. The globe in the title bar, just left of the Command chip, is where you pick one.

English is inside the app and is always there. Every other language is a pack: a file of translated sentences plus the fonts needed to draw them, downloaded once from the BakaLoader release it belongs to and kept on your machine afterwards.

Four packs are published for 1.2.0: Русский, 日本語, 简体中文 and 繁體中文. They are cut from the same English catalog the app itself reads, which holds 1,702 sentences in this release, and they weigh between about 110 KB and 750 KB. The difference between them is almost entirely the fonts a script needs rather than the words.

Switching

Press the globe. You get a list of every language BakaLoader knows about, each one written in its own name, with a line underneath saying where it stands:

Current is the one you are reading now.

Current, using the pack from 1.1.9 is the one you are reading now, drawn from a pack cut for an older BakaLoader. It used to say only Current, which meant the one host who most needed to know the words on their screen were coming from an older pack, the host reading them, was the only one the menu did not tell.

Ships inside BakaLoader is English. There is nothing to download.

Downloaded means the pack is on your machine and matches this version of BakaLoader. Press the row and the window is in that language before you let go of the mouse.

Not downloaded, 497.4 KB means there is a pack published for this version and that is what it weighs. The number is the pack's own byte count out of the published list, written the way your machine writes sizes. Press the row and it comes down.

Using the pack from 1.1.9 means you have a pack, but it was cut for an older BakaLoader. It still works. Anything added to the interface since that pack was made is still in English, and the note at the bottom of the menu says how many lines that is.

No pack published for this version yet means nobody has cut one.

Needs a connection to download means BakaLoader could not reach the release page to find out what is published. The languages you already have still work offline; this row is about the ones you do not.

Nothing reloads. The Log keeps its scrollback, both search boxes keep what you typed, and anything unsaved in the config editor is still unsaved when the words change. Switching is not a restart and never has been.

One switch is one redraw. Every other window on the machine follows, because the language is one setting, but the window you pressed in does not follow its own press: it used to redraw twice, once for its own answer and once for the message telling every window what had happened.

Downloading a pack

The row turns into a progress bar with a Cancel beside it.

While BakaLoader is still working out which release to ask, the bar sweeps rather than sitting at zero, because nothing knows the size yet. Once the download starts you get a real bar and a line saying how far along it is.

Cancel stops it, and nothing on your machine changes: the half a file goes, and if you already had an older pack it is exactly where it was.

There is one moment Cancel cannot help. When the download has finished and the pack is being put into place, stopping halfway would leave you with half a language. Cancel goes grey for those couple of seconds and the tooltip says why. If you press it in the instant before it greys out and the install had already begun, BakaLoader tells you that rather than pretending it stopped something.

If a download fails, the row says why in a sentence and keeps a Try again beside it. The reasons are things like the pack not matching its published checksum, the download going quiet, or the release page not answering.

One pack comes down at a time. Start a second and you are told the first is still going.

Partial translations

A pack carries the sentences that existed when it was cut. Anything added since is still in English.

A sentence a pack left blank is English too, and that is worth saying plainly because a half filled pack is the normal state of one while it is being translated. A line the pack does not answer for, whichever way it does not answer, is read as a line the pack does not have: no key at all, a key with nothing behind it, a key holding a translator tool's placeholder, an entry with an empty sentence in it, or a plural that was only filled in for some of the counts. Every one of those falls back to the English sentence. What never reaches your screen is the name the sentence is filed under, the dotted hearth.head.title sort of thing, which is what a lookup that trusted the pack would have painted.

When a pack is behind the app you get two marks: a line at the bottom of the globe menu saying how many lines are still English, and a small amber dot beside the version in the bottom left corner with the same sentence on its tooltip.

It is never a pop-up. It is a standing fact about the words on your screen, not something that just happened, so it sits somewhere you can look at it rather than interrupting you.

Machine translated

A pack marked Machine translated was produced by a machine and not read through by a person who speaks the language. It is usually fine and occasionally strange.

If you find something wrong, the corrections are welcome. Open an issue on the BakaLoader repository with the English sentence, what it currently says in your language, and what it should say. The id of the sentence helps if you have it, but the English is enough to find it.

Packs that a native speaker has been through do not carry the mark.

Messages to players

The globe changes your interface. The people on your server never see it.

What they do see is the restart countdown in the game chat, and what your Discord channel sees is the status post and the event posts. Those have a setting of their own: Messages to players, in the Upkeep card on the Dashboard, right under Show Norse names.

It offers Same as the interface, which is the default, English, and every language you have a pack for. English is always in the list because it is built into the app rather than downloaded, so you can write to your players in English while your own window is in Japanese without installing anything. Set it to Japanese and the countdown your players read is Japanese while your window stays in English, or the other way round. The two choices are independent because they are two different audiences.

One thing it does not change: the countdown chip on BakaLoader's own window. That is yours, and it follows the interface language. The same countdown is therefore saying the same thing twice in two languages at once, once in the game chat for your players and once on your own window for you, which is the point.

How it works

Where packs live

Beside your settings, not in the install folder:

%USERPROFILE%\AppData\LocalLow\BakaLoader\ValheimBakaLoader\languages\

Inside it:

manifest-cache.json          the last list of published packs, with the tag it came from
_fonts\<sha256>.woff2        the fonts, named after their own contents
_fonts\OFL-<sha256>.txt      the font licences
ru\1.2.0\strings.json        the sentences, one folder per language per version
ru\1.2.0\pack.json           what the pack says about itself
.staging\                    half-downloaded packs, emptied on every start

Nothing is ever written into the BakaLoader install folder, which is why an update or a reinstall cannot take your packs with it.

The fonts are shared. Two languages that use the same face store it once, because the file is named after a hash of its own bytes: same bytes, same name, one copy. That is also why the address of a font has no version in it. One pack can name the same file twice as well: the Chinese and Japanese packs declare their body face a second time for the handful of marks whose code points sit among the Latin ones, the ellipsis and the middle dot in all three of them and the two curly quotation marks in Simplified Chinese as well, so those come out full width instead of narrow. It is the same file both times, so it is downloaded once and stored once.

A pack can only publish a face under a family name the stylesheet actually asks for. The tool that cuts a pack reads the stylesheet and holds the two against each other: every family the pack declares has to be one of the stacks for that language, and every family those stacks name has to be one some pack declares. A face published under a name nothing asks for is bytes downloaded, stored, served and never drawn, and nothing inside the pack itself can see that. The test suite does the same reading again against the real published packs.

What gets downloaded, and from where

Every BakaLoader release from 1.2.0 on publishes a file called lang-manifest.json alongside the app. It lists each language with its pack's address, its size, its checksum, how many sentences it carries and how many of those are translated.

BakaLoader asks for the manifest when you open something that is drawn from it. There are two such places: the globe menu, and the Upkeep card, because the Messages to players list is built from the same answer. Opening either one is you asking out loud. A window that merely started asks for nothing, and neither does one sitting on the Dashboard with Upkeep shut.

Opening either of those asks whatever Check for BakaLoader updates is set to. That switch governs what BakaLoader does on its own account, and a menu you opened is not that. It is the same rule the update check follows: the switch stops the unattended request, never the one you made.

The address of a pack comes out of the manifest. BakaLoader never builds one itself, which is what makes it impossible for a typo in a version number to turn into a request for a file that does not exist.

There is one other time a pack is fetched without you pressing anything. If you were reading Russian, and BakaLoader updates itself, and no Russian pack for the new version is on your machine yet, it quietly fetches one in the background. That is governed by Check for BakaLoader updates in Upkeep: with that switch off, nothing is fetched on BakaLoader's own account, and the globe menu says so in a footer note. You can still download a pack by pressing it, because that is you asking.

Checksums

The manifest publishes a SHA-256 for every pack, and a byte count.

The hash is computed while the file is being written, so nothing is read twice. When the download ends, both the hash and the byte count have to match what was published. If either is out, the download is thrown away and nothing on your machine changes. An older pack you already had is untouched.

The same thing happens one level down, for the fonts. Each font inside the pack is hashed and checked against what pack.json says before it is moved into the shared store, and a file that claims to be a font but does not begin like one is refused outright.

A pack that passes all of that is moved into place in one step, so there is no moment where the folder holds half a language.

There is also a size ceiling. A pack larger than 80 MB is refused before a byte of it is fetched.

What survives an update

Everything. Packs live beside your settings, and your chosen language is a setting like any other.

When BakaLoader updates itself, the pack you have was cut for the version before. It keeps working: the window comes up in your language, with the older pack's sentences, and anything added in the new version reads in English until a matching pack arrives. The menu and the dot in the corner tell you how many lines that is.

If a new pack is published for the new version and nothing in the sentences actually changed, BakaLoader copies the pack you already have to the new version rather than downloading it again. A patch release usually costs you nothing.

Old packs are tidied up on start. The newest two versions of each language are kept, plus whichever one the running version needs, and fonts nothing refers to any more are deleted with them.

Why the window is never written in English first

The window is written in your language. No part of it is written in English and then rewritten, and there is no frame in which you see English before your own language arrives.

Two things together do that, and they are worth separating because for a while only the first one existed.

The passes. Before the page writes a word of the interface it asks the app one question: which language is saved, and where its words are. The English catalog is read first, because it is the fallback for anything a pack is missing, then the pack, and only after both of those does anything go over the document putting words into it. Every pass it gets is in your language. There is never one in English for a later one to correct.

The usual way of doing this is the other way round: write the window in English, fetch the words, then go back over the whole document replacing them. You see that second pass. Labels change under the mouse, rows change width, and anything the pack is missing changes twice. That is the thing this avoids.

The first frame. The passes alone do not cover the moment before any of them: the page's own frame goes up while those two files are still being read, and it was showing the English written into the markup. Measured on a headless browser driving the real startup, that was about 130 milliseconds, with your language landing four painted frames later. Brief, since both files come off your own disk, but not nothing.

So the app now says the language before the page exists. When your saved language is not English and its pack is on disk, BakaLoader hands the window that language on the way in, and the page keeps its contents hidden until it has been written in that language. The window is laid out at its real size the whole time, so nothing jumps when it appears; what you see until then is the window's own background.

The hiding has a hard limit of a second and a half. If the pack cannot be read, or the file never arrives at all, the window comes back anyway and comes back in English. There is no way for a broken pack to leave you looking at an empty window.

An English window is untouched by all of this. No hiding, no delay, and the same first frame it has always had.

The fonts arrive on the same road. A pack's faces are declared at the moment the pack loads, addressed by their hash in the shared store, so the interface is drawn in the right face rather than swapping under you.

Fonts and why the small print grows

The faces BakaLoader ships cover Latin and nothing else. A pack carries the faces its own script needs.

The type settings change with the language too, and they have to. BakaLoader's English look leans on wide letter spacing and small capitals, which is inscriptional on Latin and a rendering fault on Chinese or Japanese: a character carrying twenty strokes in the space a letter uses for three needs the size and not the spacing. So under those languages the smallest labels come up to 12px, the letter spacing comes off, and the uppercasing goes, since it does nothing on those scripts anyway. That now includes the title on the condition bar across the top of a hall, which was the last label of its size with no rule of its own and was drawing a twelve character Japanese title at 9px.

Russian gets a milder version of the same treatment. Its labels on the left rail hold at 10px at every window height now. They used to step down to 9px on a window shorter than 780 pixels, on the assumption that the longest of them would not fit the rail otherwise. Measured in the real rail at the smallest window BakaLoader opens at, the longest of the nine needs 68.5 of the 76 pixels it has, so there was never anything to pay for it with.

Line breaking changes as well. Chinese and Japanese wrap between characters and have their own rules about which marks may not begin or end a line, and a Latin word in the middle of one of those sentences, a version number or a path, is kept whole.

Adding a language

The packs are built from the same English catalog the app reads, WebUI/i18n/en.json, which is a plain file of sentences keyed by name. If you want to take a language on, open an issue and say so. The tooling that cuts a pack is in the repository under scripts/i18n/.

A pack does not have to be complete to be usable, and it cannot break the window by being incomplete. A sentence a pack has no answer for falls back to the English, and so does one whose answer is not a sentence at all: some pack tooling writes a placeholder into the file for every line it did not translate, and a placeholder is read as a hole rather than drawn on screen. What a host must never see is the internal name of a sentence where the sentence should be.

Questions people ask

Does my language reach anyone else? No. It is your window. The people on your server see whatever Messages to players is set to, which is its own choice.

Do my players have to install anything? No. Valheim renders the chat text itself. Whatever language the countdown is written in, it arrives as ordinary chat.

Can I have two windows in two languages? No. The language is one setting, and every open window follows a switch made in any of them.

What happens if I delete the languages folder? BakaLoader falls back to English and the menu offers the packs again. Nothing else is in there.

Why did every language say "could not be downloaded" on 1.2.0? Because the window could not read a pack back, not because anything was wrong with the pack. The files downloaded, passed their checksum and landed on disk; the address they were served from was one the embedded browser had already given to the interface folder, so nothing ever answered a request for them. 1.2.1 gives packs an address of their own. Nothing you downloaded on 1.2.0 was broken. 1.2.1 adds sentences of its own, so its catalogue revision went up and it fetches its own pack once for the language you are reading; a release that adds no sentences keeps the revision, and then the pack already on disk is reused rather than downloaded a second time.

What can the window read out of the languages folder? All of it. Serving a pack's fonts means giving the folder an address the page can fetch from, so every installed pack, every font in the shared store, the licence texts and the manifest cache are readable by the interface. That is downloaded translation data and none of it is yours. Everything of yours sits BESIDE that folder rather than inside it: userprefs.json, the logs and the caches are siblings of languages, not children, and the page cannot reach them. A pack is also trimmed on the way in, to its catalogue, its own pack.json, the faces it lists and a licence text; anything else an archive carries is dropped before it is put in place.

Does this send anything about me anywhere? No, and there are three requests rather than two. BakaLoader asks GitHub's API which files are on the release for your version, because the manifest is found on that release by name rather than at an address somebody typed. Then it downloads the manifest, and then the pack file itself: when you press a language, or on its own after BakaLoader has updated and your language has no pack for the new version yet (the paragraph above on the quiet fetch, which Check for BakaLoader updates switches off). All three are plain reads over HTTPS and none of them carries anything about you, your server or your world. See Privacy and network.

Clone this wiki locally