Typewriter Module scrambles characters

I want to use the typewriter module from this tutorial.

(please don’t say to tell me to do it this way

for i = 1, #text do
    guiObject.Text = string.sub(guiObject.Text, 1, i)
    wait()
end

This is so I can have Localization support and utf8 support. That’s why I want to use this module instead of the traditional way)

The main issue is the fact that whenever there is a lag spike, the letters in the text scramble (is this some type of undocumented behavior? could it be a bug?).

I searched on the roblox api on utf8.graphemes, however, it only provides vague information for the function. Therefore, I am was unable to find a solution to my problem.

If anybody would like the code, here it is:

local SOURCE_LOCALE = "en"

local LocalizationService = game:GetService("LocalizationService")
local Players = game:GetService("Players")

local player = Players.LocalPlayer

local translator
pcall(function()
    translator = LocalizationService:GetTranslatorForPlayerAsync(player)
end)

if not translator then
    pcall(function()
	 translator = LocalizationService:GetTranslatorForLocaleAsync(SOURCE_LOCALE)
    end)
end

local TypeWriter = {}

local defaultConfigurations = {
    delayTime = 0.2,
    extraDelayOnSpace = true
}

function TypeWriter.configure(configurations)
    for key, value in pairs(defaultConfigurations) do
	   local newValue = configurations[key]
	   if newValue ~= nil then
	      defaultConfigurations[key] = newValue
	   else
	      warn(key .. " is not a valid configuration for TypeWriter module")
	   end
     end
end

function TypeWriter.typeWrite(guiObject, text)
    guiObject.AutoLocalize = false
    guiObject.Text = ""

   local displayText = text
   if translator then
      displayText = translator:Translate(guiObject, text)
  end
  for first, last in utf8.graphemes(displayText) do
     local grapheme = string.sub(displayText, first, last)
         guiObject.Text = guiObject.Text .. grapheme

        if defaultConfigurations.extraDelayOnSpace and grapheme == " " then
          wait(defaultConfigurations.delayTime)
       end
	
      wait(defaultConfigurations.delayTime)
   end
end

return TypeWriter

After some debugging, I can make sure that:

  • The text scrambling is NOT caused by translating the text (see displayText = translator:Translate(guiObject, text) in an if statement)
  • The scrambling occurs AFTER the translating (to be more specific, the iteration)
  • NO errors are being produced.
  • All GuiObjects and Text arguments passed to Typewriter.typeWrite is NOT nil
  • There is NO difference in results between string.sub from the string library and text:sub method

Why not try and incorporate the first loop posted above into the module. It seems evident that using utf8 probably won’t work and seems complicated. Instead just loop through the translated text using the strings length and subdividing the text like this perhaps?:

function TypeWriter.typeWrite(guiObject, text)
    guiObject.AutoLocalize = false
    guiObject.Text = ""

   local displayText = text
   if translator then
      displayText = translator:Translate(guiObject, text)
  end
  for stringIndex = 1,#displayText do
        guiObject.Text = displayText:sub(1,stringIndex)
        if defaultConfigurations.extraDelayOnSpace and grapheme == " " then
          wait(defaultConfigurations.delayTime)
       ens
      wait(defaultConfigurations.delayTime)
   end
end

OP didn’t do it because they don’t want to, their module needs to work with the specifications they laid out. I’m pretty sure they very explicitly explained why things are sorted the way they are in the script to prevent responses like this that almost ignore the post.

UTF8 is a library, so unless you use it wrong then there’s no reason for it not to work. Finding it complicated to work with doesn’t mean it should be removed.

Ah, I didn’t notice him asking for specifically utf8, I just thought he wanted it to be modularized. One option if it is caused by a bug would be to loop through the string and cache the graphemes without any yielding. This would minimize the chance that the graphemes iteration might be getting messed up, and its possible that even the yielding is causing. Then when you can loop through the graphemes saved in the table and do the yielding and displaying of the text, without risking any faults with retrieving the graphemes.