New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a function to verify the existence of the translation phrase or not #626

Closed
CrazyHackGUT opened this Issue Jun 22, 2017 · 15 comments

Comments

Projects
None yet
5 participants
@CrazyHackGUT
Contributor

CrazyHackGUT commented Jun 22, 2017

I would like to be able to check the existence of the phrase in the translation cache. Now this is impossible. If the phrase does not exist, the formatting functions fires a fatal error, and the function call is terminated.

P.S.: Sorry for my english. I'm from Russia.

@Benoist3012

This comment has been minimized.

Show comment
Hide comment
@Benoist3012

Benoist3012 Jun 22, 2017

Contributor

I don't think sourcemod has a check for that, however, @SourcemodDevs how about giving back the translation key into char var, instead of terminating the code execution?

Like:

"Command Access Refuse"
{
              "en" "You are not allowed to use this command."
}

Format(sBuffer, sizeof(sBuffer), "%t", "Command Access Refused"); PrintToChat(client, sBuffer);

Output: You are not allowed to use this command.

But if the translation doesn't exist do:

Output: #Command Access Refused.

Just like any source game with missing translations, only a suggestion though.

Contributor

Benoist3012 commented Jun 22, 2017

I don't think sourcemod has a check for that, however, @SourcemodDevs how about giving back the translation key into char var, instead of terminating the code execution?

Like:

"Command Access Refuse"
{
              "en" "You are not allowed to use this command."
}

Format(sBuffer, sizeof(sBuffer), "%t", "Command Access Refused"); PrintToChat(client, sBuffer);

Output: You are not allowed to use this command.

But if the translation doesn't exist do:

Output: #Command Access Refused.

Just like any source game with missing translations, only a suggestion though.

@joao7yt

This comment has been minimized.

Show comment
Hide comment
@joao7yt

joao7yt Jun 22, 2017

I think the main option would be awesome, then if the translation doesn't exists, we will be able to send a hard coded default English sentence. Please

joao7yt commented Jun 22, 2017

I think the main option would be awesome, then if the translation doesn't exists, we will be able to send a hard coded default English sentence. Please

@asherkin

This comment has been minimized.

Show comment
Hide comment
@asherkin

asherkin Jun 22, 2017

Member

What is your use case?

Generally, testing for programmer error (you're trying to use some other plugin's translation file) or user error (the user didn't update the translation file) is not something we want to support - it is very intentional that errors in SourcePawn are loud and halt execution.

Member

asherkin commented Jun 22, 2017

What is your use case?

Generally, testing for programmer error (you're trying to use some other plugin's translation file) or user error (the user didn't update the translation file) is not something we want to support - it is very intentional that errors in SourcePawn are loud and halt execution.

@asherkin asherkin changed the title from Feature request: Add a function to verify the existence of the translation phrase or not to Add a function to verify the existence of the translation phrase or not Jun 22, 2017

@joao7yt

This comment has been minimized.

Show comment
Hide comment
@joao7yt

joao7yt Jun 22, 2017

It would just create more possibilities and would create a way to scripters to prevent the plugin to stop the function just because a translation is missing

joao7yt commented Jun 22, 2017

It would just create more possibilities and would create a way to scripters to prevent the plugin to stop the function just because a translation is missing

@CrazyHackGUT

This comment has been minimized.

Show comment
Hide comment
@CrazyHackGUT

CrazyHackGUT Jun 23, 2017

Contributor

I'm writing plugin with config in KV format. This config looks like that:

"SomePlugin"
{
    "SomeSection"
    {
        "name" "MyName"
        "id"   "MyID"
        // <...>
    }

    // <...>

    "SomeSection999"
    {
        "name" "Example"
        "id"   "911"
        // <...>
    }
}

I want that if there is a translation of "Item_ID" (ex. Item_911) exists, then use him [translation] to draw in menu, else use name ("Example") from config.

Contributor

CrazyHackGUT commented Jun 23, 2017

I'm writing plugin with config in KV format. This config looks like that:

"SomePlugin"
{
    "SomeSection"
    {
        "name" "MyName"
        "id"   "MyID"
        // <...>
    }

    // <...>

    "SomeSection999"
    {
        "name" "Example"
        "id"   "911"
        // <...>
    }
}

I want that if there is a translation of "Item_ID" (ex. Item_911) exists, then use him [translation] to draw in menu, else use name ("Example") from config.

@joao7yt

This comment has been minimized.

Show comment
Hide comment
@joao7yt

joao7yt Jun 24, 2017

stock bool TranslationExists(char[] phrase, char[] file)
{
	char cfgFile[PLATFORM_MAX_PATH];
	char dirName[PLATFORM_MAX_PATH];
	
	BuildPath(Path_SM, dirName, PLATFORM_MAX_PATH, "translations");
	BuildPath(Path_SM, cfgFile, PLATFORM_MAX_PATH, "translations/%s.txt", file);
	
	if (!DirExists(dirName) || !FileExists(cfgFile))
	{
		return false;
	}
	
	Handle kv = CreateKeyValues("Phrases");
	FileToKeyValues(kv, cfgFile);
	
	if (KvJumpToKey(kv, phrase))
	{
		char bufferformat[255];
		KvGetString(kv, "#format", bufferformat, sizeof(bufferformat), "");
		
		bool contains[16];
		bool passed = false;
		if (!StrEqual(bufferformat, ""))
		{
			for (int i = 1; i < sizeof(contains); i++)
			{
				char buffer[4];
				Format(buffer, sizeof(buffer), "{%d:", i);
				if (StrContains(bufferformat, buffer) != -1)
				{
					passed = true;
					contains[i] = true;
				}
				else
				{
					contains[i] = false;
				}
			}
		}
		
		char bufferphrase[255];
		KvGetString(kv, langname, bufferphrase, sizeof(bufferphrase), "");
		
		if (StrEqual(bufferphrase, ""))
		{
			return false;
		}
		
		if (passed)
		{
			for (int i = 1; i < sizeof(contains); i++)
			{
				if (contains[i])
				{
					char buffer[4];
					Format(buffer, sizeof(buffer), "{%d}", i);
					if (StrContains(bufferphrase, buffer) == -1)
					{
						return false;
					}
				}
			}
		}
	}
	else
	{
		return false;
	}
	CloseHandle(kv);
	
	return true;
}

Call it like this:

if (TranslationExists("Changing map", "common.phrases"))
{
	PrintToChat(client, "%t", "Changing map", map)
}
else
{
	PrintToChat(client, "Changing map to %s...", map)
}

The function checks if the folder exists, if the file exists and if the phrase contains the needed format indexes.

joao7yt commented Jun 24, 2017

stock bool TranslationExists(char[] phrase, char[] file)
{
	char cfgFile[PLATFORM_MAX_PATH];
	char dirName[PLATFORM_MAX_PATH];
	
	BuildPath(Path_SM, dirName, PLATFORM_MAX_PATH, "translations");
	BuildPath(Path_SM, cfgFile, PLATFORM_MAX_PATH, "translations/%s.txt", file);
	
	if (!DirExists(dirName) || !FileExists(cfgFile))
	{
		return false;
	}
	
	Handle kv = CreateKeyValues("Phrases");
	FileToKeyValues(kv, cfgFile);
	
	if (KvJumpToKey(kv, phrase))
	{
		char bufferformat[255];
		KvGetString(kv, "#format", bufferformat, sizeof(bufferformat), "");
		
		bool contains[16];
		bool passed = false;
		if (!StrEqual(bufferformat, ""))
		{
			for (int i = 1; i < sizeof(contains); i++)
			{
				char buffer[4];
				Format(buffer, sizeof(buffer), "{%d:", i);
				if (StrContains(bufferformat, buffer) != -1)
				{
					passed = true;
					contains[i] = true;
				}
				else
				{
					contains[i] = false;
				}
			}
		}
		
		char bufferphrase[255];
		KvGetString(kv, langname, bufferphrase, sizeof(bufferphrase), "");
		
		if (StrEqual(bufferphrase, ""))
		{
			return false;
		}
		
		if (passed)
		{
			for (int i = 1; i < sizeof(contains); i++)
			{
				if (contains[i])
				{
					char buffer[4];
					Format(buffer, sizeof(buffer), "{%d}", i);
					if (StrContains(bufferphrase, buffer) == -1)
					{
						return false;
					}
				}
			}
		}
	}
	else
	{
		return false;
	}
	CloseHandle(kv);
	
	return true;
}

Call it like this:

if (TranslationExists("Changing map", "common.phrases"))
{
	PrintToChat(client, "%t", "Changing map", map)
}
else
{
	PrintToChat(client, "Changing map to %s...", map)
}

The function checks if the folder exists, if the file exists and if the phrase contains the needed format indexes.

@KyleSanderson

This comment has been minimized.

Show comment
Hide comment
@KyleSanderson

KyleSanderson Jun 24, 2017

Member

FormatTranslation is the better solution, and while I agree this is an area we need to work on, I need to defer to my peers on actual implementation.

Member

KyleSanderson commented Jun 24, 2017

FormatTranslation is the better solution, and while I agree this is an area we need to work on, I need to defer to my peers on actual implementation.

@joao7yt

This comment has been minimized.

Show comment
Hide comment
@joao7yt

joao7yt Jun 24, 2017

FormatTranslation? Don't know about it... What is that?

joao7yt commented Jun 24, 2017

FormatTranslation? Don't know about it... What is that?

@CrazyHackGUT

This comment has been minimized.

Show comment
Hide comment
@CrazyHackGUT

CrazyHackGUT Jun 25, 2017

Contributor

@joao7yt
1). KeyValues have a bug with case of letters. Read more here.
2). This is checks translation exists on file. But SourceMod parse file once when map changes. So if you add a phrase to a file, save, and run this function, check will succeed, but the format functions still throws an error because phrase not exists in cache.

We need check phrase existing in cache. Not in file.

Contributor

CrazyHackGUT commented Jun 25, 2017

@joao7yt
1). KeyValues have a bug with case of letters. Read more here.
2). This is checks translation exists on file. But SourceMod parse file once when map changes. So if you add a phrase to a file, save, and run this function, check will succeed, but the format functions still throws an error because phrase not exists in cache.

We need check phrase existing in cache. Not in file.

@joao7yt

This comment has been minimized.

Show comment
Hide comment
@joao7yt

joao7yt Jun 25, 2017

That's right, and I recoded using SMC Parser, see here: https://forums.alliedmods.net/showthread.php?t=298883

And about the cached translations, i don't have a clue how to get them, but I think the way it's right now, at least helps.

joao7yt commented Jun 25, 2017

That's right, and I recoded using SMC Parser, see here: https://forums.alliedmods.net/showthread.php?t=298883

And about the cached translations, i don't have a clue how to get them, but I think the way it's right now, at least helps.

@Benoist3012

This comment has been minimized.

Show comment
Hide comment
@Benoist3012

Benoist3012 Jun 25, 2017

Contributor

Honestly that would just be better to make my suggestion imo, instead of building custom stocks that are going to slow down our code.
Format(sBuffer, sizeof(sBuffer), "%t", "Command Access Refused");
If the translation for "Command Access Refused" exists, it gives back what's in the file:
custom translation here
and if it doesn't exist, it simply gives back to the plugin this string:
#Command Access Refused

So plugin can still run, and code execution isn't aborted.

And if possible make a function within the sm core, that does the same stuff that when it retrieves a translation phrase for the %t param, but instead returns true or false, if said translation exist.

Contributor

Benoist3012 commented Jun 25, 2017

Honestly that would just be better to make my suggestion imo, instead of building custom stocks that are going to slow down our code.
Format(sBuffer, sizeof(sBuffer), "%t", "Command Access Refused");
If the translation for "Command Access Refused" exists, it gives back what's in the file:
custom translation here
and if it doesn't exist, it simply gives back to the plugin this string:
#Command Access Refused

So plugin can still run, and code execution isn't aborted.

And if possible make a function within the sm core, that does the same stuff that when it retrieves a translation phrase for the %t param, but instead returns true or false, if said translation exist.

@asherkin

This comment has been minimized.

Show comment
Hide comment
@asherkin

asherkin Jun 26, 2017

Member

@Benoist3012 That does not work as the format implementation wouldn't know how many parameters to process.

Member

asherkin commented Jun 26, 2017

@Benoist3012 That does not work as the format implementation wouldn't know how many parameters to process.

@Benoist3012

This comment has been minimized.

Show comment
Hide comment
@Benoist3012

Benoist3012 Jun 26, 2017

Contributor

Oh yeah I didn't think about that, and isn't possible to make it ignore all parameters if translation is missing ?

Contributor

Benoist3012 commented Jun 26, 2017

Oh yeah I didn't think about that, and isn't possible to make it ignore all parameters if translation is missing ?

@joao7yt

This comment has been minimized.

Show comment
Hide comment
@joao7yt

joao7yt Jun 27, 2017

Hey guys, I updated the code, now it will cache the valid translations in an array. And it will simply check in that array if the translation is available in the client language, server language or English. Do you think it's less slow and less broken right now? Give me your feed back.

See here.

joao7yt commented Jun 27, 2017

Hey guys, I updated the code, now it will cache the valid translations in an array. And it will simply check in that array if the translation is available in the client language, server language or English. Do you think it's less slow and less broken right now? Give me your feed back.

See here.

Headline added a commit to Headline/sourcemod that referenced this issue Aug 23, 2017

KyleSanderson added a commit that referenced this issue Nov 21, 2017

Add Translation Natives (#669)
* Add Translation Natives

See #626

* Fix vocab errors
* Better description
* Bump ITranslator Version
* Implement KyleS' Review Requests
* Improve documentation
@CrazyHackGUT

This comment has been minimized.

Show comment
Hide comment
@CrazyHackGUT

CrazyHackGUT Nov 22, 2017

Contributor

I'm close the issue. Pull request #669 with needed natives has been merged,

Contributor

CrazyHackGUT commented Nov 22, 2017

I'm close the issue. Pull request #669 with needed natives has been merged,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment