`, or `` elements), _notifications messages_, and option _label_ strings, etc.
We **do not** translate the console log messages, CSS class names, theme names, nor the various _value_ strings (e.g. for value/label pair options), nor URL routes.
The localizations are stored in _.json_ files in the `ui/localizations/messages` directory, with one language-per-file using the [ISO 3166-1 alpha-2 country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) (e.g. en for English, de for German, etc.)
#### m-function-matcher
The translations are extracted into language files (e.g. _en.json_ for English) and then paraglide-js compiles them into helpers for use with the [m-function-matcher](https://inlang.com/m/632iow21/plugin-inlang-mFunctionMatcher). An example:
```tsx
```
#### shakespere plug-in
If you enable the [Sherlock](https://inlang.com/m/r7kp499g/app-inlang-ideExtension) plug-in, the localized text "tooltip" is shown in the VSCode editor after any localized text in the language you've selected for preview. In this image, it's the blue text at the end of the line :

#### Process
##### Localizing a UI
1. Locate a string that is visible to the end user on the client/browser
2. Assign that string a "key" that reflects the logical meaning of the string in snake-case (look at existing localizations for examples), for example if there's a string `This is a test` on the _thing edit page_ it would be "thing_edit_this_is_a_test"
```json
"thing_edit_this_is_a_test": "This is a test",
```
3. Add the key and string to the _en.json_ like this:
- **Note** if the string has replacement parameters (line a user-entered name), the syntax for the localized string has `{ }` around the replacement token (e.g. _This is your name: {name}_). An complex example:
```react
{m.mount_button_showing_results({
from: indexOfFirstFile + 1,
to: Math.min(indexOfLastFile, onStorageFiles.length),
total: onStorageFiles.length
})}
```
4. Save the _en.json_ file and execute `npm run i18n` to resort the language files, validate the translations, and create the m-functions
5. Edit the _.tsx_ file and replace the string with the calls to the new m-function which will be the key-string you chose in snake-case. For example `This is a test` in _thing edit page_ turns into `m.thing_edit_this_is_a_test()`
- **Note** if the string has a replacement token, supply that to the m-function, for example for the literal `I will call you {name}`, use `m.profile_i_will_call_you({ name: edit.value })`
6. When all your strings are extracted, run `npm run i18n:machine-translate` to get a first-stab at the translations for the other supported languages. Make sure you use an LLM (you can use [aifiesta](https://chat.aifiesta.ai/chat/) to use multiple LLMs) or a [translator](https://translate.google.com) of some form to back-translate each **new** machine-generation in each _language_ to ensure those terms translate reasonably.
### Adding a new language
1. Get the [ISO 3166-1 alpha-2 country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) (for example AT for Austria)
2. Create a new file in the _ui/localization/messages_ directory (example _at.json_)
3. Add the new country code to the _ui/localizations/settings.json_ file in both the `"locales"` and the `"languageTags"` section (inlang and Sherlock aren't exactly current to each other, so we need it in both places).
4. That file also declares the baseLocale/sourceLanguageTag which is `"en"` because this project started out in English. Do NOT change that.
5. Run `npm run i18n:machine-translate` to do an initial pass at localizing all existing messages to the new language.
- **Note** you will get an error _DB has been closed_, ignore that message, we're not using a database.
- **Note** you likely will get errors while running this command due to rate limits and such (it uses anonymous Google Translate). Just keep running the command over and over... it'll translate a bunch each time until it says _Machine translate complete_
### Other notes
- Run `npm run i18n:validate` to ensure that language files and settings are well-formed.
- Run `npm run i18n:find-excess` to look for extra keys in other language files that have been deleted from the master-list in _en.json_.
- Run `npm run i18n:find-dupes` to look for multiple keys in _en.json_ that have the same translated value (this is normal)
- Run `npm run i18n:find-unused` to look for keys in _en.json_ that are not referenced in the UI anywhere.
- **Note** there are a few that are not currently used, only concern yourself with ones you obsoleted.
- Run `npm run i18n:audit` to do all the above checks.
- Using [inlang CLI](https://inlang.com/m/2qj2w8pu/app-inlang-cli) to support the npm commands.
- You can install the [Sherlock VS Code extension](https://marketplace.visualstudio.com/items?itemName=inlang.vs-code-extension) in your devcontainer.
---
**Happy coding!**
For more information, visit the [JetKVM Documentation](https://jetkvm.com/docs) or join our [Discord Server](https://jetkvm.com/discord).