[IGN-4876]System.util.translate takes too long

I have been implementing additional languages into the program and as I do, I’m noticing major slowdowns in loading times, even when it’s in English. This is especially true when it comes to
the use of system.util.translate. Has anyone else been having this issue? Is there a way to fix this or a workaround that anyone could suggest?

“Loading times” is very vague.
First, what visualization system are you using (Vision, or Perspective)?
Related to that, what are “loading times” - what action is ‘slow’ that you aren’t expecting?
Second, can you quantify “major slowdowns” a bit? Five seconds? Thirty seconds? Ten minutes?
Finally, how are you seeing system.util.translate impact loading times? What exactly are you using system.util.translate for?

I’m using perspective. Before adding the system.util.translate the page loaded really fast. I then went through and added system.util.translate all over the place and now it takes much longer to load; from about 1/10 of a second to like 3 or 4 seconds. And the parts components that don’t have the system.util.translate load in much faster, but the parts that have it take noticeably longer. I’m using it to translate text from one language to another.

I just tested it with a timer. Without system.util.translate, the page took a little more than 3 seconds to fully load. When I add the system.util.translate back in, it took 58 seconds to fully load. The elements that didn’t have it loaded pretty much right away, but then the ones with it popped in one by one.

Can you expand a little bit more on exactly how you’re using system.util.translate? Most Perspective components should automatically translate displayed text for you, and I’d expect that mechanism to be a whole lot faster (no roundtrip to the gateway is required).

We have things like this image that are several string concatenated and the different parts need to be translated. WO gets changed to 工作指示 and Boxes is changed to 盒子 for example.

Here is the code being used in an expression structure binding.

	try:
		locale = value.locale.split('-')[0]
		mode = value.mode
		wo = system.util.translate(str(value.wo), locale)
		product = system.util.translate(str(value.product), locale)
		qty = value.qty or 0.0
		units = system.util.translate(str(value.units), locale)
		
		if mode != 'Production':
			return ''
		
		if wo != '' and wo is not None:
			return 'WO# ' + wo + ' - ' + product + ' - {:,g} '.format(qty) + units
		
		if product is not None:
			return 'PC# ' + product + ' - {:,g} '.format(qty) + units
	except:
		pass
		
	return ''

EDIT: I forgot to mention this, but before running both tests, I cleared the cookies and did a hard refresh.

On a side note; if you try to use a string formatter ('{:s}'.format(units)) to format Chinese characters, it changes it from 盒子 to 盒子. This is not an issue on other python interpreters, but it is here. I don’t know if it’s a jython bug or an Ignition bug, but that took me WAY too long to figure out. It doesn’t happen with Spanish so I am thinking it is just an issue with non-alphabet languages.

You will just have to use the right encoding.

idk why its slowing down your screen so much tho.
Does this happen if you use the exact same script but comment out the translate and just use the value.wo ect? instead of system.util.translate(str(value.wo), locale)

not sure what the try except is trying to do
also i dont thing the if's are needed as a translate should never really return None (unless you set strict to true which you dont)

Also i see no loop in here.. are you translating all the data at once(you should) or on every label?(thats gonne be a lot of communication with the gateway)
Maybe its worth generating the data in a dataset tag and then create a translated dataset tag for each translation you have and dynamically grab those(and default to english if you find no translation). that should basicly eliminate any slowdown in the client, just a bit of more work for the gateway at first (but less the more clients there are) and a bit more memory used

Consider pre-translating all necessary static words into private session custom properties, where the translation is triggered only by changes in the locale. Then the heavily used expressions and transforms can simply reference {session.props.custom.translated.wo} or {session.props.custom.translated.pc} in a simple stringFormat() expression. (Bonus is that will avoid jython’s string interpolation in favor of java’s.)

(Possibly use an expression structure to generate session.props.custom.translated.* in one go.)

Yeah, unfortunately there’s a weakness in our implementation of system.util.translate here - the function can’t simply ask the gateway for a specific term, it has to load an entire ‘translation package’ (containing all your defined translations, across all locales) and then retrieve your single element. Every single call to system.util.translate is doing that.
You can use a script like the one I posted here to ‘bulk’ translate calls into a single roundtrip (and a single fetch of the translation package), or you can look into precalculating/caching translations in session properties, or you could use a modified version of the script I linked to cache the TranslationPackage in a top-level script constant.

2 Likes

I think we can make these functions a lot smarter so that workarounds like my other post aren’t necessary, so I’ve made a ticket to investigate this further.

3 Likes

So I’m working through the code in the example you linked and it’s not returning the translation.

In the Translation Manager, I added:

I set the language to zh-US:
image

I ran the code:

But it just returned the key that was passed in instead of the translation.

Changing strict = True didn’t return the translation either. It just returned null.

Changing locale = None had no effect at all.

Also, is there a way for it to just pass back the entire list of terms instead of me having to pass them all in manually?

https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.10/com/inductiveautomation/ignition/common/i18n/translation/TranslationPackage.html#getAllTranslations()
TranslationPackage has a variety of methods, you could use getAllTranslations to build up a dict of {key: {locale: translation} or {(key, locale): translation}, theoretically.
I would recommend doing that in a project script, not directly inside the tranform.

As for the script not working, you're splitting on underscores but supplying a locale separated with hyphens.

1 Like

You could try using the following class to transform a string into a locale, regardless of format:

from com.inductiveautomation.ignition.common.i18n import LocaleUtils
locale = LocaleUtils.parseLocale("zh-US").getOrThrow()
1 Like

I was having this same problem and after a little back and forth with Peter Lo from the Software Support Team, he addressed me to this topic.
I’ve tested the translate function you posted in the other topic and it works way better than system.util.translate. For example our project has gone from a 10 seconds delay to translate the elements of a drop-down list to about 2,5 seconds: it’s still quite a lot, but way better than before.

I’d be nice if this issue can be addressed in the next releases of Ignition, 'cause it’s pretty common to have to support more than one language and this weakness in the implementation of the default function is a big issue.

Thank you.

1 Like

May I ask for a code snippet showing how to use getAllTranslations? Thank you.

This is being treated as a pretty high priority issue and is expected to be picked up and worked on within the next ~4 weeks. If that does happen, this could go into 8.1.13. I would not rely on that, but that's the best case scenario.

Possible something like this, where you supply a locale and get a plain dictionary of terms : translations in return:

def getAllTerms(locale = None):
	"""
	Args:
		locale: A java.util.Locale
	Returns:
		dict: A mapping of translation terms to their translations for the given locale.
	"""
	from com.inductiveautomation.ignition.gateway import IgnitionGateway
	from com.inductiveautomation.ignition.gateway.script import GatewaySystemUtilities
	package = IgnitionGateway.get().getLocalizationManager().loadFullPackage()
	if locale is None:
		locale = GatewaySystemUtilities.LOCAL_LOCALE.get()

	return {
		translation.sourceTerm: translation.translation 
		for translation in package.getAllTranslations()
		if translation.locale == locale
	}
1 Like

On Python 2 strings are not Unicode, so in some cases I have added the following import statement to overcome that:

from __future__ import unicode_literals

Or prepend the str with a u:

u"{:s}".format(units)

Either way should work, but I prefer importing unicode_literals just so I don't have to prepend all my strs wit th u"".

2 Likes

Hello @PGriffith.
I’ve taken a look at version 8.1.13 changelog, but I didn’t see any update on this matter. Have you got any news about this issue?
Thank you!

No. Unfortunately, like I said, that was a best case scenario. The code changes haven’t happened yet, so at this point the earliest release with them would be 8.1.15; 8.1.14 is ‘frozen’ as the release candidate just went out.