{
  "name": "Translator",
  "author": "limon",
  "supportedGames": [
    "all"
  ],
  "takaroVersion": "v0.0.29",
  "versions": [
    {
      "tag": "1.2.0",
      "description": "Enables real-time translation of in-game chat messages, facilitating cross-lingual communication among players.\n\n  ## Key Functionality\n\n  * **Two-Way Translation:** Translates chat messages between players speaking different languages.\n  * **Automatic Translation:** Can automatically translate messages based on players' configured language preferences.\n  * **On-Demand Translation:** Players can translate specific messages or recent messages from other players using commands.\n  * **Configurable Languages:** Server administrators can define the list of supported languages.\n  * **Google Translate Integration:** Leverages the Google Cloud Translation API for accurate and comprehensive language support.\n  * **Permission Control:** Granular permissions allow administrators to control who can use translation features.\n\n  ## How to Use\n\n  1.  **Configuration:**\n      * `googleApiKey`: **(Required)** Enter your Google Cloud API key with access to the Cloud Translation API.\n      * `maxMessageLength`: Set the maximum character length for messages to be translated (to manage API usage/costs). Default: 500.\n      * `defaultLanguage`: Set the default language code (ISO 639-1) for translations when a player hasn't specified their preference. Default: `en`.\n      * `supportedLanguages`:  Define an array of ISO 639-1 language codes (e.g., `[\"en\", \"es\", \"fr\"]`) for the languages supported by the module.\n      * `commandPrefixes`: (Optional) An array of prefixes that are used to identify commands. Messages that start with these prefixes will not be translated. Default: `[\"/\"]`\n  2.  **Permissions:**\n      * `TRANSLATE_PERMISSION`:  Grants players access to basic translation commands (`/translate`, `/setlanguage`, `/toggletranslation`, `/translateme`).\n      * `TRANSLATE_ADMIN`:  Allows administrators to set language preferences for other players (`/setplayerlanguage`).\n      * `AUTO_TRANSLATE_PERMISSION`: Allows players to receive automatically translated messages.\n  3.  **In-Game Usage:**\n      * `/translate <language> \"text\"`: Translates the provided `text` into the specified `language` and sends it to the global chat.\n      * `/setlanguage <code>`: Sets the player's preferred language for receiving translations (e.g., `/setlanguage es`).\n      * `/toggletranslation on/off`: Enables or disables automatic translation for the player.\n      * `/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.\n      * `/setplayerlanguage <player> <language>`: (Admin only) Sets the preferred language for another player.\n\n  ## Important Considerations\n\n  * **Google Cloud API Key:** A valid Google Cloud API key with the Cloud Translation API enabled is **essential** for this module to function.\n  * **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.\n  * **Permissions Management:** Carefully manage the module's permissions to control access to translation features.\n  * **Message Length:** Be mindful of the `maxMessageLength` setting to avoid excessive API usage and potential costs.\n  * **Error Handling:** The module includes error handling, but it's important to monitor server logs for any translation-related issues.\n",
      "configSchema": "{\"$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\",\"zh-CN\",\"ro\"],\"type\":\"array\",\"items\":{\"type\":\"string\"}}}}",
      "uiSchema": "{}",
      "commands": [
        {
          "name": "setlanguage",
          "trigger": "setlanguage",
          "helpText": "No help text available",
          "function": "import { takaro, data, TakaroUserError } from '@takaro/helpers';\n\nconst LANGUAGE_VARIABLE_KEY = 'user_language';\n\nasync function main() {\n    const { player, pog, gameServerId, module, arguments: args } = data;\n\n    // List of supported languages - you can expand this as needed\n    const supportedLanguages = [\n        'en', 'es', 'fr', 'de', 'it', 'pt', 'ru', 'zh', 'ja', 'ko',\n        'ar', 'hi', 'bn', 'pa', 'te', 'mr', 'tr', 'vi', 'id', 'ms',\n        'th', 'nl', 'sv', 'no', 'da', 'fi', 'pl', 'uk', 'cs', 'sk',\n        'hu', 'ro', 'bg', 'el', 'he', 'fa', 'ro', 'zh-CN', 'zh-cn'\n    ];\n\n    // If no language specified, show current language or help\n    if (!args.language) {\n        const currentLangVar = await takaro.variable.variableControllerSearch({\n            filters: {\n                key: [LANGUAGE_VARIABLE_KEY],\n                gameServerId: [gameServerId],\n                playerId: [player.id],\n                moduleId: [module.moduleId]\n            }\n        });\n\n        if (currentLangVar.data.data.length > 0) {\n            const currentLang = currentLangVar.data.data[0].value;\n            await player.pm(`Your language is currently set to: ${currentLang}`);\n        } else {\n            await player.pm(`You haven't set a language yet. Use this command with a language code to set your language.`);\n            await player.pm(`Example: /setlanguage en`);\n            await player.pm(`Supported languages: ${supportedLanguages.join(', ')}`);\n        }\n        return;\n    }\n\n    // Convert to lowercase for consistency\n    const language = args.language.toLowerCase();\n\n    // Validate the language\n    if (!supportedLanguages.includes(language)) {\n        throw new TakaroUserError(`Unsupported language: ${language}. Supported languages: ${supportedLanguages.join(', ')}`);\n    }\n\n    // Check if user already has a language set\n    const existingLanguageVar = await takaro.variable.variableControllerSearch({\n        filters: {\n            key: [LANGUAGE_VARIABLE_KEY],\n            gameServerId: [gameServerId],\n            playerId: [player.id],\n            moduleId: [module.moduleId]\n        }\n    });\n\n    // If language variable exists, update it\n    if (existingLanguageVar.data.data.length > 0) {\n        await takaro.variable.variableControllerUpdate(existingLanguageVar.data.data[0].id, {\n            value: language\n        });\n    }\n    // Otherwise create a new variable\n    else {\n        await takaro.variable.variableControllerCreate({\n            key: LANGUAGE_VARIABLE_KEY,\n            value: language,\n            gameServerId: gameServerId,\n            playerId: player.id,\n            moduleId: module.moduleId\n        });\n    }\n\n    await player.pm(`Your language has been set to: ${language}`);\n}\n\nawait main();",
          "arguments": [
            {
              "name": "language",
              "type": "string",
              "helpText": "Set your language",
              "defaultValue": "",
              "position": 0
            }
          ]
        },
        {
          "name": "gettranslation",
          "trigger": "translateme",
          "helpText": "No help text available",
          "function": "import { takaro, data, TakaroUserError } from '@takaro/helpers';\n\nconst LANGUAGE_VARIABLE_KEY = 'user_language';\n\nasync function translateText(text, targetLanguage, apiKey) {\n    if (!text || !text.trim()) return '';\n\n    try {\n        const response = await takaro.axios.post(\n            `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`,\n            { q: text, target: targetLanguage },\n            { headers: { 'Content-Type': 'application/json' } }\n        );\n\n        const result = response.data;\n\n        if (result.error) {\n            throw new Error(result.error.message || \"Unknown translation error\");\n        }\n\n        if (!result.data?.translations?.[0]) {\n            throw new Error(\"Invalid response format from translation API\");\n        }\n\n        return result.data.translations[0].translatedText;\n    } catch (error) {\n        console.error(`Translation API error:`, error);\n        return '[Translation error]';\n    }\n}\n\nasync function main() {\n    try {\n        const { player, arguments: args, gameServerId, module: mod } = data;\n\n        // Validate configuration\n        if (!mod.userConfig.googleApiKey) {\n            throw new TakaroUserError('Translation feature is not configured. Google API key is missing.');\n        }\n\n        // Find target player\n        if (!args.targetPlayerName) {\n            throw new TakaroUserError('Please specify a player to translate messages from.');\n        }\n\n        const targetPlayer = await getTargetPlayer(args.targetPlayerName);\n\n        // Determine target language\n        const targetLanguage = await determineTargetLanguage(args.targetLang, player.id, gameServerId, mod);\n\n        // Get message count (between 1-20)\n        const messageCount = Math.min(Math.max(parseInt(args.count || 5, 10), 1), 20);\n\n        // Fetch and translate messages\n        const messages = await fetchRecentMessages(targetPlayer.id, gameServerId, messageCount);\n\n        const consolidatedMessage = await buildTranslatedOutput(messages, targetPlayer.name, targetLanguage, mod.userConfig.googleApiKey);\n\n        await player.pm(consolidatedMessage);\n\n    } catch (error) {\n        console.error('Error in translation module:', error);\n        throw error instanceof TakaroUserError\n            ? error\n            : new TakaroUserError(`An error occurred while translating messages: ${error.message}`);\n    }\n}\n\nasync function getTargetPlayer(targetPlayerName) {\n    if (targetPlayerName.id) return targetPlayerName;\n\n    const playerSearch = await takaro.player.playerControllerSearch({\n        search: { name: [targetPlayerName] }\n    });\n\n    if (!playerSearch.data.data?.length) {\n        throw new TakaroUserError(`Player \"${targetPlayerName}\" not found.`);\n    }\n\n    return playerSearch.data.data[0];\n}\n\nasync function determineTargetLanguage(requestedLanguage, playerId, gameServerId, mod) {\n    // First priority: explicitly requested language\n    if (requestedLanguage) {\n        validateLanguage(requestedLanguage, mod);\n        return requestedLanguage;\n    }\n\n    // Second priority: user's saved preference\n    const userLanguageVar = await takaro.variable.variableControllerSearch({\n        filters: {\n            key: [LANGUAGE_VARIABLE_KEY],\n            gameServerId: [gameServerId],\n            playerId: [playerId],\n            moduleId: [mod.moduleId]\n        }\n    });\n\n    if (userLanguageVar.data.data?.length) {\n        const savedLanguage = userLanguageVar.data.data[0].value;\n        validateLanguage(savedLanguage, mod);\n        return savedLanguage;\n    }\n\n    // Last priority: module default or English\n    const defaultLanguage = mod.userConfig.defaultLanguage || 'en';\n    validateLanguage(defaultLanguage, mod);\n    return defaultLanguage;\n}\n\nfunction validateLanguage(language, mod) {\n    if (mod.userConfig.supportedLanguages &&\n        !mod.userConfig.supportedLanguages.includes(language)) {\n        throw new TakaroUserError(\n            `Unsupported target language: ${language}. ` +\n            `Available languages: ${mod.userConfig.supportedLanguages.join(', ')}`\n        );\n    }\n}\n\nasync function fetchRecentMessages(playerId, gameServerId, messageCount) {\n    const events = await takaro.event.eventControllerSearch({\n        limit: 100,\n        sortBy: 'createdAt',\n        sortDirection: 'desc',\n        filters: {\n            eventName: ['chat-message'],\n            gameserverId: [gameServerId],\n            playerId: [playerId]\n        }\n    });\n\n    if (!events.data.data?.length) {\n        throw new TakaroUserError(`No chat messages found for this player.`);\n    }\n\n    // Filter out command messages (messages starting with '/' or '!')\n    const filteredMessages = events.data.data\n        .filter(event => {\n            const message = event.meta.msg;\n            return message && typeof message === 'string' &&\n                !message.startsWith('/') &&\n                !message.startsWith('!');\n        })\n        .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))\n        .slice(0, messageCount)\n        .map(event => ({\n            content: event.meta.msg,\n            timestamp: event.createdAt\n        }));\n\n    if (filteredMessages.length === 0) {\n        throw new TakaroUserError(`No non-command messages found for this player.`);\n    }\n\n    return filteredMessages;\n}\n\nasync function buildTranslatedOutput(messages, playerName, targetLanguage, apiKey) {\n    let output = `Messages from ${playerName} (${targetLanguage}):\\n\\n`;\n\n    // Reverse the messages array to start from the oldest\n    const reversedMessages = [...messages].reverse();\n\n    for (let i = 0; i < reversedMessages.length; i++) {\n        const message = reversedMessages[i];\n        const translatedText = await translateText(message.content, targetLanguage, apiKey);\n\n        // Just show the translation, not the original message\n        output += `${i + 1}. ${translatedText}\\n\\n`;\n    }\n\n    return output;\n}\n\nawait main();\n",
          "arguments": [
            {
              "name": "targetPlayerName",
              "type": "string",
              "helpText": "player name",
              "defaultValue": "",
              "position": 0
            }
          ]
        },
        {
          "name": "setplayerlanguage",
          "trigger": "setplayerlanguage",
          "helpText": "No help text available",
          "function": "import { takaro, data, TakaroUserError, checkPermission } from '@takaro/helpers';\n\nconst LANGUAGE_VARIABLE_KEY = 'user_language';\n\nasync function main() {\n    const { player, pog, gameServerId, module, arguments: args } = data;\n\n    // Check if player has admin permissions to set other players' languages\n    if (!checkPermission(pog, 'TRANSLATE_ADMIN')) {\n        throw new TakaroUserError('You do not have permission to set languages for other players.');\n    }\n\n    // Validate target player parameter\n    if (!args.targetPlayer) {\n        throw new TakaroUserError('Please specify a player name. Usage: /setplayerlanguage <player> <language>');\n    }\n\n    // Validate language parameter\n    if (!args.language) {\n        throw new TakaroUserError('Please specify a language code. Usage: /setplayerlanguage <player> <language>');\n    }\n\n    // Find the target player\n    let targetPlayer;\n    try {\n        const targetPlayerSearch = await takaro.player.playerControllerSearch({\n            search: { name: [args.targetPlayer] }\n        });\n\n        if (!targetPlayerSearch.data.data?.length) {\n            throw new TakaroUserError(`Player \"${args.targetPlayer}\" not found.`);\n        }\n\n        targetPlayer = targetPlayerSearch.data.data[0];\n    } catch (error) {\n        throw new TakaroUserError(`Failed to find player: ${error.message}`);\n    }\n\n    // Validate language code against supported languages in config\n    const supportedLanguages = module.userConfig.supportedLanguages || [];\n    if (supportedLanguages.length > 0 && !supportedLanguages.includes(args.language)) {\n        throw new TakaroUserError(\n            `Invalid language code. Valid options are: ${supportedLanguages.join(', ')}`\n        );\n    }\n\n    // Convert to lowercase for consistency\n    const language = args.language.toLowerCase();\n\n    try {\n        // Check if target player already has a language set\n        const existingLanguageVar = await takaro.variable.variableControllerSearch({\n            filters: {\n                key: [LANGUAGE_VARIABLE_KEY],\n                gameServerId: [gameServerId],\n                playerId: [targetPlayer.id],\n                moduleId: [module.moduleId]\n            }\n        });\n\n        // If language variable exists, update it\n        if (existingLanguageVar.data.data.length > 0) {\n            await takaro.variable.variableControllerUpdate(existingLanguageVar.data.data[0].id, {\n                value: language\n            });\n        }\n        // Otherwise create a new variable\n        else {\n            await takaro.variable.variableControllerCreate({\n                key: LANGUAGE_VARIABLE_KEY,\n                value: language,\n                gameServerId: gameServerId,\n                playerId: targetPlayer.id,\n                moduleId: module.moduleId\n            });\n        }\n\n        await player.pm(`Language for ${targetPlayer.name} has been set to: ${language}`);\n\n        // Also notify the target player if they're online\n        try {\n            const pogList = await takaro.playerOnGameserver.playerOnGameServerControllerSearch({\n                filters: {\n                    gameServerId: [gameServerId],\n                    playerId: [targetPlayer.id],\n                    online: [true]\n                }\n            });\n\n            if (pogList.data.data.length > 0) {\n                // The player is online, we can send them a notification\n                await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {\n                    message: `An admin has set your translation language to: ${language}`,\n                    opts: {\n                        recipient: {\n                            gameId: pogList.data.data[0].gameId\n                        }\n                    }\n                });\n            }\n        } catch (error) {\n            console.error(`Error notifying target player: ${error.message}`);\n            // We don't want to fail the whole command if just the notification fails\n        }\n\n    } catch (error) {\n        console.error(`Error setting player language: ${error.message}`);\n        throw new TakaroUserError(`Failed to set language: ${error.message}`);\n    }\n}\n\nawait main();",
          "arguments": [
            {
              "name": "targetPlayer",
              "type": "string",
              "helpText": "Name of the player to set language for",
              "defaultValue": "",
              "position": 0
            },
            {
              "name": "language",
              "type": "string",
              "helpText": "Language code to set (e.g., 'en' for English)",
              "defaultValue": "",
              "position": 1
            }
          ]
        },
        {
          "name": "translateme",
          "trigger": "translateme",
          "helpText": "Translate recent messages from a specific player into your preferred language. Specify a number to translate multiple messages.",
          "function": "import { takaro, data, TakaroUserError, checkPermission } from '@takaro/helpers';\n\nconst LANGUAGE_VARIABLE_KEY = 'user_language';\nconst TRANSLATE_PERMISSION = 'TRANSLATE_PERMISSION';\n\nasync function translateText(text, targetLanguage, apiKey) {\n    if (!text || !text.trim()) return '';\n\n    try {\n        const response = await takaro.axios.post(\n            `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`,\n            { q: text, target: targetLanguage },\n            { headers: { 'Content-Type': 'application/json' } }\n        );\n\n        const result = response.data;\n\n        if (result.error) {\n            throw new Error(result.error.message || \"Unknown translation error\");\n        }\n\n        if (!result.data?.translations?.[0]) {\n            throw new Error(\"Invalid response format from translation API\");\n        }\n\n        return result.data.translations[0].translatedText;\n    } catch (error) {\n        console.error(`Translation API error:`, error);\n        return '[Translation error]';\n    }\n}\n\nasync function main() {\n    try {\n        const { player, arguments: args, gameServerId, module: mod, pog } = data;\n\n        // Check permission - ensure player has TRANSLATE_PERMISSION\n        if (!checkPermission(pog, TRANSLATE_PERMISSION)) {\n            throw new TakaroUserError(\"You don't have permission to use the translation feature.\");\n        }\n\n        // Validate configuration\n        if (!mod.userConfig.googleApiKey) {\n            throw new TakaroUserError('Translation feature is not configured. Google API key is missing.');\n        }\n\n        // Find target player\n        if (!args.targetPlayerName) {\n            throw new TakaroUserError('Please specify a player to translate messages from.');\n        }\n\n        const targetPlayer = await getTargetPlayer(args.targetPlayerName);\n\n        // Determine target language\n        const targetLanguage = await determineTargetLanguage(args.targetLang, player.id, gameServerId, mod);\n\n        // Get message count from args or default to 1 (just the last message)\n        const messageCount = args.count ? Math.min(Math.max(parseInt(args.count, 10), 1), 20) : 1;\n\n        // Fetch and translate messages\n        const messages = await fetchRecentMessages(targetPlayer.id, gameServerId, messageCount);\n\n        const consolidatedMessage = await buildTranslatedOutput(messages, targetPlayer.name, targetLanguage, mod.userConfig.googleApiKey);\n\n        await player.pm(consolidatedMessage);\n\n    } catch (error) {\n        console.error('Error in translation module:', error);\n        throw error instanceof TakaroUserError\n            ? error\n            : new TakaroUserError(`An error occurred while translating messages: ${error.message}`);\n    }\n}\n\nasync function getTargetPlayer(targetPlayerName) {\n    if (targetPlayerName.id) return targetPlayerName;\n\n    const playerSearch = await takaro.player.playerControllerSearch({\n        search: { name: [targetPlayerName] }\n    });\n\n    if (!playerSearch.data.data?.length) {\n        throw new TakaroUserError(`Player \"${targetPlayerName}\" not found.`);\n    }\n\n    return playerSearch.data.data[0];\n}\n\nasync function determineTargetLanguage(requestedLanguage, playerId, gameServerId, mod) {\n    // First priority: explicitly requested language\n    if (requestedLanguage) {\n        validateLanguage(requestedLanguage, mod);\n        return requestedLanguage;\n    }\n\n    // Second priority: user's saved preference\n    const userLanguageVar = await takaro.variable.variableControllerSearch({\n        filters: {\n            key: [LANGUAGE_VARIABLE_KEY],\n            gameServerId: [gameServerId],\n            playerId: [playerId],\n            moduleId: [mod.moduleId]\n        }\n    });\n\n    if (userLanguageVar.data.data?.length) {\n        const savedLanguage = userLanguageVar.data.data[0].value;\n        validateLanguage(savedLanguage, mod);\n        return savedLanguage;\n    }\n\n    // Last priority: module default or English\n    const defaultLanguage = mod.userConfig.defaultLanguage || 'en';\n    validateLanguage(defaultLanguage, mod);\n    return defaultLanguage;\n}\n\nfunction validateLanguage(language, mod) {\n    if (mod.userConfig.supportedLanguages &&\n        !mod.userConfig.supportedLanguages.includes(language)) {\n        throw new TakaroUserError(\n            `Unsupported target language: ${language}. ` +\n            `Available languages: ${mod.userConfig.supportedLanguages.join(', ')}`\n        );\n    }\n}\n\nasync function fetchRecentMessages(playerId, gameServerId, messageCount) {\n    const events = await takaro.event.eventControllerSearch({\n        limit: 100,\n        sortBy: 'createdAt',\n        sortDirection: 'desc',\n        filters: {\n            eventName: ['chat-message'],\n            gameserverId: [gameServerId],\n            playerId: [playerId]\n        }\n    });\n\n    if (!events.data.data?.length) {\n        throw new TakaroUserError(`No chat messages found for this player.`);\n    }\n\n    // Filter out command messages (messages starting with '/' or '!')\n    const filteredMessages = events.data.data\n        .filter(event => {\n            const message = event.meta.msg;\n            return message && typeof message === 'string' &&\n                !message.startsWith('/') &&\n                !message.startsWith('!');\n        })\n        .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))\n        .slice(0, messageCount)\n        .map(event => ({\n            content: event.meta.msg,\n            timestamp: event.createdAt\n        }));\n\n    if (filteredMessages.length === 0) {\n        throw new TakaroUserError(`No non-command messages found for this player.`);\n    }\n\n    return filteredMessages;\n}\n\nasync function buildTranslatedOutput(messages, playerName, targetLanguage, apiKey) {\n    let output = `Messages from ${playerName} (${targetLanguage}):\\n\\n`;\n\n    // Reverse the messages array to start from the oldest\n    const reversedMessages = [...messages].reverse();\n\n    for (let i = 0; i < reversedMessages.length; i++) {\n        const message = reversedMessages[i];\n        const translatedText = await translateText(message.content, targetLanguage, apiKey);\n\n        // Just show the translation, not the original message\n        output += `${i + 1}. ${translatedText}\\n\\n`;\n    }\n\n    return output;\n}\n\nawait main();",
          "arguments": [
            {
              "name": "targetPlayerName",
              "type": "string",
              "helpText": "player name",
              "defaultValue": "",
              "position": 0
            },
            {
              "name": "count",
              "type": "string",
              "helpText": "Number of most recent messages to translate (default: 1)",
              "defaultValue": "1",
              "position": 1
            }
          ]
        },
        {
          "name": "toggletranslation",
          "trigger": "toggletranslation",
          "helpText": "Enable or disable automatic translation of messages. Use 'toggletranslation on' to receive translated messages, 'toggletranslation off' to disable.",
          "function": "import { takaro, data, TakaroUserError, checkPermission } from '@takaro/helpers';\n\nconst TRANSLATION_ENABLED_KEY = 'translation_enabled';\n\nasync function main() {\n    const { player, pog, gameServerId, module, arguments: args } = data;\n\n    // Check if player has permission to use this command\n    if (!checkPermission(pog, 'TRANSLATE_PERMISSION')) {\n        throw new TakaroUserError('You do not have permission to use translation features.');\n    }\n\n    // Get the current status if no argument is provided\n    if (!args.status || (args.status !== 'on' && args.status !== 'off')) {\n        const currentStatusVar = await takaro.variable.variableControllerSearch({\n            filters: {\n                key: [TRANSLATION_ENABLED_KEY],\n                gameServerId: [gameServerId],\n                playerId: [player.id],\n                moduleId: [module.moduleId]\n            }\n        });\n\n        // Check if we have a stored preference\n        if (currentStatusVar.data.data.length > 0) {\n            const isEnabled = currentStatusVar.data.data[0].value === 'true';\n            await player.pm(`Your translation status is currently: ${isEnabled ? 'ENABLED' : 'DISABLED'}`);\n            await player.pm('Use \"/toggletranslation on\" or \"/toggletranslation off\" to change this setting.');\n        } else {\n            // If no preference is set, check the module default setting\n            const defaultEnabled = module.userConfig.enabledByDefault ?? false;\n            await player.pm(`Your translation status is currently: ${defaultEnabled ? 'ENABLED' : 'DISABLED'} (using default setting)`);\n            await player.pm('Use \"/toggletranslation on\" or \"/toggletranslation off\" to change this setting.');\n        }\n        return;\n    }\n\n    // Convert argument to boolean\n    const newStatus = args.status === 'on';\n\n    // Check if user already has a preference set\n    const existingStatusVar = await takaro.variable.variableControllerSearch({\n        filters: {\n            key: [TRANSLATION_ENABLED_KEY],\n            gameServerId: [gameServerId],\n            playerId: [player.id],\n            moduleId: [module.moduleId]\n        }\n    });\n\n    // If preference exists, update it\n    if (existingStatusVar.data.data.length > 0) {\n        await takaro.variable.variableControllerUpdate(existingStatusVar.data.data[0].id, {\n            value: newStatus.toString()\n        });\n    }\n    // Otherwise create a new variable\n    else {\n        await takaro.variable.variableControllerCreate({\n            key: TRANSLATION_ENABLED_KEY,\n            value: newStatus.toString(),\n            gameServerId: gameServerId,\n            playerId: player.id,\n            moduleId: module.moduleId\n        });\n    }\n\n    await player.pm(`Translation has been ${newStatus ? 'ENABLED' : 'DISABLED'} for you.`);\n\n    // If translations were enabled but no language is set, prompt the user\n    if (newStatus) {\n        const languageVar = await takaro.variable.variableControllerSearch({\n            filters: {\n                key: ['user_language'],\n                gameServerId: [gameServerId],\n                playerId: [player.id],\n                moduleId: [module.moduleId]\n            }\n        });\n\n        if (languageVar.data.data.length === 0) {\n            const defaultLanguage = module.userConfig.defaultLanguage || 'en';\n            await player.pm(`No language preference is set. Messages will be translated to ${defaultLanguage} by default.`);\n            await player.pm(`Use \"/setlanguage <code>\" to set your preferred language.`);\n            await player.pm(`Example: /setlanguage es (for Spanish)`);\n\n            // List available languages\n            if (module.userConfig.supportedLanguages && module.userConfig.supportedLanguages.length > 0) {\n                await player.pm(`Supported languages: ${module.userConfig.supportedLanguages.join(', ')}`);\n            }\n        }\n    }\n}\n\nawait main();",
          "arguments": [
            {
              "name": "status",
              "type": "string",
              "helpText": "on/off to enable/disable translations",
              "defaultValue": "off",
              "position": 0
            }
          ]
        },
        {
          "name": "translate",
          "trigger": "translate",
          "helpText": "No help text available",
          "function": "import { takaro, data, TakaroUserError } from '@takaro/helpers';\n\nasync function main() {\n    const { player, gameServerId, module: mod, arguments: args } = data;\n\n    // Get the text to translate\n    const textToTranslate = args.text;\n\n    if (!textToTranslate || textToTranslate.trim() === \"\") {\n        throw new TakaroUserError(\"No text to translate was provided.\");\n    }\n\n    // Validate language code against supported languages in config\n    const validLanguages = mod.userConfig.supportedLanguages;\n    if (!validLanguages.includes(args.language)) {\n        throw new TakaroUserError(\n            `Invalid language code. Valid options are: ${validLanguages.join(', ')}`\n        );\n    }\n\n    // First verify API key is configured\n    if (!mod.userConfig.googleApiKey) {\n        throw new TakaroUserError('Translation service is not properly configured. Please contact an administrator.');\n    }\n\n    try {\n        // Translate the text\n        const apiKey = mod.userConfig.googleApiKey;\n        const translation = await translateText(textToTranslate, args.language, apiKey);\n\n        // Get language name for better UX\n        const languageNames = {\n            'en': 'English',\n            'es': 'Spanish',\n            'fr': 'French',\n            'de': 'German',\n            'it': 'Italian',\n            'pt': 'Portuguese',\n            'ru': 'Russian',\n            'zh': 'Chinese',\n            'ja': 'Japanese',\n            'ko': 'Korean',\n            'ar': 'Arabic',\n            'hi': 'Hindi',\n            'tr': 'Turkish',\n            'nl': 'Dutch',\n            'pl': 'Polish',\n            'vi': 'Vietnamese',\n            'th': 'Thai',\n            'id': 'Indonesian',\n            'zh-CN': 'Chinese Simplified',\n            'ro': 'Romanian'\n        };\n        const languageName = languageNames[args.language] || args.language;\n\n        // Send translation to the game server global chat\n        await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {\n            message: `[${player.name} -> ${languageName}]: ${translation}`\n        });\n\n    } catch (error) {\n        console.error(`Translation error: ${error.message}`);\n        throw new TakaroUserError(`Translation failed: ${error.message}`);\n    }\n}\n\n// Translation function using Takaro's HTTP methods\nasync function translateText(text, targetLanguage, apiKey) {\n    try {\n        // Use axios (available in the Takaro environment)\n        const response = await takaro.axios.post(\n            `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`,\n            {\n                q: text,\n                target: targetLanguage\n            },\n            { headers: { 'Content-Type': 'application/json' } }\n        );\n\n        const result = response.data;\n\n        if (result.error) {\n            throw new Error(result.error.message || \"Unknown translation error\");\n        }\n\n        if (!result.data || !result.data.translations || !result.data.translations[0]) {\n            throw new Error(\"Invalid response format from translation API\");\n        }\n\n        return result.data.translations[0].translatedText;\n    } catch (error) {\n        console.error(`Translation API error: ${error.message}`);\n        throw new Error(`API error: ${error.message}`);\n    }\n}\n\nawait main();",
          "arguments": [
            {
              "name": "language",
              "type": "string",
              "helpText": "what language you want to translate to?",
              "defaultValue": "",
              "position": 0
            },
            {
              "name": "text",
              "type": "string",
              "helpText": "The text that you want to translate",
              "defaultValue": "",
              "position": 1
            }
          ]
        }
      ],
      "hooks": [
        {
          "name": "auto-translate",
          "eventType": "chat-message",
          "description": "Hook for chat-message events",
          "regex": null,
          "function": "import { takaro, data, TakaroUserError } from '@takaro/helpers';\n\nconst LANGUAGE_VARIABLE_KEY = 'user_language';\nconst TRANSLATION_ENABLED_KEY = 'translation_enabled';\n\nasync function main() {\n    const { gameServerId, module: mod, eventData } = data;\n\n    // Skip if API key is not configured\n    if (!mod.userConfig.googleApiKey) {\n        console.error('Auto-translation is not configured: missing Google API key');\n        return;\n    }\n\n    // Skip commands\n    const msg = eventData.msg;\n    const prefix = (await takaro.settings.settingsControllerGetOne('commandPrefix', gameServerId)).data.data.value;\n    if (msg.startsWith(prefix)) {\n        console.log('Skipping command message');\n        return;\n    }\n\n    // Skip system messages\n    if (!data.player) {\n        console.log('Skipping system message (no player)');\n        return;\n    }\n\n    const senderName = data.player.name;\n    const senderId = data.player.id;\n    const messageToTranslate = msg;\n\n    console.log(`Processing message from ${senderName}: ${messageToTranslate}`);\n\n    // Get all online players\n    const onlinePlayers = (await takaro.gameserver.gameServerControllerGetPlayers(gameServerId)).data.data;\n    console.log(`Found ${onlinePlayers.length} online players`);\n\n    // Detect the source language\n    let sourceLanguage;\n    try {\n        sourceLanguage = await detectLanguage(messageToTranslate, mod.userConfig.googleApiKey);\n        console.log(`Detected source language: ${sourceLanguage}`);\n    } catch (error) {\n        console.error(`Language detection error: ${error.message}`);\n        sourceLanguage = 'en'; // Default to English if detection fails\n    }\n\n    // Process each online player\n    const translationPromises = onlinePlayers.map(async (playerInfo) => {\n        // Skip the sender - don't translate for them\n        if (playerInfo.steamId === data.player.steamId) {\n            console.log(`Skipping translation for message sender: ${playerInfo.name}`);\n            return null;\n        }\n\n        try {\n            // Get the player's Takaro ID\n            const playerRes = await takaro.player.playerControllerSearch({\n                filters: {\n                    steamId: [playerInfo.steamId]\n                }\n            });\n\n            if (playerRes.data.data.length === 0) {\n                console.log(`Could not find Takaro player for Steam ID: ${playerInfo.steamId}`);\n                return null;\n            }\n\n            const receiverPlayer = playerRes.data.data[0];\n            console.log(`Processing player: ${receiverPlayer.name} (ID: ${receiverPlayer.id})`);\n\n            // Check if player has enabled translations\n            const enabledRes = await takaro.variable.variableControllerSearch({\n                filters: {\n                    key: [TRANSLATION_ENABLED_KEY],\n                    gameServerId: [gameServerId],\n                    playerId: [receiverPlayer.id],\n                    moduleId: [mod.moduleId]\n                }\n            });\n\n            // If player has explicitly disabled translations, skip them\n            if (enabledRes.data.data.length > 0 && enabledRes.data.data[0].value === 'false') {\n                console.log(`Player ${receiverPlayer.name} has disabled translations, skipping`);\n                return null;\n            }\n\n            // Get the player's language preference\n            const langVar = await takaro.variable.variableControllerSearch({\n                filters: {\n                    key: [LANGUAGE_VARIABLE_KEY],\n                    gameServerId: [gameServerId],\n                    playerId: [receiverPlayer.id],\n                    moduleId: [mod.moduleId]\n                }\n            });\n\n            // Skip if no language preference is set\n            if (langVar.data.data.length === 0) {\n                console.log(`No language preference set for ${receiverPlayer.name}, skipping`);\n                return null;\n            }\n\n            const targetLanguage = langVar.data.data[0].value;\n            console.log(`${receiverPlayer.name}'s language preference: ${targetLanguage}`);\n\n            // Skip if the target language is the same as source language\n            if (targetLanguage === sourceLanguage) {\n                console.log(`Skipping translation for ${receiverPlayer.name} - same language`);\n                return null;\n            }\n\n            // Translate the message\n            console.log(`Translating to ${targetLanguage} for ${receiverPlayer.name}`);\n            const translation = await translateText(messageToTranslate, targetLanguage, mod.userConfig.googleApiKey);\n\n            // Get the playerOnGameserver record to get the gameId\n            const pogRes = await takaro.playerOnGameserver.playerOnGameServerControllerSearch({\n                filters: {\n                    gameServerId: [gameServerId],\n                    playerId: [receiverPlayer.id]\n                }\n            });\n\n            if (pogRes.data.data.length === 0) {\n                console.log(`Could not find PlayerOnGameserver record for ${receiverPlayer.name}, cannot send message`);\n                return null;\n            }\n\n            const pog = pogRes.data.data[0];\n\n            // Send the translated message to the player as private message\n            console.log(`Sending translation to ${receiverPlayer.name} with gameId: ${pog.gameId}`);\n            await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {\n                message: `[Translated from ${senderName}]: ${translation}`,\n                opts: {\n                    recipient: {\n                        gameId: pog.gameId\n                    }\n                }\n            });\n\n            return true;\n        } catch (error) {\n            console.error(`Error processing player ${playerInfo.name}: ${error.message}`);\n            return null;\n        }\n    });\n\n    // Wait for all translations to complete\n    await Promise.allSettled(translationPromises);\n}\n\n// Function to detect the language of text\nasync function detectLanguage(text, apiKey) {\n    try {\n        const response = await takaro.axios.post(\n            `https://translation.googleapis.com/language/translate/v2/detect?key=${apiKey}`,\n            { q: text },\n            { headers: { 'Content-Type': 'application/json' } }\n        );\n\n        if (response.data.error) {\n            throw new Error(response.data.error.message || \"Unknown detection error\");\n        }\n\n        if (!response.data.data || !response.data.data.detections ||\n            !response.data.data.detections[0] || !response.data.data.detections[0][0]) {\n            throw new Error(\"Invalid response format from language detection API\");\n        }\n\n        return response.data.data.detections[0][0].language;\n    } catch (error) {\n        console.error(`Language detection API error: ${error.message}`);\n        throw new Error(`API error: ${error.message}`);\n    }\n}\n\n// Translation function\nasync function translateText(text, targetLanguage, apiKey) {\n    try {\n        const response = await takaro.axios.post(\n            `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`,\n            {\n                q: text,\n                target: targetLanguage\n            },\n            { headers: { 'Content-Type': 'application/json' } }\n        );\n\n        const result = response.data;\n\n        if (result.error) {\n            throw new Error(result.error.message || \"Unknown translation error\");\n        }\n\n        if (!result.data || !result.data.translations || !result.data.translations[0]) {\n            throw new Error(\"Invalid response format from translation API\");\n        }\n\n        return result.data.translations[0].translatedText;\n    } catch (error) {\n        console.error(`Translation API error: ${error.message}`);\n        throw new Error(`API error: ${error.message}`);\n    }\n}\n\nawait main();"
        }
      ],
      "cronJobs": [],
      "functions": [],
      "permissions": [
        {
          "permission": "TRANSLATE_PERMISSION",
          "friendlyName": "TRANSLATE_PERMISSION",
          "description": "Give players Translate permission",
          "canHaveCount": false
        },
        {
          "permission": "TRANSLATE_ADMIN",
          "friendlyName": "Admin Set Language",
          "description": "Admins can set language",
          "canHaveCount": false
        }
      ]
    }
  ]
}