Using gettext with Javascript from PHP via XMLHttpRequest

孤人 提交于 2020-02-03 18:53:49

问题


I have an application mainly written in PHP. The translations are done using gettext().

There is a small JavaScript part which also contains strings to be translated. I wrote this simple but working method using XMLHttpRequest:

function gettext(string_to_translate) {
    var filename = get_php_script_folder() + 'gettext.php?string_to_translate=' + string_to_translate;
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.open("GET", filename, false);
    xmlhttp.send();
    if (xmlhttp.status === 200) {
        var translated_string = xmlhttp.responseText;
        return translated_string;
    } else {
        console.log("Error while translating " + string_to_translate + " Status " + xmlhttp.status);
        return string_to_translate; //Just give the original string.
    }

}

The php file is also quite simple:

require_once '../../default.php'; //configures gettext, session management, etc.
//TODO: support for ngettext might be added.
$string_to_translate = filter_input(INPUT_GET, 'string_to_translate', FILTER_SANITIZE_STRING);
$translated_string = gettext($string_to_translate);
echo $translated_string;

In the JavaScript I just call:

var input_box_form_default_reason = gettext("Vacation");
document.getElementById('input_box_form_reason').value = input_box_form_default_reason;

If I call this function synchronously [xmlhttp.open("GET", filename, false);] Firefox/Chrome warns me that:

[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.

So while this method works, it may cease to do so at any time.

But if I run the code async [xmlhttp.open("GET", filename, true);], then the next line will be executed before the result is there. The value will be undefined.

Is it feasable to make async XMLHttpRequest work in this context? Should I stick to synchronously fetching the values until some clever API is written? Should I write my JS files with PHP? (I hope not.)

PS:

  1. I do not use any framework like jQuery. That is a "religious" thing. I want to fully understand and maintain the whole codebase myself.

  2. I read the following questions, which did not answer mine:

    • Translation in JavaScript like gettext in PHP?

    • PHP Gettext in JavaScript, not working in extern JS file

    • Extract javascript gettext in Poedit?

    • How do I feed terms from a gettext dictionary into JavaScript?

    • javascript i18n with gettext and .po files (broken link)


回答1:


Yes, you need a callback!

function gettext(string_to_translate, obj, callback)
... //your original xmlhttprequest
xmlhttp.callback = callback;, add a callback to the xmlhttp

//set the readystate event that listens to changes in the ajax call
xmlhttp.onreadystatechange = function()
{
    //target found and request complete
    if (this.status === 200 && this.readyState == 4) {
        //send result to the callback function
        this.callback(obj, this.responseText);
    } else {
        console.log("Error while translating " + string_to_translate + " Status " + xmlhttp.status);
        this.callback(obj, string_to_translate);
    }
}

//callback function specific for this case.
function setValue(obj, value)
{
   obj.value = value;
}

To call this:

gettext("Vacation", document.getElementById('input_box_form_reason'), setValue);

An extended ajax function with callback

function ajax(url, method, json, callBack)
{
	//it supports get and post
	//returns parsed JSON, when json is set to true. | json accessible via this.JSON in the callBack
	//a callback can be attached where the this refers to the xmlHTTP
	//supply an url like you would in a get request: http://www.example.com/page.php?query=1
	//start the request with xmlDoc.fire.
	
	var xmlDoc = new XMLHttpRequest
	xmlDoc.JSON = json ? true : false;
	xmlDoc.error = true;
	xmlDoc.errorMessage = "";	
	xmlDoc.errorObj = {"error" : xmlDoc.error, "object" : "XMLHttpRequest", "message" : xmlDoc.errorMessage, "url" : url, "sync" : true, "method" : (method ? "POST" : "GET")};
	xmlDoc.url = url
	xmlDoc.method = method ? "post" : "get";
	
	xmlDoc.preserveWhiteSpace = true;

	if (method == "post")
	{
		xmlDoc.pUrl = url; 
		xmlDoc.pArg = "";
		if (url.match(/\?/)) //we need to filter out the arguments since the are send seperately. 
		{
			var splitted = url.split(/\?/);
			xmlDoc.pUrl = splitted[0];
			xmlDoc.pArg = "";
			for (var i = 1; i < splitted.length; i++)
			{
				xmlDoc.pArg += splitted[i];	//prevent additional questionmarks from being splitted.				
			}					
			
		}
		
		xmlDoc.open.apply(xmlDoc, ["post", xmlDoc.pUrl , true]); //set up the connection
		
		xmlDoc.setRequestHeader("Content-type", "application/x-www-form-urlencoded ; charset=UTF-8");
	}
	else
	{
		//get request, no special action need, just pass the url
		this.xmlDoc.open("get", url, true); //true for async
	}

	xmlDoc.onreadystatechange = readyStateXML.bind(xmlDoc, callBack);
	xmlDoc.setRequestHeader("Pragma", "no-cache");
	xmlDoc.setRequestHeader("Cache-Control", "no-cache, must-revalidate");
	
	xmlDoc.fire = fireXmlRequest; //set up fire function.
	
	return xmlDoc;
}

function fireXmlRequest()
{
	if (this.method == "post")
	{
		this.send(this.pArg); //post
	}
	else
	{
		this.send(null); //get
	}
}

function readyStateXML(callBack)
{
	if (this.readyState == 4)
	{
		//request completed, now check the returned data
		//We always assume that a request fails.
		if (this.errorMessage == "XML Not loaded." || this.errorMessage == "")
		{
			this.error = false; //set error to false, request succeeded.
			this.errorObj.error = false;			

			if (!this.responseXML && !this.JSON)
			{
				this.error = true;
				this.errorMessage = "invalid XML.";
				this.errorObj.error = this.error;
				this.errorObj.message = this.errorMessage;				
			}
			
			if (this.error == false)
			{
				this.xmlData = this.responseXML;
				
				if (this.JSON)
				{
					try
					{
						this.JSON = JSON.parse(this.responseText);
					}
					catch(err)
					{
						//JSON couldn't be parsed
						this.error = true;
						this.errorMessage = err.message + "<br />" + this.responseText;
						this.errorObj.error = this.error;
						this.errorObj.message = this.errorMessage;		
					}
				}
				
			}
			
			//404 or 400, not found error
			if (this.status == "400" || this.status == "404" || this.status == 400 || this.status == 404)
			{
				this.error = true;
				this.errorMessage = "404: The requested page isn't found.";
				this.errorObj.error = this.error;
				this.errorObj.message = this.errorMessage;				
			}
			else if(this.status == "500")
			{
				this.error = true;
				this.errorMessage = "500: Internal server error.";
				this.errorObj.error = this.error;
				this.errorObj.message = this.errorMessage;				
			}

			if (typeof(callBack) != "undefined")
			{
				callBack.call(this); //pass the xmlDoc object to the callBack
			}
		}
		else
		{
			alert("Error \n" + this.errorMessage);
			if (typeof(callBack) != "undefined")
			{
				callBack.call(this);
			}
		}
			
	}
	else
	{
		this.error = true;
		this.errorMessage = "XML Not loaded.";
		this.errorObj.error = this.error;
		this.errorObj.message = this.errorMessage;		
	}
}

//to use
ajx = ajax("index.php?query=1", "post", true, false, function(){/*callback*/});
   console.log(ajx);
   ajx.fire();



回答2:


JS is an event driven programming language. What you are missing is an event that gets triggered when your request is completed. You can bind an event “onreadystatechange” to your xmlhttp object that’ll get triggered every time readyState changes.

function gettext(string_to_translate) {
var filename = get_php_script_folder() + 'gettext.php?string_to_translate=' + string_to_translate;
var xmlhttp = new XMLHttpRequest();

xmlhttp.onreadystatechange = function() {
    if (xmlhttp.status === 200) {
        var translated_string = xmlhttp.responseText;
        document.getElementById('input_box_form_reason').value = translated_string;
    } else {
        console.log("Error while translating " + string_to_translate + " Status " + xmlhttp.status);
    }
};
xmlhttp.open("GET", filename);
xmlhttp.send();
}

I would suggest reading about JS events and Callbacks.




回答3:


As Mouser pointed out, there needs to be a callback. I edited my function as follows:

function gettext(string_to_translate, object, callback_function) {
    var filename = get_php_script_folder() + 'gettext.php?string_to_translate=' + string_to_translate;
    var xml_http_request = new XMLHttpRequest();

    /*
     * Default values:
     */
    if (undefined === callback_function) {
        callback_function = set_value;
    }
    /*
     * Input error handling:
     */
    if (typeof object !== "object") {
        console.log("Error:" + object + " is not an object.");
        return false;
    }
    if (typeof callback_function === "function") {
        xml_http_request.callback = callback_function; // add a callback to the xml_http_request
    } else {
        console.log("Error:" + callback_function + " is not a function.");
        return false;
    }

    xml_http_request.onreadystatechange = function ()
    {
        //target found and request complete
        if (this.status === 200 && this.readyState === 4) {
            //send result to the callback function
            this.callback(object, this.responseText);
        } else if (this.readyState === 4) {
            console.log("Error while translating " + string_to_translate + " Status " + xml_http_request.status);
            this.callback(object, string_to_translate);
        }
    };
    xml_http_request.open("GET", filename, true);
    xml_http_request.send();
}
//callback function specific for gettext
function set_value(object, value)
{
    object.value = value;
}

It can be called as follows:

gettext("Vacation", document.getElementById('input_box_form_reason'));

With "Vacation" being the string to be translated and input_box_form_reason being the object which value will be changed. For more flexibility in the assignment the set_value function might be modified. For complex translations and concatenations of text, gettext.php has to be optimized.



来源:https://stackoverflow.com/questions/46477165/using-gettext-with-javascript-from-php-via-xmlhttprequest

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!