Translator

  • community
  • integration
  • by limon
  • Takaro v0.0.29
  • all
View export JSON

Enables real-time translation of in-game chat messages, facilitating cross-lingual communication among players.

Key Functionality

  • Two-Way Translation: Translates chat messages between players speaking different languages.
  • Automatic Translation: Can automatically translate messages based on players' configured language preferences.
  • On-Demand Translation: Players can translate specific messages or recent messages from other players using commands.
  • Configurable Languages: Server administrators can define the list of supported languages.
  • Google Translate Integration: Leverages the Google Cloud Translation API for accurate and comprehensive language support.
  • Permission Control: Granular permissions allow administrators to control who can use translation features.

How to Use

  1. Configuration:
    • googleApiKey: (Required) Enter your Google Cloud API key with access to the Cloud Translation API.
    • maxMessageLength: Set the maximum character length for messages to be translated (to manage API usage/costs). Default: 500.
    • defaultLanguage: Set the default language code (ISO 639-1) for translations when a player hasn't specified their preference. Default: en.
    • supportedLanguages: Define an array of ISO 639-1 language codes (e.g., ["en", "es", "fr"]) for the languages supported by the module.
    • commandPrefixes: (Optional) An array of prefixes that are used to identify commands. Messages that start with these prefixes will not be translated. Default: ["/"]
  2. Permissions:
    • TRANSLATE_PERMISSION: Grants players access to basic translation commands (/translate, /setlanguage, /toggletranslation, /translateme).
    • TRANSLATE_ADMIN: Allows administrators to set language preferences for other players (/setplayerlanguage).
    • AUTO_TRANSLATE_PERMISSION: Allows players to receive automatically translated messages.
  3. In-Game Usage:
    • /translate <language> "text": Translates the provided text into the specified language and sends it to the global chat.
    • /setlanguage <code>: Sets the player's preferred language for receiving translations (e.g., /setlanguage es).
    • /toggletranslation on/off: Enables or disables automatic translation for the player.
    • /translateme <player> [count]: Translates the last count messages from the specified player and sends them to the user via DM. If count is omitted, translates the last message.
    • /setplayerlanguage <player> <language>: (Admin only) Sets the preferred language for another player.

Important Considerations

  • Google Cloud API Key: A valid Google Cloud API key with the Cloud Translation API enabled is essential for this module to function.
  • Language Codes: Use correct ISO 639-1 two-letter language codes (e.g., 'en', 'es', 'fr'). Refer to the Google Cloud Translation API documentation for a full list.
  • Permissions Management: Carefully manage the module's permissions to control access to translation features.
  • Message Length: Be mindful of the maxMessageLength setting to avoid excessive API usage and potential costs.
  • Error Handling: The module includes error handling, but it's important to monitor server logs for any translation-related issues.

Configuration 5

Settings you fill in when installing the module on a server.

SettingTypeDefaultDescription
googleApiKey required googleApiKey string Your Google Cloud API key with access to the Translation API
maxMessageLength maxMessageLength number 500 Maximum length of messages that will be translated (to control API costs)
enabledByDefault enabledByDefault boolean false If true, all new players will automatically receive translated messages in English
defaultLanguage defaultLanguage string "en" The default language code to use if enabledByDefault is true
supportedLanguages supportedLanguages array ["en","es","fr","de","it","pt","ru","zh","ja","ko","ar","hi"] List of supported language codes for translation
Raw config schema
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": [
    "googleApiKey"
  ],
  "additionalProperties": false,
  "properties": {
    "googleApiKey": {
      "title": "googleApiKey",
      "description": "Your Google Cloud API key with access to the Translation API",
      "type": "string",
      "minLength": 1
    },
    "maxMessageLength": {
      "title": "maxMessageLength",
      "description": "Maximum length of messages that will be translated (to control API costs)",
      "default": 500,
      "type": "number",
      "minimum": 1
    },
    "enabledByDefault": {
      "title": "enabledByDefault",
      "description": "If true, all new players will automatically receive translated messages in English",
      "default": false,
      "type": "boolean"
    },
    "defaultLanguage": {
      "title": "defaultLanguage",
      "description": "The default language code to use if enabledByDefault is true",
      "default": "en",
      "type": "string"
    },
    "supportedLanguages": {
      "title": "supportedLanguages",
      "description": "List of supported language codes for translation",
      "default": [
        "en",
        "es",
        "fr",
        "de",
        "it",
        "pt",
        "ru",
        "zh",
        "ja",
        "ko",
        "ar",
        "hi"
      ],
      "type": "array",
      "items": {
        "type": "string"
      }
    }
  }
}
Raw UI schema
{}

Commands 6

Chat commands players trigger in game.

  • setplayerlanguage

    No help text available

    ArgumentTypeDefaultHelp
    language string Language code to set (e.g., 'en' for English)
    targetPlayer string Name of the player to set language for
    Command source
    import { takaro, data, TakaroUserError, checkPermission } from '@takaro/helpers';
    
    const LANGUAGE_VARIABLE_KEY = 'user_language';
    
    async function main() {
        const { player, pog, gameServerId, module, arguments: args } = data;
    
        // Check if player has admin permissions to set other players' languages
        if (!checkPermission(pog, 'TRANSLATE_ADMIN')) {
            throw new TakaroUserError('You do not have permission to set languages for other players.');
        }
    
        // Validate target player parameter
        if (!args.targetPlayer) {
            throw new TakaroUserError('Please specify a player name. Usage: /setplayerlanguage <player> <language>');
        }
    
        // Validate language parameter
        if (!args.language) {
            throw new TakaroUserError('Please specify a language code. Usage: /setplayerlanguage <player> <language>');
        }
    
        // Find the target player
        let targetPlayer;
        try {
            const targetPlayerSearch = await takaro.player.playerControllerSearch({
                search: { name: [args.targetPlayer] }
            });
    
            if (!targetPlayerSearch.data.data?.length) {
                throw new TakaroUserError(`Player "${args.targetPlayer}" not found.`);
            }
    
            targetPlayer = targetPlayerSearch.data.data[0];
        } catch (error) {
            throw new TakaroUserError(`Failed to find player: ${error.message}`);
        }
    
        // Validate language code against supported languages in config
        const supportedLanguages = module.userConfig.supportedLanguages || [];
        if (supportedLanguages.length > 0 && !supportedLanguages.includes(args.language)) {
            throw new TakaroUserError(
                `Invalid language code. Valid options are: ${supportedLanguages.join(', ')}`
            );
        }
    
        // Convert to lowercase for consistency
        const language = args.language.toLowerCase();
    
        try {
            // Check if target player already has a language set
            const existingLanguageVar = await takaro.variable.variableControllerSearch({
                filters: {
                    key: [LANGUAGE_VARIABLE_KEY],
                    gameServerId: [gameServerId],
                    playerId: [targetPlayer.id],
                    moduleId: [module.moduleId]
                }
            });
    
            // If language variable exists, update it
            if (existingLanguageVar.data.data.length > 0) {
                await takaro.variable.variableControllerUpdate(existingLanguageVar.data.data[0].id, {
                    value: language
                });
            }
            // Otherwise create a new variable
            else {
                await takaro.variable.variableControllerCreate({
                    key: LANGUAGE_VARIABLE_KEY,
                    value: language,
                    gameServerId: gameServerId,
                    playerId: targetPlayer.id,
                    moduleId: module.moduleId
                });
            }
    
            await player.pm(`Language for ${targetPlayer.name} has been set to: ${language}`);
    
            // Also notify the target player if they're online
            try {
                const pogList = await takaro.playerOnGameserver.playerOnGameServerControllerSearch({
                    filters: {
                        gameServerId: [gameServerId],
                        playerId: [targetPlayer.id],
                        online: [true]
                    }
                });
    
                if (pogList.data.data.length > 0) {
                    // The player is online, we can send them a notification
                    await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
                        message: `An admin has set your translation language to: ${language}`,
                        opts: {
                            recipient: {
                                gameId: pogList.data.data[0].gameId
                            }
                        }
                    });
                }
            } catch (error) {
                console.error(`Error notifying target player: ${error.message}`);
                // We don't want to fail the whole command if just the notification fails
            }
    
        } catch (error) {
            console.error(`Error setting player language: ${error.message}`);
            throw new TakaroUserError(`Failed to set language: ${error.message}`);
        }
    }
    
    await main();
  • translate

    No help text available

    ArgumentTypeDefaultHelp
    text string The text that you want to translate
    language string what language you want to translate to?
    Command source
    import { takaro, data, TakaroUserError } from '@takaro/helpers';
    
    async function main() {
        const { player, gameServerId, module: mod, arguments: args } = data;
    
        // Get the text to translate
        const textToTranslate = args.text;
    
        if (!textToTranslate || textToTranslate.trim() === "") {
            throw new TakaroUserError("No text to translate was provided.");
        }
    
        // Validate language code against supported languages in config
        const validLanguages = mod.userConfig.supportedLanguages;
        if (!validLanguages.includes(args.language)) {
            throw new TakaroUserError(
                `Invalid language code. Valid options are: ${validLanguages.join(', ')}`
            );
        }
    
        // First verify API key is configured
        if (!mod.userConfig.googleApiKey) {
            throw new TakaroUserError('Translation service is not properly configured. Please contact an administrator.');
        }
    
        try {
            // Translate the text
            const apiKey = mod.userConfig.googleApiKey;
            const translation = await translateText(textToTranslate, args.language, apiKey);
    
            // Get language name for better UX
            const languageNames = {
                'en': 'English', 'es': 'Spanish', 'fr': 'French', 'de': 'German',
                'it': 'Italian', 'pt': 'Portuguese', 'ru': 'Russian', 'zh': 'Chinese',
                'ja': 'Japanese', 'ko': 'Korean', 'ar': 'Arabic', 'hi': 'Hindi',
                'tr': 'Turkish', 'nl': 'Dutch', 'pl': 'Polish', 'vi': 'Vietnamese',
                'th': 'Thai', 'id': 'Indonesian'
            };
            const languageName = languageNames[args.language] || args.language;
    
            // Send translation to the game server global chat
            await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
                message: `[${player.name} -> ${languageName}]: ${translation}`
            });
    
        } catch (error) {
            console.error(`Translation error: ${error.message}`);
            throw new TakaroUserError(`Translation failed: ${error.message}`);
        }
    }
    
    // Translation function using Takaro's HTTP methods
    async function translateText(text, targetLanguage, apiKey) {
        try {
            // Use axios (available in the Takaro environment)
            const response = await takaro.axios.post(
                `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`,
                {
                    q: text,
                    target: targetLanguage
                },
                { headers: { 'Content-Type': 'application/json' } }
            );
    
            const result = response.data;
    
            if (result.error) {
                throw new Error(result.error.message || "Unknown translation error");
            }
    
            if (!result.data || !result.data.translations || !result.data.translations[0]) {
                throw new Error("Invalid response format from translation API");
            }
    
            return result.data.translations[0].translatedText;
        } catch (error) {
            console.error(`Translation API error: ${error.message}`);
            throw new Error(`API error: ${error.message}`);
        }
    }
    
    await main();
  • toggletranslation

    Enable or disable automatic translation of messages. Use 'toggletranslation on' to receive translated messages, 'toggletranslation off' to disable.

    ArgumentTypeDefaultHelp
    status string off on/off to enable/disable translations
    Command source
    import { takaro, data, TakaroUserError, checkPermission } from '@takaro/helpers';
    
    const TRANSLATION_ENABLED_KEY = 'translation_enabled';
    
    async function main() {
        const { player, pog, gameServerId, module, arguments: args } = data;
    
        // Check if player has permission to use this command
        if (!checkPermission(pog, 'TRANSLATE_PERMISSION')) {
            throw new TakaroUserError('You do not have permission to use translation features.');
        }
    
        // Get the current status if no argument is provided
        if (!args.status || (args.status !== 'on' && args.status !== 'off')) {
            const currentStatusVar = await takaro.variable.variableControllerSearch({
                filters: {
                    key: [TRANSLATION_ENABLED_KEY],
                    gameServerId: [gameServerId],
                    playerId: [player.id],
                    moduleId: [module.moduleId]
                }
            });
    
            // Check if we have a stored preference
            if (currentStatusVar.data.data.length > 0) {
                const isEnabled = currentStatusVar.data.data[0].value === 'true';
                await player.pm(`Your translation status is currently: ${isEnabled ? 'ENABLED' : 'DISABLED'}`);
                await player.pm('Use "/toggletranslation on" or "/toggletranslation off" to change this setting.');
            } else {
                // If no preference is set, check the module default setting
                const defaultEnabled = module.userConfig.enabledByDefault ?? false;
                await player.pm(`Your translation status is currently: ${defaultEnabled ? 'ENABLED' : 'DISABLED'} (using default setting)`);
                await player.pm('Use "/toggletranslation on" or "/toggletranslation off" to change this setting.');
            }
            return;
        }
    
        // Convert argument to boolean
        const newStatus = args.status === 'on';
    
        // Check if user already has a preference set
        const existingStatusVar = await takaro.variable.variableControllerSearch({
            filters: {
                key: [TRANSLATION_ENABLED_KEY],
                gameServerId: [gameServerId],
                playerId: [player.id],
                moduleId: [module.moduleId]
            }
        });
    
        // If preference exists, update it
        if (existingStatusVar.data.data.length > 0) {
            await takaro.variable.variableControllerUpdate(existingStatusVar.data.data[0].id, {
                value: newStatus.toString()
            });
        }
        // Otherwise create a new variable
        else {
            await takaro.variable.variableControllerCreate({
                key: TRANSLATION_ENABLED_KEY,
                value: newStatus.toString(),
                gameServerId: gameServerId,
                playerId: player.id,
                moduleId: module.moduleId
            });
        }
    
        await player.pm(`Translation has been ${newStatus ? 'ENABLED' : 'DISABLED'} for you.`);
    
        // If translations were enabled but no language is set, prompt the user
        if (newStatus) {
            const languageVar = await takaro.variable.variableControllerSearch({
                filters: {
                    key: ['user_language'],
                    gameServerId: [gameServerId],
                    playerId: [player.id],
                    moduleId: [module.moduleId]
                }
            });
    
            if (languageVar.data.data.length === 0) {
                const defaultLanguage = module.userConfig.defaultLanguage || 'en';
                await player.pm(`No language preference is set. Messages will be translated to ${defaultLanguage} by default.`);
                await player.pm(`Use "/setlanguage <code>" to set your preferred language.`);
                await player.pm(`Example: /setlanguage es (for Spanish)`);
    
                // List available languages
                if (module.userConfig.supportedLanguages && module.userConfig.supportedLanguages.length > 0) {
                    await player.pm(`Supported languages: ${module.userConfig.supportedLanguages.join(', ')}`);
                }
            }
        }
    }
    
    await main();
  • translateme

    Translate recent messages from a specific player into your preferred language. Specify a number to translate multiple messages.

    ArgumentTypeDefaultHelp
    targetPlayerName string player name
    count string 1 Number of most recent messages to translate (default: 1)
    Command source
    import { takaro, data, TakaroUserError, checkPermission } from '@takaro/helpers';
    
    const LANGUAGE_VARIABLE_KEY = 'user_language';
    const TRANSLATE_PERMISSION = 'TRANSLATE_PERMISSION';
    
    async function translateText(text, targetLanguage, apiKey) {
        if (!text || !text.trim()) return '';
    
        try {
            const response = await takaro.axios.post(
                `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`,
                { q: text, target: targetLanguage },
                { headers: { 'Content-Type': 'application/json' } }
            );
    
            const result = response.data;
    
            if (result.error) {
                throw new Error(result.error.message || "Unknown translation error");
            }
    
            if (!result.data?.translations?.[0]) {
                throw new Error("Invalid response format from translation API");
            }
    
            return result.data.translations[0].translatedText;
        } catch (error) {
            console.error(`Translation API error:`, error);
            return '[Translation error]';
        }
    }
    
    async function main() {
        try {
            const { player, arguments: args, gameServerId, module: mod, pog } = data;
    
            // Check permission - ensure player has TRANSLATE_PERMISSION
            if (!checkPermission(pog, TRANSLATE_PERMISSION)) {
                throw new TakaroUserError("You don't have permission to use the translation feature.");
            }
    
            // Validate configuration
            if (!mod.userConfig.googleApiKey) {
                throw new TakaroUserError('Translation feature is not configured. Google API key is missing.');
            }
    
            // Find target player
            if (!args.targetPlayerName) {
                throw new TakaroUserError('Please specify a player to translate messages from.');
            }
    
            const targetPlayer = await getTargetPlayer(args.targetPlayerName);
    
            // Determine target language
            const targetLanguage = await determineTargetLanguage(args.targetLang, player.id, gameServerId, mod);
    
            // Get message count from args or default to 1 (just the last message)
            const messageCount = args.count ? Math.min(Math.max(parseInt(args.count, 10), 1), 20) : 1;
    
            // Fetch and translate messages
            const messages = await fetchRecentMessages(targetPlayer.id, gameServerId, messageCount);
    
            const consolidatedMessage = await buildTranslatedOutput(messages, targetPlayer.name, targetLanguage, mod.userConfig.googleApiKey);
    
            await player.pm(consolidatedMessage);
    
        } catch (error) {
            console.error('Error in translation module:', error);
            throw error instanceof TakaroUserError
                ? error
                : new TakaroUserError(`An error occurred while translating messages: ${error.message}`);
        }
    }
    
    async function getTargetPlayer(targetPlayerName) {
        if (targetPlayerName.id) return targetPlayerName;
    
        const playerSearch = await takaro.player.playerControllerSearch({
            search: { name: [targetPlayerName] }
        });
    
        if (!playerSearch.data.data?.length) {
            throw new TakaroUserError(`Player "${targetPlayerName}" not found.`);
        }
    
        return playerSearch.data.data[0];
    }
    
    async function determineTargetLanguage(requestedLanguage, playerId, gameServerId, mod) {
        // First priority: explicitly requested language
        if (requestedLanguage) {
            validateLanguage(requestedLanguage, mod);
            return requestedLanguage;
        }
    
        // Second priority: user's saved preference
        const userLanguageVar = await takaro.variable.variableControllerSearch({
            filters: {
                key: [LANGUAGE_VARIABLE_KEY],
                gameServerId: [gameServerId],
                playerId: [playerId],
                moduleId: [mod.moduleId]
            }
        });
    
        if (userLanguageVar.data.data?.length) {
            const savedLanguage = userLanguageVar.data.data[0].value;
            validateLanguage(savedLanguage, mod);
            return savedLanguage;
        }
    
        // Last priority: module default or English
        const defaultLanguage = mod.userConfig.defaultLanguage || 'en';
        validateLanguage(defaultLanguage, mod);
        return defaultLanguage;
    }
    
    function validateLanguage(language, mod) {
        if (mod.userConfig.supportedLanguages &&
            !mod.userConfig.supportedLanguages.includes(language)) {
            throw new TakaroUserError(
                `Unsupported target language: ${language}. ` +
                `Available languages: ${mod.userConfig.supportedLanguages.join(', ')}`
            );
        }
    }
    
    async function fetchRecentMessages(playerId, gameServerId, messageCount) {
        const events = await takaro.event.eventControllerSearch({
            limit: 100,
            sortBy: 'createdAt',
            sortDirection: 'desc',
            filters: {
                eventName: ['chat-message'],
                gameserverId: [gameServerId],
                playerId: [playerId]
            }
        });
    
        if (!events.data.data?.length) {
            throw new TakaroUserError(`No chat messages found for this player.`);
        }
    
        // Filter out command messages (messages starting with '/' or '!')
        const filteredMessages = events.data.data
            .filter(event => {
                const message = event.meta.msg;
                return message && typeof message === 'string' &&
                    !message.startsWith('/') &&
                    !message.startsWith('!');
            })
            .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
            .slice(0, messageCount)
            .map(event => ({
                content: event.meta.msg,
                timestamp: event.createdAt
            }));
    
        if (filteredMessages.length === 0) {
            throw new TakaroUserError(`No non-command messages found for this player.`);
        }
    
        return filteredMessages;
    }
    
    async function buildTranslatedOutput(messages, playerName, targetLanguage, apiKey) {
        let output = `Messages from ${playerName} (${targetLanguage}):\n\n`;
    
        // Reverse the messages array to start from the oldest
        const reversedMessages = [...messages].reverse();
    
        for (let i = 0; i < reversedMessages.length; i++) {
            const message = reversedMessages[i];
            const translatedText = await translateText(message.content, targetLanguage, apiKey);
    
            // Just show the translation, not the original message
            output += `${i + 1}. ${translatedText}\n\n`;
        }
    
        return output;
    }
    
    await main();
  • gettranslation

    No help text available

    ArgumentTypeDefaultHelp
    targetPlayerName string player name
    Command source
    import { takaro, data, TakaroUserError } from '@takaro/helpers';
    
    const LANGUAGE_VARIABLE_KEY = 'user_language';
    
    async function main() {
        const { player, gameServerId, module: mod, arguments: args } = data;
    
        // Check if a player name was provided
        if (!args.targetPlayer || args.targetPlayer.trim() === "") {
            throw new TakaroUserError("Please specify a player name. Usage: /gettranslation [player name]");
        }
    
        // First verify API key is configured
        if (!mod.userConfig.googleApiKey) {
            throw new TakaroUserError('Translation service is not properly configured. Please contact an administrator.');
        }
    
        // Get the target player's information
        const targetPlayerName = args.targetPlayer.trim();
    
        try {
            // Get the requesting player's language preference
            const langVarResponse = await takaro.variable.variableControllerSearch({
                filters: {
                    key: [LANGUAGE_VARIABLE_KEY],
                    gameServerId: [gameServerId],
                    playerId: [player.id],
                    moduleId: [mod.moduleId]
                }
            });
    
            // Check if the requesting player has set a language preference
            if (langVarResponse.data.data.length === 0) {
                await player.pm(`You haven't set a language preference yet. Use /setlanguage to set your preferred language.`);
                return;
            }
    
            const targetLanguage = langVarResponse.data.data[0].value;
    
            // Find the target player by searching for players on the game server
            const players = (await takaro.gameserver.gameServerControllerGetPlayers(gameServerId)).data.data;
            const targetPlayer = players.find(p => p.name.toLowerCase().includes(targetPlayerName.toLowerCase()));
    
            if (!targetPlayer) {
                throw new TakaroUserError(`Player "${targetPlayerName}" not found. They might be offline or the name is incorrect.`);
            }
    
            // Inform the requesting player that we're fetching messages
            await player.pm(`Fetching and translating the last 5 messages from ${targetPlayer.name}...`);
    
            // Get recent chat messages (we would fetch more than 5 since not all might be from target player)
            // Note: In a real implementation, you'd want to check if your game server's API allows fetching historic messages
            // This is a simplified example assuming chat messages are accessible via some API
            const messagesResponse = await takaro.chatMessage.chatMessageControllerSearch({
                filters: {
                    gameServerId: [gameServerId]
                },
                limit: 50 // Fetch enough to hopefully get 5 from target player
            });
    
            const allMessages = messagesResponse.data.data;
    
            // Filter messages from the target player and get the most recent 5
            const targetPlayerMessages = allMessages
                .filter(msg => {
                    // This condition depends on how your message structure looks
                    // Adjust based on your actual data structure
                    return msg.playerSteamId === targetPlayer.steamId ||
                        (msg.player && msg.player.steamId === targetPlayer.steamId);
                })
                .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)) // Sort by date descending
                .slice(0, 5); // Get the 5 most recent
    
            if (targetPlayerMessages.length === 0) {
                await player.pm(`No recent messages found from ${targetPlayer.name}.`);
                return;
            }
    
            // Translate and send each message
            await player.pm(`Last ${targetPlayerMessages.length} messages from ${targetPlayer.name}:`);
    
            for (let i = 0; i < targetPlayerMessages.length; i++) {
                const msg = targetPlayerMessages[i];
                const messageContent = msg.message;
                const timestamp = new Date(msg.createdAt).toLocaleString();
    
                try {
                    // Detect the source language
                    const sourceLanguage = await detectLanguage(messageContent, mod.userConfig.googleApiKey);
    
                    // Skip translation if the message is already in the target language
                    if (sourceLanguage === targetLanguage) {
                        await player.pm(`[${timestamp}] ${targetPlayer.name}: ${messageContent} (Already in ${targetLanguage})`);
                    } else {
                        // Translate the message
                        const translation = await translateText(messageContent, targetLanguage, mod.userConfig.googleApiKey);
                        await player.pm(`[${timestamp}] ${targetPlayer.name}: ${translation} (Translated from ${sourceLanguage})`);
                    }
                } catch (error) {
                    console.error(`Translation error for message: ${error.message}`);
                    await player.pm(`[${timestamp}] ${targetPlayer.name}: ${messageContent} (Translation failed)`);
                }
            }
    
        } catch (error) {
            console.error(`Get translation command error: ${error.message}`);
            throw new TakaroUserError(`Failed to get translations: ${error.message}`);
        }
    }
    
    // Function to detect the language of text
    async function detectLanguage(text, apiKey) {
        try {
            const response = await takaro.axios.post(
                `https://translation.googleapis.com/language/translate/v2/detect?key=${apiKey}`,
                { q: text },
                { headers: { 'Content-Type': 'application/json' } }
            );
    
            if (response.data.error) {
                throw new Error(response.data.error.message || "Unknown detection error");
            }
    
            if (!response.data.data || !response.data.data.detections ||
                !response.data.data.detections[0] || !response.data.data.detections[0][0]) {
                throw new Error("Invalid response format from language detection API");
            }
    
            return response.data.data.detections[0][0].language;
        } catch (error) {
            console.error(`Language detection API error: ${error.message}`);
            throw new Error(`API error: ${error.message}`);
        }
    }
    
    // Translation function using Takaro's HTTP methods
    async function translateText(text, targetLanguage, apiKey) {
        try {
            const response = await takaro.axios.post(
                `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`,
                {
                    q: text,
                    target: targetLanguage
                },
                { headers: { 'Content-Type': 'application/json' } }
            );
    
            const result = response.data;
    
            if (result.error) {
                throw new Error(result.error.message || "Unknown translation error");
            }
    
            if (!result.data || !result.data.translations || !result.data.translations[0]) {
                throw new Error("Invalid response format from translation API");
            }
    
            return result.data.translations[0].translatedText;
        } catch (error) {
            console.error(`Translation API error: ${error.message}`);
            throw new Error(`API error: ${error.message}`);
        }
    }
    
    await main();
  • setlanguage

    No help text available

    ArgumentTypeDefaultHelp
    language string Set your language
    Command source
    import { takaro, data, TakaroUserError } from '@takaro/helpers';
    
    const LANGUAGE_VARIABLE_KEY = 'user_language';
    
    async function main() {
        const { player, pog, gameServerId, module, arguments: args } = data;
    
        // List of supported languages - you can expand this as needed
        const supportedLanguages = [
            'en', 'es', 'fr', 'de', 'it', 'pt', 'ru', 'zh', 'ja', 'ko',
            'ar', 'hi', 'bn', 'pa', 'te', 'mr', 'tr', 'vi', 'id', 'ms',
            'th', 'nl', 'sv', 'no', 'da', 'fi', 'pl', 'uk', 'cs', 'sk',
            'hu', 'ro', 'bg', 'el', 'he', 'fa'
        ];
    
        // If no language specified, show current language or help
        if (!args.language) {
            const currentLangVar = await takaro.variable.variableControllerSearch({
                filters: {
                    key: [LANGUAGE_VARIABLE_KEY],
                    gameServerId: [gameServerId],
                    playerId: [player.id],
                    moduleId: [module.moduleId]
                }
            });
    
            if (currentLangVar.data.data.length > 0) {
                const currentLang = currentLangVar.data.data[0].value;
                await player.pm(`Your language is currently set to: ${currentLang}`);
            } else {
                await player.pm(`You haven't set a language yet. Use this command with a language code to set your language.`);
                await player.pm(`Example: /setlanguage en`);
                await player.pm(`Supported languages: ${supportedLanguages.join(', ')}`);
            }
            return;
        }
    
        // Convert to lowercase for consistency
        const language = args.language.toLowerCase();
    
        // Validate the language
        if (!supportedLanguages.includes(language)) {
            throw new TakaroUserError(`Unsupported language: ${language}. Supported languages: ${supportedLanguages.join(', ')}`);
        }
    
        // Check if user already has a language set
        const existingLanguageVar = await takaro.variable.variableControllerSearch({
            filters: {
                key: [LANGUAGE_VARIABLE_KEY],
                gameServerId: [gameServerId],
                playerId: [player.id],
                moduleId: [module.moduleId]
            }
        });
    
        // If language variable exists, update it
        if (existingLanguageVar.data.data.length > 0) {
            await takaro.variable.variableControllerUpdate(existingLanguageVar.data.data[0].id, {
                value: language
            });
        }
        // Otherwise create a new variable
        else {
            await takaro.variable.variableControllerCreate({
                key: LANGUAGE_VARIABLE_KEY,
                value: language,
                gameServerId: gameServerId,
                playerId: player.id,
                moduleId: module.moduleId
            });
        }
    
        await player.pm(`Your language has been set to: ${language}`);
    }
    
    await main();

Hooks 1

Code that runs in reaction to a game or Takaro event.

  • auto-translate

    Hook for chat-message events

    Hook source
    import { takaro, data, TakaroUserError } from '@takaro/helpers';
    
    const LANGUAGE_VARIABLE_KEY = 'user_language';
    const TRANSLATION_ENABLED_KEY = 'translation_enabled';
    
    async function main() {
        const { gameServerId, module: mod, eventData } = data;
    
        // Skip if API key is not configured
        if (!mod.userConfig.googleApiKey) {
            console.error('Auto-translation is not configured: missing Google API key');
            return;
        }
    
        // Skip commands
        const msg = eventData.msg;
        const prefix = (await takaro.settings.settingsControllerGetOne('commandPrefix', gameServerId)).data.data.value;
        if (msg.startsWith(prefix)) {
            console.log('Skipping command message');
            return;
        }
    
        // Skip system messages
        if (!data.player) {
            console.log('Skipping system message (no player)');
            return;
        }
    
        const senderName = data.player.name;
        const senderId = data.player.id;
        const messageToTranslate = msg;
    
        console.log(`Processing message from ${senderName}: ${messageToTranslate}`);
    
        // Get all online players
        const onlinePlayers = (await takaro.gameserver.gameServerControllerGetPlayers(gameServerId)).data.data;
        console.log(`Found ${onlinePlayers.length} online players`);
    
        // Detect the source language
        let sourceLanguage;
        try {
            sourceLanguage = await detectLanguage(messageToTranslate, mod.userConfig.googleApiKey);
            console.log(`Detected source language: ${sourceLanguage}`);
        } catch (error) {
            console.error(`Language detection error: ${error.message}`);
            sourceLanguage = 'en'; // Default to English if detection fails
        }
    
        // Process each online player
        const translationPromises = onlinePlayers.map(async (playerInfo) => {
            // Skip the sender - don't translate for them
            if (playerInfo.steamId === data.player.steamId) {
                console.log(`Skipping translation for message sender: ${playerInfo.name}`);
                return null;
            }
    
            try {
                // Get the player's Takaro ID
                const playerRes = await takaro.player.playerControllerSearch({
                    filters: {
                        steamId: [playerInfo.steamId]
                    }
                });
    
                if (playerRes.data.data.length === 0) {
                    console.log(`Could not find Takaro player for Steam ID: ${playerInfo.steamId}`);
                    return null;
                }
    
                const receiverPlayer = playerRes.data.data[0];
                console.log(`Processing player: ${receiverPlayer.name} (ID: ${receiverPlayer.id})`);
    
                // Check if player has enabled translations
                const enabledRes = await takaro.variable.variableControllerSearch({
                    filters: {
                        key: [TRANSLATION_ENABLED_KEY],
                        gameServerId: [gameServerId],
                        playerId: [receiverPlayer.id],
                        moduleId: [mod.moduleId]
                    }
                });
    
                // If player has explicitly disabled translations, skip them
                if (enabledRes.data.data.length > 0 && enabledRes.data.data[0].value === 'false') {
                    console.log(`Player ${receiverPlayer.name} has disabled translations, skipping`);
                    return null;
                }
    
                // Get the player's language preference
                const langVar = await takaro.variable.variableControllerSearch({
                    filters: {
                        key: [LANGUAGE_VARIABLE_KEY],
                        gameServerId: [gameServerId],
                        playerId: [receiverPlayer.id],
                        moduleId: [mod.moduleId]
                    }
                });
    
                // Skip if no language preference is set
                if (langVar.data.data.length === 0) {
                    console.log(`No language preference set for ${receiverPlayer.name}, skipping`);
                    return null;
                }
    
                const targetLanguage = langVar.data.data[0].value;
                console.log(`${receiverPlayer.name}'s language preference: ${targetLanguage}`);
    
                // Skip if the target language is the same as source language
                if (targetLanguage === sourceLanguage) {
                    console.log(`Skipping translation for ${receiverPlayer.name} - same language`);
                    return null;
                }
    
                // Translate the message
                console.log(`Translating to ${targetLanguage} for ${receiverPlayer.name}`);
                const translation = await translateText(messageToTranslate, targetLanguage, mod.userConfig.googleApiKey);
    
                // Get the playerOnGameserver record to get the gameId
                const pogRes = await takaro.playerOnGameserver.playerOnGameServerControllerSearch({
                    filters: {
                        gameServerId: [gameServerId],
                        playerId: [receiverPlayer.id]
                    }
                });
    
                if (pogRes.data.data.length === 0) {
                    console.log(`Could not find PlayerOnGameserver record for ${receiverPlayer.name}, cannot send message`);
                    return null;
                }
    
                const pog = pogRes.data.data[0];
    
                // Send the translated message to the player as private message
                console.log(`Sending translation to ${receiverPlayer.name} with gameId: ${pog.gameId}`);
                await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
                    message: `[Translated from ${senderName}]: ${translation}`,
                    opts: {
                        recipient: {
                            gameId: pog.gameId
                        }
                    }
                });
    
                return true;
            } catch (error) {
                console.error(`Error processing player ${playerInfo.name}: ${error.message}`);
                return null;
            }
        });
    
        // Wait for all translations to complete
        await Promise.allSettled(translationPromises);
    }
    
    // Function to detect the language of text
    async function detectLanguage(text, apiKey) {
        try {
            const response = await takaro.axios.post(
                `https://translation.googleapis.com/language/translate/v2/detect?key=${apiKey}`,
                { q: text },
                { headers: { 'Content-Type': 'application/json' } }
            );
    
            if (response.data.error) {
                throw new Error(response.data.error.message || "Unknown detection error");
            }
    
            if (!response.data.data || !response.data.data.detections ||
                !response.data.data.detections[0] || !response.data.data.detections[0][0]) {
                throw new Error("Invalid response format from language detection API");
            }
    
            return response.data.data.detections[0][0].language;
        } catch (error) {
            console.error(`Language detection API error: ${error.message}`);
            throw new Error(`API error: ${error.message}`);
        }
    }
    
    // Translation function
    async function translateText(text, targetLanguage, apiKey) {
        try {
            const response = await takaro.axios.post(
                `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`,
                {
                    q: text,
                    target: targetLanguage
                },
                { headers: { 'Content-Type': 'application/json' } }
            );
    
            const result = response.data;
    
            if (result.error) {
                throw new Error(result.error.message || "Unknown translation error");
            }
    
            if (!result.data || !result.data.translations || !result.data.translations[0]) {
                throw new Error("Invalid response format from translation API");
            }
    
            return result.data.translations[0].translatedText;
        } catch (error) {
            console.error(`Translation API error: ${error.message}`);
            throw new Error(`API error: ${error.message}`);
        }
    }
    
    await main();

Permissions 1

Roles you can grant to decide who may use what.

  • TRANSLATE_PERMISSION

    Give players Translate permission