#Internationalization (i18n)
SillyTavern supports multiple languages. This guide explains how to add and manage translations.
You're probably here because some piece of text is untranslated in your language, and it's driving you nuts. First I'll show you how I fixed some missing translations in the Chinese (Traditional) locale. Each was missing for a different reason, so you'll get a good idea of how to fix your own missing translations.
In the second half, we look at
- how i18n works in SillyTavern,
- writing translations and code to use them,
- debug functions to find missing translations,
- adding a new language,
- and contributing your changes.
If you're developing an extension or modifying the core code, write your HTML and JavaScript with i18n in mind. This way your work is ready for other people to translate it into their language.
Nobody knows 15 languages by themselves. We work together to make SillyTavern accessible to everyone.
Everyone in the world should be able to use their own language on phones and computers.
#Let's fix some missing translations!
All 3 of these issues required code changes to fix. If you're adding a new translation, you might not need to touch the code at all. Just add the translation to the JSON file. It just so happens that somebody recently added a large number of missing translations to the Chinese (Traditional) JSON file, so the remaining issues were all in the code. In other locales there are plenty of missing translations you can fix without touching the code.
#Generate Image
The text "Generate Image" is untranslated in the Chinese (Traditional) locale. Why?
Right-click on the element and inspect it. You'll see the HTML:
Where is its data-i18n
attribute? It's missing! Let's add it. We find it in the source code:
We are in luck, that string Generate Image
is in many of the language files, including in Chinese (Traditional).
Why isn't it showing up? We have to wire the element up correctly:
Now it works! Reload the page and see.
But while we have the HTML open, what's with Stop Image Generation
just under it? The HTML doesn't look right.
If we generate an image and then open the wand menu while it's generating, we see untranslated text.
First fix the HTML:
This isn't enough to fix the issue. There are no translations for "Stop Image Generation" in the Chinese (Traditional) file. We can add it! Here's one possible translation:
... which we can add to the JSON file just after the "Generate Image" translation.
After some discussion with Claude, we're actually going to go with the following translations:
- Traditional Chinese: "Stop Image Generation": "終止圖片生成"
- Simplified Chinese: "Stop Image Generation": "中止图像生成"
- Japanese: "Stop Image Generation": "画像生成を停止"
"Generate Caption" is untranslated in the Chinese (Traditional) locale. Let's fix it!
Where is it? Inspect the element.
Turns out that this HTML is produced by JavaScript. Let's find the source code.
We will first have to fix the code:
There are also no translations for "Generate Caption" in the Chinese (Traditional) file. Let's add it!
We will use the following translations:
- Traditional Chinese: "Generate Caption": "生成圖片說明"
- Simplified Chinese: "Generate Caption": "生成图片说明"
- Japanese: "Generate Caption": "画像説明を生成"
#Inspect Prompts
The text "Inspect Prompts" is untranslated in the Chinese (Traditional) locale. Why? This one is a bit more complicated. The text is generated by JavaScript, and the translation is missing.
Well wouldn't you know it... neither phrase is in the i18n files. Let's add them.
Now we have to fix the JavaScript code. It has to use the t
function to get the translation.
We got these suggestions from Claude. Keep the strings, ignore the code. They have to be added to the JSON files.
We will merge those into the JSON files.
A pity about that tooltip. The problem is that the code doesn't use the t
function.
We will have to fix that in the extension code.
We also need to add the translations to the JSON files.
Prompt inspector is a separate extension, so we will PR the code fixes to that repo: https://github.com/SillyTavern/Extension-PromptInspector/pull/1
The translations will be added to the main SillyTavern repo. https://github.com/SillyTavern/SillyTavern/pull/3198
#Language files
Each language has a JSON file in public/locales/
named with its language code (e.g., ru-ru.json
).
The file contains key-value pairs where:
- Keys are either the original English text or unique identifiers
- Values are the translated text
Example:
#How translations work
There are two ways translations are used in the application:
HTML Elements: Using
data-i18n
attributesThe default text in the HTML will be replaced with the translated text if available.
Template Strings: In the JavaScript code using the
t
functionThese strings should be translated keeping the
${0}
,${1}
, etc. placeholders intact.
SillyTavern uses HTML elements with data-i18n
attributes to mark translatable content. There are several ways to use this:
#1. Translating Element Text
For simple text content:
This replaces the element's text content with the translation of "Role:".
#2. Translating Attributes
To translate an attribute like a title or placeholder:
The [title]
prefix indicates which attribute to translate. The rest of the attribute value is the text that will be used as a lookup key in the JSON file. It is common for coders to use the English text as the key, but it is not required. The key can be any unique identifier.
The original English text must be present in the corresponding attribute (title="Insert prompt"
) though. It's used as a fallback if the translation is missing. Most notably, there is no translation file for English.
Here is an example of using a unique identifier no_items_text
as the key, rather than the English text:
#3. Multiple Translations Per Element
Some elements need both content and attribute translations, separated by semicolons. The most common pattern is translating both the element's text content and its title attribute:
This translates:
- The element's text content using the key "Authorize"
- The title attribute using the key "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai"
Note that both the title
attribute and the element's text content are provided in English as fallbacks.
You can also translate multiple attributes:
The corresponding translations in your language file would look like:
When the page loads, the system:
- Finds all elements with
data-i18n
attributes - Parses any attribute prefixes like
[title]
or[placeholder]
- Looks up each key in your language's JSON file
- Replaces the element's content or attributes with the translated text
#Dynamic Text
For dynamic text in JavaScript code, translations use either:
- Template literals with the
t
function: - Direct translation function:
#Variable Placeholders
Some strings contain placeholders for dynamic values using ${0}
, ${1}
, etc:
Keep the placeholders the same for key and translation. The system will replace ${0}
with the value of presetName
, etc.
#Finding missing translations
Let's say you don't just want to fix one annoying missing translation, you want to find them all.
That's a big ambition! Even fixing one translation is worth it. But if you want to catch 'em all, you need a tool.
#SillyTavern-i18n
https://github.com/SillyTavern/SillyTavern-i18n
Tools for working with frontend localization files.
Features:
- Automatically add new keys to translate from HTML files.
- Prune missing keys from localization files.
- Use automatic Google translation to auto-populate missing values.
- Sort JSON files by keys.
#Inbuilt debug functions
These are under User Settings > Debug Menu.
#Get missing translations
Detects missing localization data in the current locale and dumps the data into the browser console. If the current locale is English, searches all other locales.
The console will show a table of missing translations with:
- key: The text or identifier needing translation
- language: Your current language code
- value: The English text to translate
#Apply locale
Reapplies the currently selected locale to the page
Neither of these tools are perfect
- they don't catch missing translations in JavaScript code
- they don't catch missing data-i18n attributes in HTML, they just catch untranslated keys
- there are bugs in the code for
getMissingTranslations
: keys should not be prefixed with[title]
or[placeholder]
#Adding a new language
To add support for a new language:
Add your language to
public/locales/lang.json
:Create
public/locales/xx-xx.json
with your translations
#Contributing
When your translations are ready:
- Verify your JSON file is valid
- Test thoroughly in the application
- Submit via GitHub pull request