一. 簡介
作為一個兼職碼農,最近嘗試了自己的一個站點的多語言化。發現Laravel本身的locale設定(通過message或者json)適合靜態內容,對於文章等動態內容的多語言化還不能滿足。因此嘗試了通過jQuery結合NLP平臺來實現動態內容翻譯,已經基本實現功能。
二. Laravel部分
1) 在.env中設定預設語言和語言字首
APP_LOCALE=en
APP_LOCAL_PREFIX=
APP_LOCAL_PREFIX用於設定URL的預設語言字首,如果對於預設語言,不希望有語言字首,可以設定為空。
2)新建一個處理locale的middleware,並完成註冊。
public function handle(Request $request, Closure $next)
{
$locale=in_array($request->segment(1),['en','zh','jp','fr','de','kr'])? $request->segment(1):env('APP_LOCALE');
//Set locale
app()->setLocale($locale);
//Use session to store the prefix
if($locale===env('APP_LOCALE') and env('APP_LOCAL_PREFIX')=="")
session(['locale_prefix' => '']);
else
session(['locale_prefix' => $locale]);
return $next($request);
}
session('locale_prefix')
可以用來在連結的URL中動態增加prefix。
3)完成Route更新
Route::group([ 'middleware' => 'setlocale'], function() {
Route::get('/', function () {
return view('welcome');
});
});
Route::group(['prefix' => '{locale}', 'middleware' => 'setlocale'], function() {
Route::any('/', function(){
return view('welcome');
});
Route::any('/en', 'GMA\WebController@index')->name('home');
});
對於預設語言,如果不希望有prefix,則Route需要對於有prefix和沒有prefix兩種邏輯分別處理。如果對於預設語言也需要prefix,則僅需保留第二個Route Group。
4)NLP API,這裡採用騰訊AI平臺,程式碼不再贅述,Route設定路徑是/api/nlp
。
三. jQuery部分
var transObjects = $("[id^='trans']");
var text_array=new Array(transObjects.length);
for(let i=0;i<transObjects.length;i++){
text_array[i]=new Array();
//Clean each jQuery childNode's HTML data and collect the text into an array
getNodeText(transObjects[i],text_array[i]);
text_array[i]=text_array[i].join("\n");
}
// Join text from different divs into one string
var srcText = text_array.join('\n\n');
var transData={
'source' : source_lang,
'target' : target_lang,
'text' : srcText,
}
//Use Ajax to get translated text via Tencent AI Platform
var getTrans=$.ajax({
type: 'POST',
url: '/api/nlp',
data: transData,
success: function(data){
//split into contents for div
let responseText=data.data.target_text
text_array=responseText.split('\n\n')
//Processing each div
for(let i=0;i<transObjects.length;i++){
//split translated text into different jQuery childNodes
text_array[i]=text_array[i].split('\n');
updateNodeText(transObjects[i],text_array[i]);
}
},
dataType: 'json',
});
//Covert all jQuery childNodes' text to array
function getNodeText(TransObj,text_array){
for(let i=0;i<TransObj.childNodes.length;i++){
if(TransObj.childNodes[i].childNodes.length>0){
getNodeText(TransObj.childNodes[i],text_array);
}
else{
if(TransObj.childNodes[i].nodeName==="#text"){
let parsedText=delExtraSpaces(delNewlines(TransObj.childNodes[i].data));
if(parsedText!=="" && parsedText!==" ") text_array.push(parsedText);
}
}
}
}
//Update jQuery childNodes with translated text
function updateNodeText(TransObj,text_array){
for(let i=0;i<TransObj.childNodes.length;i++)
{
if(TransObj.childNodes[i].childNodes.length>0){
updateNodeText(TransObj.childNodes[i],text_array);
}
else{
if(TransObj.childNodes[i].nodeName==="#text"){
let parsedText=delExtraSpaces(delNewlines(TransObj.childNodes[i].data)).trim();
let sentenseEnd=['.','。','?','!'];
if(parsedText!=="" && parsedText!==" "){
if(text_array[0]!==undefined){
//check the last character of string, remove the . introduced by new line
if(!sentenseEnd.includes(parsedText.charAt(parsedText.length-1)) &&
sentenseEnd.includes(text_array[0].charAt(text_array[0].length-1)) ){
text_array[0]=" "+text_array[0].substring(0,text_array[0].length-2)+parsedText.charAt(parsedText.length-1)+" ";
}
TransObj.childNodes[i].data=" "+text_array[0];
}
text_array.shift();
}
}
}
}
}
//Remove all new line breaks
function delNewlines(nodeText){
if(nodeText.includes('\n')){
return delNewlines(nodeText.replace('\n',''));
}
return nodeText;
}
//Remove extra white spaces
function delExtraSpaces(nodeText){
if(nodeText.includes(' ')){
return delExtraSpaces(nodeText.replace(' ',' '));
}
return nodeText;
}
基本原理是通過jQuery獲取所有childNodes的內容,對於其中的文字內容進行預處理(刪除多餘的空格和所有換行符),然後用換行符作為拼接各個childNode內容的分隔符。拼接成一段文字後,通過ajax提交給NLP API翻譯,獲取翻譯內容後再用換行符分隔各個childNodes,然後更新內容。
四. 完整程式碼
完成程式碼見Github。
本作品採用《CC 協議》,轉載必須註明作者和本文連結