Translator
- community
- integration
- by limon
- Takaro v0.0.29
- all
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
- 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:["/"]
- 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.
- In-Game Usage:
/translate <language> "text": Translates the providedtextinto the specifiedlanguageand 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 lastcountmessages from the specifiedplayerand sends them to the user via DM. Ifcountis 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
maxMessageLengthsetting 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.
| Setting | Type | Default | Description |
|---|---|---|---|
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.
-
translate
No help text available
Argument Type Default Help languagestring what language you want to translate to? textstring The text that you want to translate 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(); -
translateme
Translate recent messages from a specific player into your preferred language. Specify a number to translate multiple messages.
Argument Type Default Help targetPlayerNamestring player name countstring 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(); -
setplayerlanguage
No help text available
Argument Type Default Help targetPlayerstring Name of the player to set language for languagestring Language code to set (e.g., 'en' for English) 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(); -
gettranslation
No help text available
Argument Type Default Help targetPlayerNamestring player name Command source
import { takaro, data, TakaroUserError } from '@takaro/helpers'; const LANGUAGE_VARIABLE_KEY = 'user_language'; 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 } = data; // 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 (between 1-20) const messageCount = Math.min(Math.max(parseInt(args.count || 5, 10), 1), 20); // 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(); -
setlanguage
No help text available
Argument Type Default Help languagestring 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(); -
toggletranslation
Enable or disable automatic translation of messages. Use 'toggletranslation on' to receive translated messages, 'toggletranslation off' to disable.
Argument Type Default Help statusstring 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();
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