Skip to content

Language Files and Translation Keys

Samera2022 edited this page Jan 30, 2026 · 1 revision

Language Files

Relevant source files

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. For overall configuration system architecture, see Configuration System.


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

{
  "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<String, String> structure stored in the Localizer class.

Sources: src/io/github/samera2022/mouse_macros/Localizer.java L52, src/io/github/samera2022/mouse_macros/Localizer.java 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: <language_code>.json

Language File Name Example
Chinese (Simplified) zh_cn.json Default language in config
English (US) en_us.json Fallback language
Other languages <code>.json Format: <lang>_<region>.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, src/io/github/samera2022/mouse_macros/Localizer.java L23-L24, src/io/github/samera2022/mouse_macros/manager/ConfigManager.java 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

flowchart TD

Start["ConfigManager.getAvailableLangs()"]
CheckDevMode["Localizer.isDevMode()"]
DevPath["FileUtil.listFileNames('lang')"]
DevFilter["Filter files ending with .json<br>Strip .json extension"]
JarCheck["dirURL.getProtocol()"]
JarPath["Read JAR file entries<br>Filter 'lang/*.json'"]
FilePath["Read filesystem directory<br>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
Loading

Sources: 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, 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

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


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

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<String, String>
    Localizer->>JAR Resources: getResourceAsStream("lang/zh_cn.json")
    JAR Resources-->>Localizer: InputStream
    Localizer->>Gson Parser: fromJson(InputStreamReader)
    Gson Parser-->>Localizer: Map<String, String>
  end
  Localizer->>Localizer: translations = parsedMap
  Localizer->>Localizer: currentLang = "zh_cn"
  Localizer-->>Application Code: Load complete
Loading

Sources: src/io/github/samera2022/mouse_macros/Localizer.java L47-L65

Development Mode Loading

In development mode:

  1. Constructs File object pointing to lang/<lang>.json
  2. Creates FileReader for the file
  3. Uses Gson to parse JSON into Map<String, String>
  4. Stores result in static translations field

Sources: src/io/github/samera2022/mouse_macros/Localizer.java L49-L52

JAR Mode Loading

In JAR mode:

  1. Constructs resource path: lang/<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<String, String>
  5. Stores result in static translations field

Sources: 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

flowchart TD

Start["Localizer.get(key)"]
CheckCurrent["Key exists in<br>current language?"]
ReturnCurrent["Return translation from<br>current language"]
CheckFallback["Current language<br>is 'en_us'?"]
LoadEnglish["Load en_us.json"]
CheckEnglish["Key exists in<br>en_us.json?"]
ReturnEnglish["Return translation from<br>en_us.json"]
ReturnKey["Return key as-is<br>(untranslated)"]

Start --> CheckCurrent
CheckCurrent --> ReturnCurrent
CheckCurrent --> CheckFallback
CheckFallback --> ReturnKey
CheckFallback --> LoadEnglish
LoadEnglish --> CheckEnglish
CheckEnglish --> ReturnEnglish
CheckEnglish --> ReturnKey
Loading

Sources: 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


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-CNzh_cn)
  3. Normalizes common locales: * Languages starting with zhzh_cn * Languages starting with enen_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


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

Language Selection Flow

flowchart TD

Start["Application Start"]
CheckFollow["config.followSystemSettings"]
UseSystem["Use system locale<br>java.util.Locale.getDefault()"]
UseConfig["Use config.lang value"]
Load["Localizer.load(lang)"]

Start --> CheckFollow
CheckFollow --> UseSystem
CheckFollow --> UseConfig
UseSystem --> Load
UseConfig --> Load
Loading

Sources: src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L28, 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


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

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, src/io/github/samera2022/mouse_macros/Localizer.java L49-L59, 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, src/io/github/samera2022/mouse_macros/manager/ConfigManager.java 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

flowchart TD

LoadAttempt["Localizer.load(lang)"]
TryLoad["Try to load<br>language file"]
Success["Parse JSON into Map<br>Store in translations"]
Failure["Exception caught"]
EmptyMap["translations = new HashMap()"]
Continue["Application continues<br>with empty translations"]

LoadAttempt --> TryLoad
TryLoad --> Success
TryLoad --> Failure
Failure --> EmptyMap
EmptyMap --> Continue
Loading

Sources: src/io/github/samera2022/mouse_macros/Localizer.java L62-L64, 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: <language_code>.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.

Clone this wiki locally