通过XMLHttpRequest从PHP使用gettext与Javascript

3
我有一个主要用PHP编写的应用程序。使用gettext()进行翻译。
还有一小部分JavaScript,其中包含需要翻译的字符串。 我使用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.
    }

}

这个php文件也非常简单:

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;

在 JavaScript 中,我刚刚调用:
var input_box_form_default_reason = gettext("Vacation");
document.getElementById('input_box_form_reason').value = input_box_form_default_reason;

如果我同步调用这个函数[xmlhttp.open("GET", filename, false);],Firefox/Chrome会警告我:
[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/.

所以,虽然这种方法能够正常工作,但它可能随时停止工作。
但是,如果我异步运行代码 [xmlhttp.open("GET", filename, true);],那么下一行将在结果出现之前执行。 值将为未定义。
在这种情况下,使用异步XMLHttpRequest是否可行?还是我应该继续同步获取值,直到编写了一些聪明的API?
我应该用PHP编写我的JS文件吗?(我希望不是这样。)
附言:
  1. 我不使用像jQuery这样的框架。这是一种“宗教”信仰。我想要完全理解和维护整个代码库。

  2. 我阅读了以下问题,但没有回答我的问题:


2
个人而言,我使用PHP直接在页面源代码中填充JS数组,以便翻译任何需要翻译的字符串,这不依赖于任何AJAX请求。如果您有很多字符串,您还需要考虑很多请求,这可能会减慢您的应用程序速度。 - Mike
我同意。我加载一个包含翻译的 XML 文件,并使用 XPath 读取它们。 - Mouser
3个回答

3
是的,你需要一个回调函数!
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;
}

调用此函数:

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

一个带回调函数的扩展ajax函数

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();


1
谢谢!我只做了一些小改动:链接 - Bruno

2

JS是一种事件驱动的编程语言。你需要的是一个在请求完成时触发的事件。你可以将事件“onreadystatechange”绑定到你的xmlhttp对象上,每当readyState改变时就会触发。

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();
}

我建议阅读有关JS事件和回调的内容。

0
正如 Mouser 指出的那样,需要一个回调函数。 我已经编辑了我的函数,如下所示:
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;
}

可以按如下方式调用:

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

将字符串“Vacation”翻译并将其输入到input_box_form_reason对象中进行更改。为了使赋值更加灵活,可以修改set_value函数。对于复杂的文本翻译和连接,需要优化gettext.php。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接