Autotransl - guiled/LRE GitHub Wiki

Automatic translation

LRE allows you to automatically translate component values and table data using Let's Role's i18n system by setting lre.autoTransl(true) in your system script.

Problem description

When building multilingual character sheets, you often need to translate text strings throughout your code. The following code shows a common pattern where you need to manually call the translation function _() everywhere:

const raceName = sheet.get('race').value();
const translatedRace = _(raceName);
log('Selected race: ' + translatedRace);

const skillNames = sheet.get('skills').value();
const translatedSkills = {};
Object.keys(skillNames).forEach(function(key) {
    translatedSkills[key] = _(skillNames[key]);
});

// Or when working with table data
Tables.get('items').each(function(item) {
    const translatedName = _(item.name);
    const translatedDescription = _(item.description);
    log(translatedName + ': ' + translatedDescription);
});

This approach requires you to:

  • Remember to call _() on every string that needs translation
  • Manually translate nested objects and arrays
  • Handle translation for table data separately
  • Write repetitive translation code throughout your script

Some systems have dozens or even hundreds of _() calls scattered throughout the code, making it harder to read and maintain. Moreover, you can lose time coding and debugging because you forgot to add _() in some places.

LRE solution = lre.autoTransl(true)

LRE offers a flag that allows you to automatically translate all non-numeric string values from components, tables, objects, and arrays. This works recursively, so nested data structures are automatically translated as well. You don't need to use _() manually anymore.

lre.autoTransl is set to false by default and can be changed anywhere in your system code. Please note that any code run before lre.autoTransl(true) won't have any automatic translations.

const init = lre(function (sheet) {
    lre.autoTransl(true);
    
    // Component values are automatically translated
    const raceName = sheet.get('race').value();
    log('Selected race: ' + raceName); // Already translated!
    
    // Objects are automatically translated recursively
    const skills = sheet.get('skills').value();
    // All string values in the skills object are now translated
    
    // Arrays are automatically translated recursively
    const itemNames = sheet.get('itemList').value();
    // All string values in the array are now translated
});

What gets translated?

Only non-numeric strings are translated. This means:

  • Regular text strings are translated:

    lre.autoTransl(true);
    const text = lre.value("Strength"); // Returns: translated version (e.g., "Force" in French)
    
  • String values in objects are translated:

    lre.autoTransl(true);
    const data = {
        name: "Sword",
        type: "Weapon",
        damage: "1d6"
    };
    const translated = lre.value(data);
    // Result: { name: "Épée", type: "Arme", damage: "1d6" }
    // Note: "1d6" is not translated because it's numeric
    
  • String values in arrays are translated:

    lre.autoTransl(true);
    const items = ["Sword", "Shield", "Potion"];
    const translated = lre.value(items);
    // Result: ["Épée", "Bouclier", "Potion"]
    
  • Numeric strings are NOT translated (they are converted to numbers if autoNum is enabled):

    lre.autoTransl(true);
    const level = lre.value("5"); // Returns: 5 (number, not translated)
    const damage = lre.value("1d6"); // Returns: "1d6" (contains numbers, not translated)
    
  • Empty strings are NOT translated:

    lre.autoTransl(true);
    const empty = lre.value(""); // Returns: "" (unchanged)
    
  • Numbers, objects, and arrays themselves are NOT translated (only their string contents):

    lre.autoTransl(true);
    const num = lre.value(42); // Returns: 42 (unchanged)
    const obj = lre.value({}); // Returns: {} (unchanged, but string values inside would be)
    const arr = lre.value([1, 2, 3]); // Returns: [1, 2, 3] (unchanged, but string values inside would be)
    

Automatic translation with components

When lre.autoTransl(true) is enabled, component values are automatically translated when you call component.value():

lre.autoTransl(true);

// Component value is automatically translated
const race = sheet.get('race').value();
log(race); // Output: translated race name (e.g., "Elf" becomes "Elfe" in French)

// Works with all component types that return strings
const characterName = sheet.get('characterName').value(); // Translated if it's a string
const description = sheet.get('description').value(); // Translated if it's a string

Automatic translation with tables

The flag allows automatic translation of table data as well. When you access table data, all non-numeric string values are automatically translated:

lre.autoTransl(true);

// Table data is automatically translated
Tables.get('races').each(function(race) {
    log(race.name); // Already translated!
    log(race.description); // Already translated!
    log(race.bonus); // Not translated if it's numeric (e.g., "+2")
});

// Using DataProvider methods
const races = Tables.get('races');
const translatedNames = races.select('name').providedValue();
// All race names in the result are automatically translated

Automatic translation with objects and arrays

LRE automatically translates string values recursively in objects and arrays:

lre.autoTransl(true);

// Nested objects are translated recursively
const characterData = {
    name: "Gandalf",
    race: "Wizard",
    stats: {
        strength: "12",
        class: "Mage"
    }
};

const translated = lre.value(characterData);
// Result:
// {
//     name: "Gandalf" (translated if translation exists),
//     race: "Magicien" (translated),
//     stats: {
//         strength: 12 (converted to number if autoNum is enabled),
//         class: "Mage" (translated)
//     }
// }

// Arrays are translated recursively
const skills = ["Acrobatics", "Athletics", "Stealth"];
const translatedSkills = lre.value(skills);
// Result: ["Acrobatie", "Athlétisme", "Furtivité"]

Combining autoNum and autoTransl

You can use both lre.autoNum(true) and lre.autoTransl(true) together. In this case, numeric strings are converted to numbers first, and non-numeric strings are translated:

lre.autoNum(true);
lre.autoTransl(true);

const data = {
    level: "5",           // Converted to number: 5
    name: "Character",    // Translated: "Personnage"
    damage: "1d6",       // Not numeric, not translated: "1d6"
    type: "Warrior"      // Translated: "Guerrier"
};

const result = lre.value(data);
// Result: { level: 5, name: "Personnage", damage: "1d6", type: "Guerrier" }

Translation priority

When both autoNum and autoTransl are enabled, the priority is:

  1. First: Check if the string is numeric → convert to number (if autoNum is enabled)
  2. Then: If not numeric → translate the string (if autoTransl is enabled)

This means numeric strings are never translated, and non-numeric strings are never converted to numbers.

Missing translations

If a translation doesn't exist in your i18n system, the original string is returned unchanged. This allows you to gradually add translations without breaking your code:

lre.autoTransl(true);

// If "Sword" has a translation → returns translated version
// If "Sword" has no translation → returns "Sword" (unchanged)
const weapon = lre.value("Sword");

LRE tracks untranslated strings internally, which can be useful for identifying missing translations during development.

log(lre.i18n.getUntranslated())

Complete example

Here's a complete example showing automatic translation in action:

const init = lre(function (sheet) {
    // Enable automatic translation
    lre.autoTransl(true);
    
    // Component values are automatically translated
    sheet.get('race').on('update', function(raceComponent) {
        const race = raceComponent.value(); // Already translated!
        log('Selected race: ' + race);
    });
    
    // Table data is automatically translated
    const items = Tables.get('items');
    items.each(function(item) {
        // All string values are already translated
        log(item.name + ': ' + item.description);
    });
    
    // Complex nested data is automatically translated
    const characterData = sheet.get('characterData').value();
    // All string values in the object (and nested objects) are translated
    
    // Populate a choice with translated values
    const races = Tables.get('races');
    sheet.get('raceChoice').setChoices(races.select('name'));
    // Race names in the choice are automatically translated
});

When to use autoTransl

Use lre.autoTransl(true) when:

  • ✅ You want to support multiple languages in your character sheet
  • ✅ You have many strings that need translation
  • ✅ You want to avoid manually calling _() everywhere
  • ✅ You want automatic translation of table data
  • ✅ You want translation to work recursively in objects and arrays

Don't use lre.autoTransl(true) when:

  • ❌ Your character sheet is single-language only
  • ❌ You need fine-grained control over which strings are translated
  • ❌ You want to translate only specific strings manually

Performance note

Automatic translation adds a small overhead to value retrieval, but it's generally negligible. The translation lookup is fast, and the convenience of automatic translation usually outweighs the minimal performance cost.