Resource Bundle (Translation Tool, Hub Kit & Seasonal Events Module)

Introduction

Hey there, how’s it going? Today I wanted to share 3 resources I made pretty recently as people seemed to like the last post I did. I wasn’t entirely sure if they were worth a post individually, so I decided to merge them into a “bundle”, hope you don’t mind.

The resources are the following:
Manual Translation Tool
Hub Creation kit
Time Events

As always, I consider myself an amateur, so if you are an advanced scripter most of this won’t be of much use. If you have any issues or suggestions, let me know below, without further words i’ll leave you with the resources.


Manual Translation Tool

MTT is a dictionary based translation tool I made for a game i’m making. It’s objetive is allowing the localization of all sorts of Text/Strings/Audio/Images in an easy and amateur friendly way.

Advantages of using MTT

  • Automatic and easier to use than LocalizationService.
  • All the work is done in the go using a dictionary, no external programs needed.
  • No unwanted individual word translations.
  • Support for Audios, Images and Text/Strings.
  • Support for any language (including regional variants and fictional languages).
  • Easy to edit to fit your needs (example: to support models you can either fork the module or implement it with the events the module provides by default).

Disadvantages of using MTT

  • Not made for projects with large amounts of text in mind (kilometric dictionaries with a set order can be a nightmare, especially if your game constantly gets new text, I might try to support multiple dictionaries at some point to address this). This is no longer an issue thanks to identifiers.
  • Translations won’t show up on the localization portal.
  • Won’t work with FilteringEnabled (you can use CullingService instead).
How to use

MTT uses a “Source” dictionary (which refers to the language the game is written in) to reference all the objects to translate and store, after a new language is picked the class of each object is checked and the according values from the new language (“ES-LA” for example) are applied if available.

This means all you have to do is pick the objects to translate and reference them in each language dictionary followed by an identifier.

Additionally, if the language your game was written in is not english, make sure to change the variable that decides source’s language in the main module, it’s “EN” by default.


Example:

"Source" (English in this example)

local LangTable = {
	
	["Strings"] = {
		{GuiFrame.PlayButton, "Play_Button"}, --"Play"
		{GuiFrame.Dialogue, "Dialogue_Prompt"} --"Hello, how are you?"
	},
	
	["Audios"] = {
		{RepStorage.Track1, "FinalBossTheme"}, --Sound
		{RepStorage.Track2, "ExplosionBoom"} --SFX
	},
	
	["Images"] = {
		{Workspace.Image1, "User flag"}, --USA Flag
		{Workspace.Image2, "The image of a cube"} --Cube
	}
}

"ES-LA" Spanish Translation

local LangTable = {
	
	["Strings"] = {
		{"Hola, ¿Cómo te va?", "Dialogue_Prompt"} --As you can see, order doesn't matter thanks to the identifier
		{"Jugar", "Play_Button"},
	},
	
	["Audios"] = {
		{RepStorage.Track1ES.SoundId, "FinalBossTheme"}, --Spanish dub of the song?
	}, --In this example I decided to not translate the SFX, so the source audio will be used instead
	
	["Images"] = {
		{Workspace.Image1.Image, "User flag"}, --ES Flag
	} --Same here, image will remain unchanged if not translated
}

Alright I translated everything but nothing is happening, why?

In order for the module to work, you’ll need to tell it when the language changes, otherwise it won’t be able to tell.

Here is an example of how I’d do it:

--- Variables ---

local Utilities = ReplicatedStorage:WaitForChild("Utilities")
local MTT = require(Utilities:WaitForChild("Manual Translation Tool"))

--- Code ---

--Apply player's language when they join (If found, otherwise it'll throw a warn)
local DefaultLanguage = MTT:GetUserLanguage()
MTT.SetLanguage(DefaultLanguage)

--Change language with a button

--English (United States)
EnglishButton.Activated:Connect(function()
	MTT.SetLanguage("EN")
end)

--Spanish (South America)
SpanishLAButton.Activated:Connect(function()
	MTT.SetLanguage("ES-LA")
end)

As a last note, I’d like to add that the module only has 2 regional variants for languages, this is intended so you can add your own and customize them to your liking, it shouldn’t take longer than 3 lines to do so.

Video:

Link:


Hub Creation Kit

Back in 2020 I made a hub intended to gather all the platformers in the platform to help players find them easly. What I found out not very long after starting the project, was that manually inputing and updating over 40 games was neither realistic, nor scalable at long term.

Now that I know a little more of scripting than in 2020, I tried to make the process way easier, with all the data being gathered automatically this time using MarketplaceService and RoProxy (More on this down below), and teleporters to games being handled from a single script and dynamically changed to fit their status.

The “Kit” comes with a module that wraps all the hard work for you, with functions to get the game name, description, thumbnails, owner, price, state, etc), so even though this was made for hubs, it can be used for your own games if they need to gather data.

Features

  • Easy to use (place the ID of the game inside each door model, and you are good to go).
  • Automatically maintained (all the data is gathered on the go and it will always stay up to date).
  • Data Module (gathers all the data you could possibly need).
  • Example Pupups/Loading Screen (to give your game a more professional touch).
About the Proxy

As far as I’ve read in the forum, using public proxies to get the data for your game isn’t a great idea due to you now knowing what the host is doing with the data, if the data you get is correct nor how long the host will maintain it, and overall, you should host your own proxy to avoid these issues.

I personally don’t host one myself, but I have seen multiple posts out there that explain how to set up your own proxy for free if you can’t afford one, RoProxy itself has a lite version you can also host yourself, and overall I encourage anyone who uses this to take a few minutes of their day and replace the proxy found in the ServerScript for their own.

And if you don’t need to get the thumbnails and game status (uncopylocked and open) you can remove the server script and it’s functions from the module, everything else uses MarketplaceService.

Video:

Link:

Note: There appears to be a bug with the "multiget-playability-status" API causing isPlayable to always return false (and the alternative API requires your cookie), if anyone knows a solution or can report this that'd be cool. Once it's fixed I'll update the system to use it, for the time being you can set the status manually and it'll turn the teleporter off.


Time Events (Because the filter didn’t like Date-Based)

Time events is a module I made to allow people to make seasonal events (such as Halloween, Egg Hunt, Christmas, etc.) easly.

It provides a pretty simple API that constantly compares the dates you input on its table with the current time, and it fires an event to let you know if the date is reached and if it happened on live. It also offers a few handy functions to allow your system work the way you envision it.

Features

  • Support for UTC, Developer Offset and Local time.
  • Handy general purpose functions (converting digital to table, getting current unix, number reformatting, etc).
  • Support for cheap live events.

I wanted to add more stuff (such as an object method, a function to get the time until the next event, the support for years and seconds I forgot to add initially, etc.), but I’m busy lately so I decided this was good enough for now.

How to Use

The module contains a dictionary where you can input the festivities the event will trigger on, as well as their starting date and their end date.

First thing you’ll do is input them there in your format of choice ({Month, Day, Hour, Minute}, or “Month/Day - Hour:Minute” (you’ll need to use the module in the example for the Digital one)), and once you are done you’ll have to detect said changes.

Example listening to events:

DateEvents.LocalDateUpdated:Connect(function(IsActive, IsLive, Festivity, DateTable)
	if IsActive == true and Festivity == "Christmas" then --It's christmas
		if IsLive == true then --We were in game on christmas
			LiveEventStart(true) --We get to see santa leaving us a gift
		end
		ShowDeco(true) --It'll appear regadless if we were not in-game
	elseif IsActive == false then --Christmas is over
		if IsLive == true then --We were in-game when it ended
			LiveEventStart(false) --We get to see Santa showing up with a flamethrower and burning our tree to ashes
		end
		ShowDeco(false) --Tree will be gone regardless of if we were in-game or not.
	end
end)

Example with Ifs:

--Formated Dates
local Start = "04/26 - 00:00"
local Expiration = "04/27 - 00:00"

--Dates to table
local TableStart = DateEvents.FromDigital(Start)
local TableExpiration = DateEvents.FromDigital(Expiration)

--Dates to unix
local CurrentUnix = DateEvents.GetUnixDate()
local StartUnix = DateEvents.ToUnix(TableStart)
local ExpirationUnix = DateEvents.ToUnix(TableExpiration)

--Christmas
if CurrentUnix >= StartUnix then --It's past christmas
	if CurrentUnix < ExpirationUnix then --Christmas is not over
		print("It's christmas") --We get coal for christmas :(
	end
end

Video:

Link:


Closing

And that’s about it for the bundle, nothing really amazing on it, but I hope someone out there finds one of these useful.

If you find my resources useful, I have have a Ko-Fi and a place for tips if you feel like dropping 3 bobux. I also have a bunch of other resources on my roblox profile (grappling hooks, automatic interactions system, a kit of cool invisible walls, a detective sorta game quest, etc), some of them available in the spanish side of the forums.

As always, if you find a bug or have a suggestion, hit me up down below and I’ll look into it when I can.

13 Likes

Small Update for 2 of the modules

Hub Creation Kit

  • The GetInfo module didn’t retry retrieving the info if it failed, now it retries 6 times by default.

Manual Translation Tool

  • The module now uses identifiers as opposed to a linear and strict dictionary, meaning the following should no longer be the case:
  • Rewrote the instructions and a small bit of the code to hoperfully be more easy to understand (fixed a couple typos too).

  • API remains the same when calling the module, but the structure of it changed, meaning you’ll have to rewrite your translations to fit it (old strict version is still in the place, but I discourage using it).

Legacy Structure:

--- Source Module (English on this example) ---

local LangTable = {
	
	["Strings"] = {
		GuiFrame.PlayButton, --"Play"
		GuiFrame.Dialogue --"Hello, how are you?"
	},
	
	["Audios"] = {
		RepStorage.Track1, --Song
		RepStorage.Track2 --SFX
	},
	
	["Images"] = {
		Workspace.Image1, --USA Flag
		Workspace.Image2 --Cube
	}
}

--- ES Module ---

local LangTable = {
	
	["Strings"] = {
		"Jugar",
		"Hola, ¿Cómo te va?"
	},
	
	["Audios"] = {
		RepStorage.Track1ES.SoundId, --Spanish dub of the song?
		false --Doesn't need a translation for this language
	},
	
	["Images"] = {
		Workspace.Image1.Image, --ES Flag
		false --Doesn't need a translation for this language
	}
}

New Structure:

--- Source Module (english on this example) ---

local LangTable = {
	
	["Strings"] = {
		{GuiFrame.PlayButton, "Play_Button"}, --"Play"
		{GuiFrame.Dialogue, "Dialogue_Prompt"} --"Hello, how are you?"
	},
	
	["Audios"] = {
		{RepStorage.Track1, "FinalBossTheme"}, --Sound
		{RepStorage.Track2, "ExplosionBoom"} --SFX
	},
	
	["Images"] = {
		{Workspace.Image1, "User flag"}, --USA Flag
		{Workspace.Image2, "The image of a cube"} --Cube
	}
}

--- ES Module ---

local LangTable = {
	
	["Strings"] = {
		{"Hola, ¿Cómo te va?", "Dialogue_Prompt"} --As you can see, order doesn't matter thanks to the identifier
		{"Jugar", "Play_Button"},
	},
	
	["Audios"] = {
		{RepStorage.Track1ES.SoundId, "FinalBossTheme"}, --Spanish dub of the song?
	}, --In this example I decided to not translate the SFX, so the source audio will be used instead
	
	["Images"] = {
		{Workspace.Image1.Image, "User flag"}, --ES Flag
	} --Same here, image will remain unchanged if not translated
}

Let me know if you have any issues with the update.

2 Likes