Pull to refresh

Пишем многоязычное приложение Opera Unite (часть 1)

Reading time3 min
Views633
К сожалению, пока что Opera не поддерживает локализацию виджетов методом, предложенном в стандарте W3C, но даже если будет поддерживать, то это касается только серверной стороны, и, видимо, только языка сервера. Поэтому сделаем всё сами, учитывая, что языки браузера-сервера и браузера-клиента в общем случае разные.

Получение со стороны сервера языка отсылаемой к клиенту информации

Как определить язык клиента на сервере? — по заголовку HTTP Accept-Language. Как до него добраться? — через метод getRequestHeader или свойство headers объёкта типа WebServerRequest. А дальше его по алгоритму, описанному в RFC, обрабатывать? — да. Для этого я написал функцию, принимающую WebServerRequest и список поддерживаемых локализаций, и выдающую предпочитаемую клиентом локализацию:
function getLanguageNameForRequest(Request,SelectedArray){
	var HeaderCollection=Request.getRequestHeader("Accept-Language");
	var AcceptString="";
	if(HeaderCollection!=null)if(HeaderCollection.length>=1){
		//HeaderCollection является DOMStringList и не имеет метода join, поэтому порнография
		for(var i=0,AcceptString=HeaderCollection.item(0); i<HeaderCollection.length-1;){
			i++;
			AcceptString+=","+HeaderCollection.item(i);
		}
	}
	var AcceptArray=AcceptString.replace(" ","").split(",");
	//Смотри RFC2616,  #14.4 Accept-Language
	//http://tools.ietf.org/html/rfc2616#section-14.4
	var Lang=SelectedArray[0],Qu=-Infinity;
	for(var i in AcceptArray){
		var l,q,lq;
		lq=AcceptArray[i].split(";");
		l=lq[0];q=1;
		try{
			if(lq[1].substring(0,2)==="q="){
				q=parseFloat(lq[1].substring(2));
			}
		}catch(err){
			q=1;
		}
		if(SelectedArray.indexOf(l)>=0){
			if(q>Qu){
				Lang=l;
				Qu=q;
			}
		}
	}
	
	return Lang;
}
Пример вызова
Например, если клиент отправил в заголовке Accept-Language строку «ru,ru-RU;q=0.9,en;q=0.8,de;q=0.7», а на сервере поддерживаются языки «ru» и «en», то getLanguageNameForRequest вернёт «ru»:
window.onload = function () {opera.io.webserver.addEventListener('_index', function(RequestEvent){
	RequestEvent.connection.response.writeLine("Язык клиента: "+getLanguageNameForRequest(RequestEvent.connection.request,["ru","en"]));
	RequestEvent.connection.response.close();
}, false);}
Почему не использовать вместо всего этого UserAgent? Потому что в нём передаётся язык интерфейса браузера, а не страниц.

Получение со стороны сервера языка выводимой на сервер информации

Особенность технологии Opera Unite в том, что серверный скрипт взаимодействует не только с людьми, которые получают через браузеры-клиенты HTML, но и с человеком, который сидит за браузером-сервером, непосредственно через различные API, например отсылкой сообщений через widget.showNotification. К счастью, для серверного кода доступен тот же DOM, что и для обычной страницы, то есть window.navigator.language работает и выдаёт язык интерфейса браузера-сервера. Обёртываем в аналогичную предыдущему случаю функцию, выбирающую язык из доступных:
function getLanguageNameForServer(SelectedArray){
	var l=window.navigator.language
	return (SelectedArray.indexOf(l)>=0)?l:SelectedArray[0];
}

widget.showNotification("Язык сервера:"+getLanguageNameForServer(["en","ru","de"]));

Создание инфраструктуры для локализации приложения в целом

Так как одним из важнейших преимуществ Opera Unite является возможность использовать один и тот же код JavaScript одновременно и в серверной, и в клиентской частях приложения, то хотелось бы при создании API для локализации это свойство не потерять, то есть язык отдаваемых строк должен неявно определяться местом выполнения кода, который их просит. Об этом будет вторая часть поста, если я её напишу.
Tags:
Hubs:
Total votes 28: ↑20 and ↓8+12
Comments10

Articles