Skip to content

🌎 Traslations

Introduction

To support multilingualism, PBModular includes a built-in translation system. Modules can provide translations for different languages, and the framework will automatically load and make them available based on the bot's global language configuration.

Step 1: Creating Translation Files

  1. Inside your module's directory, create a folder named strings/.
  2. Inside strings/, create YAML files for each language you want to support. The filename must be the ISO 639-1 language code (e.g., en.yaml, ru.yaml, es.yaml).
  3. Structure your translations within the YAML files using nested keys for organization.

Example strings/en.yaml:

yaml
# strings/en.yaml
greeting: "Hello, {user}!"
farewell: Goodbye, {user}!
errors:
  not_found: "Sorry, the item could not be found."
  permission_denied: |
  	You do not have permission to do that.
  	{user}

Step 2: Loading Translations

During module initialization, the BaseModule automatically:

  1. Scans the strings/ directory.
  2. Loads all valid .yaml files found into a dictionary accessible via self.rawS. The keys are the language codes (e.g., self.rawS['en'], self.rawS['ru']).
  3. Determines the language to use based on the bot's global configuration (config.language and config.fallback_language).
    • It first tries config.language.
    • If not found in self.rawS, it tries config.fallback_language.
    • If the fallback is also not found, it logs a warning and uses the first language loaded into self.rawS.
  4. Loads the selected language's translations (potentially merged with the fallback language for missing keys) into self.S. This self.S object is a SafeDict, meaning accessing a non-existent key returns the key itself instead of raising a KeyError.
  5. Stores the code of the currently active language in self.cur_lang.

Merging with Fallback

If both the primary language (config.language) and the fallback language (config.fallback_language) exist in your module's strings/ folder, the framework creates a merged dictionary for self.S. It starts with a copy of the fallback language's strings and then deeply merges the primary language's strings on top. This means any string present in the primary language overrides the fallback, but any string missing in the primary but present in the fallback will still be available.

Step 3: Using Translations in Code

Access translated strings through the self.S dictionary. Use standard Python string formatting (.format() or f-strings) for inserting variables.

python
# Inside a BaseModule or ModuleExtension method

async def greet_user(self, message: Message):
    user_name = message.from_user.first_name
    # Accessing a simple string
    await message.reply(self.S["greeting"].format(user=user_name))

async def show_help(self, message: Message):
    help_title = self.S["help"]["title"] # Accessing nested keys
    command_name = "mycommand"
    usage_text = self.S["help"]["usage"].format(command=command_name)
    await message.reply(f"**{help_title}**\n\n{usage_text}")

async def handle_error(self, message: Message, error_key: str):
    # Using SafeDict property: if key missing, key itself is returned
    error_message = self.S["errors"][error_key]
    await message.reply(f"Error: {error_message}")

# Example accessing raw translations or current lang
def log_languages(self):
    self.logger.info(f"Current language code: {self.cur_lang}")
    self.logger.info(f"Available language codes: {list(self.rawS.keys())}")
    # Access specific language directly (less common)
    # english_farewell = self.rawS.get("en", {}).get("farewell", "Fallback Farewell")

Using this system ensures your module can easily adapt to different languages configured in the bot, providing a better user experience.