# Language Files > **Relevant source files** > * [src/lang/en_us.json](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/lang/en_us.json) > * [src/lang/ja_jp.json](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/lang/ja_jp.json) > * [src/lang/zh_cn.json](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/lang/zh_cn.json) ## Purpose and Scope This document describes the language file format, structure, naming conventions, and discovery mechanisms used by the MouseMacros localization system. Language files are JSON-formatted translation dictionaries that enable multi-language support in the application. For information about the `Localizer` class that loads and uses these files, see [Localizer](Localizer). For overall configuration system architecture, see [Configuration System](Configuration-and-Persistence). --- ## File Format Language files use JSON format with UTF-8 encoding. Each file consists of a flat key-value map where keys are translation identifiers and values are localized strings. ### Structure ```json { "key.identifier": "Translated String", "another.key": "Another Translation", "button.start": "Start Recording" } ``` The file format is loaded using Google's Gson library, which deserializes the JSON into a `Map` structure stored in the `Localizer` class. **Sources:** [src/io/github/samera2022/mouse_macros/Localizer.java L52](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L52-L52), [src/io/github/samera2022/mouse_macros/Localizer.java L58](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L58-L58) --- ## File Location and Naming Conventions ### Directory Structure Language files are stored in the `lang/` directory relative to the application root. The location differs based on execution context: | Context | Location | | --- | --- | | Development mode | `lang/` directory in project root | | JAR execution | `lang/` directory inside JAR resources | ### Naming Convention Language files follow the pattern: `.json` | Language | File Name | Example | | --- | --- | --- | | Chinese (Simplified) | `zh_cn.json` | Default language in config | | English (US) | `en_us.json` | Fallback language | | Other languages | `.json` | Format: `_.json` | Language codes use lowercase with underscore separators (e.g., `zh_cn`, `en_us`). **Sources:** [src/io/github/samera2022/mouse_macros/Localizer.java L17-L18](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L17-L18), [src/io/github/samera2022/mouse_macros/Localizer.java L23-L24](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L23-L24), [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L29](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L29-L29) --- ## Language Discovery Mechanism The application discovers available language files at runtime using `ConfigManager.getAvailableLangs()`. The discovery mechanism differs based on execution context. ### Discovery Flow Diagram ```mermaid flowchart TD Start["ConfigManager.getAvailableLangs()"] CheckDevMode["Localizer.isDevMode()"] DevPath["FileUtil.listFileNames('lang')"] DevFilter["Filter files ending with .json
Strip .json extension"] JarCheck["dirURL.getProtocol()"] JarPath["Read JAR file entries
Filter 'lang/*.json'"] FilePath["Read filesystem directory
Filter *.json files"] Return["Return String[] of language codes"] Start --> CheckDevMode CheckDevMode --> DevPath CheckDevMode --> JarCheck DevPath --> DevFilter DevFilter --> Return JarCheck --> JarPath JarCheck --> FilePath JarPath --> Return FilePath --> Return ``` **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L67-L120](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L67-L120) ### Development Mode Discovery In development mode (when `lang/zh_cn.json` exists in the filesystem), the discovery process: 1. Calls `FileUtil.listFileNames("lang")` to list all files in the `lang/` directory 2. Filters files for `.json` extension 3. Strips the `.json` extension to get language codes 4. Returns array of language codes **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L69-L79](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L69-L79), [src/io/github/samera2022/mouse_macros/Localizer.java L16-L18](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L16-L18) ### JAR Mode Discovery In JAR execution mode, the discovery process uses two approaches: #### JAR Protocol Discovery When running from a JAR file: 1. Gets URL to `lang/` resource directory via `ConfigManager.class.getClassLoader().getResource("lang/")` 2. Extracts JAR file path from the URL 3. Opens the JAR file using `java.util.jar.JarFile` 4. Enumerates all JAR entries 5. Filters entries matching pattern `lang/*.json` 6. Strips `lang/` prefix and `.json` suffix to extract language codes **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L81-L101](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L81-L101) #### File Protocol Discovery When running from extracted class files: 1. Converts URL to filesystem path using `dirURL.toURI()` 2. Lists files in directory with `.json` extension 3. Strips `.json` extension to get language codes **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L102-L114](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L102-L114) --- ## Language File Loading The `Localizer.load(String lang)` method loads language files into memory. The loading mechanism varies based on execution context. ### Loading Process Diagram ```mermaid sequenceDiagram participant Application Code participant Localizer participant File System participant JAR Resources participant Gson Parser Application Code->>Localizer: load("zh_cn") loop [isDevMode == true] Localizer->>File System: new File("lang/zh_cn.json") File System-->>Localizer: File object Localizer->>Gson Parser: fromJson(FileReader) Gson Parser-->>Localizer: Map Localizer->>JAR Resources: getResourceAsStream("lang/zh_cn.json") JAR Resources-->>Localizer: InputStream Localizer->>Gson Parser: fromJson(InputStreamReader) Gson Parser-->>Localizer: Map end Localizer->>Localizer: translations = parsedMap Localizer->>Localizer: currentLang = "zh_cn" Localizer-->>Application Code: Load complete ``` **Sources:** [src/io/github/samera2022/mouse_macros/Localizer.java L47-L65](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L47-L65) ### Development Mode Loading In development mode: 1. Constructs `File` object pointing to `lang/.json` 2. Creates `FileReader` for the file 3. Uses Gson to parse JSON into `Map` 4. Stores result in static `translations` field **Sources:** [src/io/github/samera2022/mouse_macros/Localizer.java L49-L52](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L49-L52) ### JAR Mode Loading In JAR mode: 1. Constructs resource path: `lang/.json` 2. Opens `InputStream` via `Localizer.class.getClassLoader().getResourceAsStream(path)` 3. Wraps stream in `InputStreamReader` with `StandardCharsets.UTF_8` 4. Uses Gson to parse JSON into `Map` 5. Stores result in static `translations` field **Sources:** [src/io/github/samera2022/mouse_macros/Localizer.java L54-L59](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L54-L59) --- ## Translation Key Retrieval and Fallback The `Localizer.get(String key)` method retrieves translated strings with a fallback mechanism. ### Retrieval Flow ```mermaid flowchart TD Start["Localizer.get(key)"] CheckCurrent["Key exists in
current language?"] ReturnCurrent["Return translation from
current language"] CheckFallback["Current language
is 'en_us'?"] LoadEnglish["Load en_us.json"] CheckEnglish["Key exists in
en_us.json?"] ReturnEnglish["Return translation from
en_us.json"] ReturnKey["Return key as-is
(untranslated)"] Start --> CheckCurrent CheckCurrent --> ReturnCurrent CheckCurrent --> CheckFallback CheckFallback --> ReturnKey CheckFallback --> LoadEnglish LoadEnglish --> CheckEnglish CheckEnglish --> ReturnEnglish CheckEnglish --> ReturnKey ``` **Sources:** [src/io/github/samera2022/mouse_macros/Localizer.java L67-L93](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L67-L93) ### Fallback Behavior The localization system implements a three-tier fallback mechanism: | Priority | Source | Condition | | --- | --- | --- | | 1 | Current language file | Key exists in loaded `translations` map | | 2 | `en_us.json` | Key missing and current language is not `en_us` | | 3 | Key itself | Key missing in both current language and English | This ensures that missing translations gracefully degrade to English or display the translation key itself. **Sources:** [src/io/github/samera2022/mouse_macros/Localizer.java L68-L92](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L68-L92) --- ## System Language Detection The `Localizer` class automatically detects the system language at initialization. ### Detection Process 1. Calls `java.util.Locale.getDefault().toString().toLowerCase()` 2. Replaces hyphens with underscores (e.g., `zh-CN` → `zh_cn`) 3. Normalizes common locales: * Languages starting with `zh` → `zh_cn` * Languages starting with `en` → `en_us` 4. Verifies language file exists (in dev mode) 5. Falls back to `en_us` if file not found 6. Loads the determined language file **Sources:** [src/io/github/samera2022/mouse_macros/Localizer.java L20-L32](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L20-L32) --- ## Integration with Configuration The language selection is persisted in `config.cfg` and can be overridden by user settings. ### Configuration Storage The selected language is stored in `ConfigManager.Config.lang` field: | Field | Type | Default | Description | | --- | --- | --- | --- | | `lang` | `String` | `"zh_cn"` | Current language code | | `followSystemSettings` | `boolean` | `true` | Whether to sync with OS language | **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L28-L29](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L28-L29) ### Language Selection Flow ```mermaid flowchart TD Start["Application Start"] CheckFollow["config.followSystemSettings"] UseSystem["Use system locale
java.util.Locale.getDefault()"] UseConfig["Use config.lang value"] Load["Localizer.load(lang)"] Start --> CheckFollow CheckFollow --> UseSystem CheckFollow --> UseConfig UseSystem --> Load UseConfig --> Load ``` **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L28](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L28-L28), [src/io/github/samera2022/mouse_macros/Localizer.java L20-L32](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L20-L32) --- ## Translation Key Conventions While the codebase does not enforce strict naming conventions, examining the code reveals common patterns for translation keys: ### Common Key Patterns | Pattern | Usage Example | Purpose | | --- | --- | --- | | `window.*` | `window.title` | Window titles | | `button.*` | `button.start`, `button.stop` | Button labels | | `menu.*` | `menu.file`, `menu.settings` | Menu items | | `message.*` | `message.success`, `message.error` | Status messages | | `dialog.*` | `dialog.about`, `dialog.hotkey` | Dialog-specific strings | | `label.*` | `label.language`, `label.theme` | Form labels | ### Key Lookup Translation keys are retrieved throughout the UI code using `Localizer.get(String key)`. The method returns the localized string or the key itself if no translation exists. **Sources:** [src/io/github/samera2022/mouse_macros/Localizer.java L67-L93](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L67-L93) --- ## Dev Mode Detection The localization system detects whether it's running in development mode to determine file loading strategy. ### Detection Logic ``` // From Localizer static initializer File devLangFile = new File("lang/zh_cn.json"); isDevMode = devLangFile.exists(); ``` If `lang/zh_cn.json` exists as a filesystem file (not in JAR), the application assumes development mode and loads files from the filesystem rather than JAR resources. **Sources:** [src/io/github/samera2022/mouse_macros/Localizer.java L16-L18](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L16-L18) ### Mode Comparison | Aspect | Development Mode | JAR Mode | | --- | --- | --- | | Detection | `lang/zh_cn.json` file exists | `lang/zh_cn.json` file doesn't exist | | File Loading | `File` + `FileReader` | `getResourceAsStream()` | | Directory Listing | `FileUtil.listFileNames()` | JAR entry enumeration | | File System Access | Direct filesystem | Via ClassLoader resources | **Sources:** [src/io/github/samera2022/mouse_macros/Localizer.java L16-L18](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L16-L18), [src/io/github/samera2022/mouse_macros/Localizer.java L49-L59](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L49-L59), [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L69-L114](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L69-L114) --- ## File Encoding All language files must use UTF-8 encoding without BOM (Byte Order Mark). This is enforced during both loading and discovery operations. ### Encoding Specification * **File Encoding:** UTF-8 * **Reader Encoding:** `StandardCharsets.UTF_8` specified explicitly * **JAR Resource Encoding:** UTF-8 via `InputStreamReader(in, StandardCharsets.UTF_8)` **Sources:** [src/io/github/samera2022/mouse_macros/Localizer.java L57](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L57-L57), [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L88](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L88-L88) --- ## Error Handling The language file system implements graceful error handling to ensure application stability even when language files are missing or malformed. ### Error Scenarios | Scenario | Handling | Result | | --- | --- | --- | | Language file not found | Catch `FileNotFoundException` | Empty `translations` map | | Malformed JSON | Catch `Exception` in `load()` | Empty `translations` map | | Missing translation key | Check for null in `get()` | Fall back to English, then key | | JAR enumeration failure | Catch `Exception` in `getAvailableLangs()` | Return empty array | ### Error Flow ```mermaid flowchart TD LoadAttempt["Localizer.load(lang)"] TryLoad["Try to load
language file"] Success["Parse JSON into Map
Store in translations"] Failure["Exception caught"] EmptyMap["translations = new HashMap()"] Continue["Application continues
with empty translations"] LoadAttempt --> TryLoad TryLoad --> Success TryLoad --> Failure Failure --> EmptyMap EmptyMap --> Continue ``` **Sources:** [src/io/github/samera2022/mouse_macros/Localizer.java L62-L64](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/Localizer.java#L62-L64), [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L115-L117](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L115-L117) --- ## Summary Language files in MouseMacros follow these key characteristics: * **Format:** UTF-8 encoded JSON files with flat key-value structure * **Location:** `lang/` directory in project root or JAR resources * **Naming:** `.json` (e.g., `zh_cn.json`, `en_us.json`) * **Discovery:** Automatic enumeration via `ConfigManager.getAvailableLangs()` * **Loading:** Dual-mode support for development filesystem and JAR resources * **Fallback:** Three-tier fallback (current language → English → key itself) * **Error Handling:** Graceful degradation with empty translation maps The system is designed to work seamlessly in both development and production environments, with robust error handling ensuring the application remains functional even when language files are missing or malformed.