mirror of
https://github.com/zyphlar/organicmaps-locale-viewer.git
synced 2024-03-08 13:27:46 +00:00
995 lines
41 KiB
HTML
995 lines
41 KiB
HTML
<html>
|
|
<head>
|
|
<script src="https://code.jquery.com/jquery-3.6.1.min.js" integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" crossorigin="anonymous"></script>
|
|
|
|
<style type="text/css">
|
|
.badge {
|
|
--bs-badge-font-size: 0.9em;
|
|
--bs-badge-padding-y: 0.15em;
|
|
}
|
|
|
|
/*div.output .input-group { width: 55em; }*/
|
|
div.output {
|
|
width: 70%;
|
|
margin-bottom: 1em;
|
|
padding-bottom: 1em;
|
|
border-bottom: 1px dashed;
|
|
}
|
|
.btn.btn-xs {
|
|
--bs-btn-padding-y: .25rem;
|
|
--bs-btn-padding-x: .5rem;
|
|
--bs-btn-font-size: .5rem;
|
|
}
|
|
|
|
.tranString.badge {
|
|
height: 2.5em;
|
|
margin: 0 0.1em 0.2em;
|
|
}
|
|
.tranString input[type='text'] {
|
|
border-collapse: collapse;
|
|
border: none;
|
|
}
|
|
.tranString input[type='text'][readonly] {
|
|
background: transparent;
|
|
color: white;
|
|
}
|
|
.tranString span.stringTxt {
|
|
line-height: 1.49em;
|
|
font-weight: normal;
|
|
}
|
|
.tranString .contextPhoto {
|
|
height: 1.8em;
|
|
margin-right: 0.5em;
|
|
border: 1px solid RGBA(13,110,253,1);
|
|
cursor: help;
|
|
}
|
|
.tranString .contextPhoto.enlarged {
|
|
height: 150px;
|
|
float: left;
|
|
position: relative;
|
|
z-index: 999;
|
|
}
|
|
.buttonwrapper {
|
|
display: inline-block;
|
|
width: 2em;
|
|
}
|
|
.wide { width: 18em; }
|
|
.narrow { width: 7em; }
|
|
.text-bg-warning { background-color: RGBA(183,138,2,var(--bs-bg-opacity,1)) !important }
|
|
.distance {
|
|
font-weight: bold;
|
|
padding: 0.2em;
|
|
color: white;
|
|
background-color: rgba(255,255,255,0.2);
|
|
margin-right: 1em;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body style="padding: 1em;">
|
|
<div style="position: fixed; top: 0; right: 0; width: 30%; z-index: 999; background: white; border: 1px solid gray; padding: 1em;">
|
|
<h3 style="font-size: 1.5em;">Organic Maps Locale Viewer / Editor</h3>
|
|
<p>Don't worry about adding or removing periods like <span class="badge bg-secondary">.</span> <span class="badge bg-secondary">。</span>(Japanese) or <span class="badge bg-secondary">।</span>(Hindi) at the end of strings. They are automatically removed as appropriate. <br/>You may hover over phrases to see their English version in a popup. Right-to-left languages may not be displayed correctly. Click the edit button next to a string and then click the save button to make changes. <br/><b>Your changes are not saved anywhere,</b> so copy the change request that appears below when you're ready.</p>
|
|
<b>Locale language:</b>
|
|
<select id="localeSelect" class="form-control">
|
|
<option value="ar">ﺎﻠﻋﺮﺒﻳﺓ</option>
|
|
<option value="be">Беларусь</option>
|
|
<option value="ca">Català</option>
|
|
<option value="cs">Čeština</option>
|
|
<option value="da">Dansk</option>
|
|
<option value="de">Deutsch</option>
|
|
<option value="el">Ελληνικά</option>
|
|
<option value="en">English</option>
|
|
<option value="es">Español</option>
|
|
<option value="es-MX">Español (MX)</option>
|
|
<option value="eu">Euskara</option>
|
|
<option value="fa">ﻑﺍﺮﺴﯾ</option>
|
|
<option value="fi">Suomi</option>
|
|
<option value="fr">Français</option>
|
|
<option value="hi">हिंदी</option>
|
|
<option value="hr">Hrvatski</option>
|
|
<option value="hu">Magyar</option>
|
|
<option value="id">Indonesia</option>
|
|
<option value="it">Italiano</option>
|
|
<option value="ja">日本語</option>
|
|
<option value="ko">한국어</option>
|
|
<option value="mr">मराठी</option>
|
|
<option value="nb">Norsk</option>
|
|
<option value="nl">Nederlands</option>
|
|
<option value="pl">Polski</option>
|
|
<option value="pt">Português</option>
|
|
<option value="pt-BR">Português (BR)</option>
|
|
<option value="ro">Română</option>
|
|
<option value="ru">Русский</option>
|
|
<option value="sk">Slovenčina</option>
|
|
<option value="sv">Svenska</option>
|
|
<option value="sw">Kiswahili</option>
|
|
<option value="th">ภาษาไทย</option>
|
|
<option value="tr">Türkçe</option>
|
|
<option value="uk">Українська</option>
|
|
<option value="vi">Tiếng Việt</option>
|
|
<option value="zh-Hans">中文简体</option>
|
|
<option value="zh-Hant">中文繁體</option>
|
|
</select><br/>
|
|
<!--TTS Voice: <select id="voiceSelect" class="form-control"></select><br/><br/>-->
|
|
|
|
<!--
|
|
<a id="sourceUrl" href="#" target="_blank">json</a><br/>
|
|
<a href="https://github.com/organicmaps/organicmaps/blob/ada410b5825e2dfd7c1ed95d539292dcef7d09dc/data/strings/sound.txt" target="_blank">sound.txt</a><br/>
|
|
<em>Please propose any fixes by editing sound.txt or by adding a comment to the <a href="https://github.com/organicmaps/organicmaps/pull/3130">pull request</a></em>
|
|
-->
|
|
|
|
<!-- position: absolute; z-index: 999; padding: 1em; box-shadow: 2px 2px 6px #999; top: 20%; left: 20%; width: 60%; background: white; border: 1px solid black;" -->
|
|
<div id="submitpopup" style="display: none;">
|
|
<b>Copy this text: </b><button address="any text" class="btn btn-sm btn-primary copyToClipboard"><span>Copy</span></button>
|
|
<textarea class="form-control" style="height: 20em; font-family: monospace; font-size: 0.7em"></textarea>
|
|
<p><b>Then,</b> paste it into a new comment on <a href="https://github.com/organicmaps/organicmaps/pull/3130" target="_blank">this Github pull request</a></p>
|
|
<!--
|
|
<p style="text-align: center; margin-top: 2em;">
|
|
<button id="closesubmitpopup" class="btn btn-danger">Done</button>
|
|
</p>
|
|
-->
|
|
</div>
|
|
</div>
|
|
|
|
<div class="output" id="out-f"></div>
|
|
<div class="output" id="out-e"></div>
|
|
<div class="output" id="out-g"></div>
|
|
<div class="output" id="out-h"></div>
|
|
<div class="output" id="out-d"></div>
|
|
<div class="output" id="out-c"></div>
|
|
<div class="output" id="out-b"></div>
|
|
<div class="output" id="out-a"></div>
|
|
|
|
<script type="text/javascript">
|
|
const synth = window.speechSynthesis;
|
|
var voices;
|
|
|
|
function loadTts(){
|
|
voices = synth.getVoices();
|
|
$.each(voices, function(i, voice){
|
|
$("#voiceSelect").append('<option value="'+i+'" lang="'+voice.lang+'">'+voice.name+'</option>');
|
|
});
|
|
if (voices.length == 0) {
|
|
$("#voiceSelect").attr("disabled", "disabled").after('<em>Try another browser to use TTS, or install TTS support for this browser.</em>');
|
|
window.hideTts = true;
|
|
}
|
|
|
|
let params = new URLSearchParams(document.location.search);
|
|
let lang = params.get("lang");
|
|
let tts = params.get("tts");
|
|
|
|
const userLocale =
|
|
navigator.languages && navigator.languages.length
|
|
? navigator.languages[0]
|
|
: navigator.language;
|
|
|
|
if (lang) {
|
|
$("#localeSelect").val(lang);
|
|
} else {
|
|
$("#localeSelect option").each(function(i, o){
|
|
if (userLocale.match($(o).attr('value'))) {
|
|
$("#localeSelect").val($(o).attr('value'));
|
|
}
|
|
});
|
|
}
|
|
if (tts) {
|
|
$("#voiceSelect").val(tts);
|
|
} else {
|
|
if (lang) {
|
|
$("#voiceSelect option").each(function(i, o){
|
|
// console.log(lang,$(o).attr('lang').substr(0,2));
|
|
if (lang.match($(o).attr('lang').substr(0,2))) {
|
|
// console.log("got it");
|
|
$("#voiceSelect").val($(o).attr('value'));
|
|
return false;
|
|
}
|
|
});
|
|
} else {
|
|
$("#voiceSelect option").each(function(i, o){
|
|
// console.log(userLocale,$(o).attr('lang'));
|
|
if (userLocale.match($(o).attr('lang'))) {
|
|
$("#voiceSelect").val($(o).attr('value'));
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
$("#localeSelect").change(function(){
|
|
showData();
|
|
params.set('lang', $("#localeSelect").val());
|
|
document.location.search = params.toString();
|
|
});
|
|
|
|
$("#voiceSelect").change(function(){
|
|
loadTts();
|
|
// params.set('tts', $("#voiceSelect").val());
|
|
// document.location.search = params.toString();
|
|
});
|
|
|
|
loadLocale();
|
|
}
|
|
|
|
$(document).ready(function(){ loadTts(); });
|
|
|
|
</script>
|
|
|
|
<div class="modal fade" id="fmtModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<form id="fmtModalForm">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="exampleModalLabel">Edit Complex TTS String</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<label for="exampleInputEmail1" class="form-label">TTS String</label>
|
|
<input type="text" class="form-control" id="fmtModalText" aria-describedby="fmtModalDesc">
|
|
<div id="fmtModalDesc" class="form-text">
|
|
Formatter strings use numbered variables like <span class="badge bg-secondary">%1$s</span> to indicate parts that should be replaced by other text.
|
|
<ul>
|
|
<li><span class="badge text-bg-warning">%1$s</span> will be replaced by the distance translation string, like "in 500 meters."</li>
|
|
<li><span class="badge text-bg-primary">%2$s</span> will be replaced by the direction translation string, like "make a right turn." <i>For languages that use different grammar for sentences like "in 100 feet, make a right turn onto Main Street" versus "in 100 feet, make a right turn" an optional string like <code>make_a_right_turn_street</code> can replace the default <code>make_a_right_turn</code> string.</i></li>
|
|
<li><span class="badge text-bg-secondary">%3$s</span> will be dynamically replaced by the name or number of the street or exit, like "Main Street" or "Exit 123."</li>
|
|
<li><span class="badge text-bg-danger">%4$s</span> is optional and is used for languages that split their grammar for sentences like "in 100 feet, make a right turn onto Main Street" into two parts, like "make in 100 feet a right turn onto Main Street". Optional strings like <code>make_a_right_turn_street_verb</code> may be defined for this purpose.</li>
|
|
</ul>
|
|
For example "<span class="badge text-bg-warning">%1$s</span> <span class="badge text-bg-primary">%2$s</span> onto <span class="badge text-bg-secondary">%3$s</span>"<br/> becomes "<span class="badge text-bg-warning">In 500 meters</span> <span class="badge text-bg-primary">make a right turn</span> onto <span class="badge text-bg-secondary">Main Street</span>"<br/><br/>
|
|
whereas "<span class="badge text-bg-danger">%4$s</span> onto <span class="badge text-bg-secondary">%3$s</span> a <span class="badge text-bg-primary">%2$s</span> when you reach it <span class="badge text-bg-warning">%1$s</span>"<br/> can become "<span class="badge text-bg-danger">Make</span> onto <span class="badge text-bg-secondary">Main Street</span> a <span class="badge text-bg-primary">right turn</span> when you reach it <span class="badge text-bg-warning">in 500 meters</span>." with the help of <code>_street</code> and <code>_street_verb</code> strings.
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<input type="submit" class="btn btn-primary" value="Save changes" />
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<script type="text/javascript">
|
|
function parseSoundTxt(raw) {
|
|
var lines = raw.split("\n");
|
|
var thisSection = "";
|
|
var out = {};
|
|
|
|
for (var i=0;i<lines.length;i++) {
|
|
var line = lines[i];
|
|
|
|
var sectionMatch = line.match(/\s+\[(\w+)\]/);
|
|
var stringMatch = line.match(/\s+([\w\-]+) = (.+)/);
|
|
|
|
if (sectionMatch && sectionMatch.length > 1) {
|
|
thisSection = sectionMatch[1];
|
|
} else if (stringMatch && stringMatch.length > 2) {
|
|
if (!out[stringMatch[1]]) {
|
|
out[stringMatch[1]] = {};
|
|
}
|
|
out[stringMatch[1]][thisSection] = stringMatch[2];
|
|
} else {
|
|
console.log("no text parser match:", line);
|
|
}
|
|
}
|
|
console.log(out);
|
|
|
|
return out;
|
|
}
|
|
|
|
function buildTranStringInput(key, value, color="text-bg-primary", editable=true) {
|
|
var classes = "stringTxt";
|
|
|
|
if (!value)
|
|
return "";
|
|
|
|
var size = value.length+8;
|
|
|
|
var english = "key: "+key;
|
|
var englishVersion = window.originalEnglishData[key];
|
|
if (englishVersion) {
|
|
english += "\nen: "+englishVersion;
|
|
}
|
|
|
|
var out = "<span class='tranString badge "+color+"'>";
|
|
|
|
// display "then" icon
|
|
if (key == "then"){
|
|
out += "<span class='distance'>...</span>";
|
|
}
|
|
|
|
// display distance icon
|
|
if (key.substring(0,3) == "in_"){
|
|
var dist = key.replace(/in_|_meters|_kilometers|_kilometer|_feet|_miles|_mile/g, '').replace(/_/g, '.');
|
|
var unit = "";
|
|
if (key.includes("kilo")){
|
|
unit = "km";
|
|
} else if (key.includes("meter")){
|
|
unit = "m";
|
|
} else if (key.includes("feet")){
|
|
unit = "ft";
|
|
} else if (key.includes("mile")){
|
|
unit = "mi";
|
|
}
|
|
out += "<span class='distance'>"+dist+unit+"</span>";
|
|
}
|
|
|
|
const imagesArr = {
|
|
"take_the_1_exit": "ic_turn_round_exit_1",
|
|
"take_the_2_exit": "ic_turn_round_exit_2",
|
|
"take_the_3_exit": "ic_turn_round_exit_3",
|
|
"take_the_4_exit": "ic_turn_round_exit_4",
|
|
"take_the_5_exit": "ic_turn_round_exit_5",
|
|
"take_the_6_exit": "ic_turn_round_exit_6",
|
|
"take_the_7_exit": "ic_turn_round_exit_7",
|
|
"take_the_8_exit": "ic_turn_round_exit_8",
|
|
"take_the_9_exit": "ic_turn_round_exit_9",
|
|
"take_the_10_exit": "ic_turn_round_exit_10",
|
|
"take_the_11_exit": "ic_turn_round_exit_11",
|
|
"make_a_slight_right_turn": "ic_turn_right_slight",
|
|
"make_a_right_turn": "ic_turn_right",
|
|
"make_a_sharp_right_turn": "ic_turn_right_sharp",
|
|
"enter_the_roundabout": "ic_turn_round_enter",
|
|
"leave_the_roundabout": "ic_turn_round_exit",
|
|
"make_a_slight_left_turn": "ic_turn_left_slight",
|
|
"make_a_left_turn": "ic_turn_left",
|
|
"make_a_sharp_left_turn": "ic_turn_left_sharp",
|
|
"make_a_u_turn": "ic_turn_uleft",
|
|
"go_straight": "ic_turn_straight",
|
|
"exit": "ic_exit_highway_to_right",
|
|
// "onto",
|
|
"take_exit_number": "ic_exit_highway_to_right",
|
|
// "onto_exit_number",
|
|
"destination": "ic_turn_finish",
|
|
"you_have_reached_the_destination": "ic_turn_finish",
|
|
"unknown_camera": "camera"
|
|
};
|
|
|
|
// _street_verb and _street use the same icons
|
|
var imageKey = key.replace(/_street_verb|_street/g, '');
|
|
|
|
if (img = imagesArr[imageKey]){
|
|
|
|
// poorly detect left/right driving based on user's browser timezone for iconography
|
|
// (the browser being used tells us about the user, versus the language being selected)
|
|
var browserTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
if (
|
|
browserTimezone.includes("Nassau") || // Bahamas
|
|
browserTimezone.includes("Jamaica") ||
|
|
browserTimezone.includes("Guyana") ||
|
|
browserTimezone.includes("Paramaribo") || // Suriname
|
|
browserTimezone.includes("Stanley") || // Falkland
|
|
browserTimezone.includes("London") || // UK
|
|
browserTimezone.includes("GB") || // UK
|
|
browserTimezone.includes("Dublin") || // Ireland
|
|
browserTimezone.includes("Eire") ||
|
|
browserTimezone.includes("Windhoek") || // Namibia
|
|
browserTimezone.includes("Johannesburg") || // South Africa
|
|
browserTimezone.includes("Maputo") || // Mozambique, Botswana, Malawi, Zambia, Zimbabwe (NOT: Burundi, DRC, Rwanda)
|
|
browserTimezone.includes("Blantyre") || // Malawi
|
|
browserTimezone.includes("Nairobi") || // Kenya, Uganda, Tanzania (NOT: Somalia, Madagascar, Comoros, Ethiopia, Eritrea, Djibouti)
|
|
browserTimezone.includes("Mbabane") || // Swaziland
|
|
browserTimezone.includes("Maseru") || // Lesotho
|
|
browserTimezone.includes("Nicosia") || // Cyprus
|
|
browserTimezone.includes("Famagusta") || // Cyprus
|
|
browserTimezone.includes("Karachi") || // Pakistan
|
|
browserTimezone.includes("Kolkata") || // India
|
|
browserTimezone.includes("Katmandu") || // Nepal
|
|
browserTimezone.includes("Thimphu") || // Bhutan
|
|
browserTimezone.includes("Dhaka") || // Bangladesh
|
|
browserTimezone.includes("Colombo") || // Sri Lanka
|
|
browserTimezone.includes("Bangkok") || // Thailand
|
|
browserTimezone.includes("Tokyo") || // Japan
|
|
browserTimezone.includes("Japan") ||
|
|
browserTimezone.includes("Jakarta") || // Indonesia
|
|
browserTimezone.includes("Jayapura") ||
|
|
browserTimezone.includes("Makassar") ||
|
|
browserTimezone.includes("Pontianak") ||
|
|
browserTimezone.includes("Singapore") || // and Malaysia
|
|
browserTimezone.includes("Bougainville") || // Papua New Guinea
|
|
browserTimezone.includes("Port_Moresby") ||
|
|
browserTimezone.includes("Australia") ||
|
|
browserTimezone.includes("Auckland") || // New Zealand
|
|
browserTimezone.includes("Chatham") ||
|
|
browserTimezone.includes("Fiji") ||
|
|
browserTimezone.includes("Pago_Pago")
|
|
){
|
|
imagesArr["make_a_u_turn"] = "ic_turn_uright";
|
|
imagesArr["exit"] = "ic_exit_highway_to_left";
|
|
}
|
|
|
|
var imageAlt = img.replace(/ic_|turn_/g, '')
|
|
.replace(/round/g, 'roundabout').replace(/uleft|uright/g, 'u-turn')
|
|
.replace(/highway_to_left|highway_to_right/g, 'highway').replace(/_/g, ' ');
|
|
|
|
out += "<img alt='"+imageAlt+"' title='"+imageAlt+"' src='img/"+img+".webp' style='height: 1.5em; margin-right: 1em' />";
|
|
}
|
|
|
|
if (value.includes("I 278")) {
|
|
out += "<img class='contextPhoto' src='img/exit-i278-brooklynqueensexpressway,48street-brooklyn.png' />";
|
|
} else if (value.includes("H1 East")) {
|
|
out += "<img class='contextPhoto' src='img/exit-h1-east-airport.png' />";
|
|
} else if (value.includes("3: D19")) {
|
|
out += "<img class='contextPhoto' src='img/exit-3-d19-maisons-alfort-alfortville-stmaurice.png' />";
|
|
} else if (value.includes("5: I 280")) {
|
|
out += "<img class='contextPhoto' src='img/exit-5-i280-i680.png' />";
|
|
} else if (value.includes("19: NY 25")) {
|
|
out += "<img class='contextPhoto' src='img/exit-19-ny25-woodhavenboulevard-queensboulevard.png' />";
|
|
} else if (value.includes("13B: Halawa")) {
|
|
out += "<img class='contextPhoto' src='img/exit-13B-halawaheights-stadium.png' />";
|
|
} else if (value.includes("172: Priest")) {
|
|
out += "<img class='contextPhoto' src='img/exit-172-priest-drive.png' />";
|
|
}
|
|
|
|
if (editable) {
|
|
var valueEl = document.createElement("input");
|
|
valueEl.setAttribute("type", "text");
|
|
valueEl.setAttribute("class", classes);
|
|
valueEl.setAttribute("size", size);
|
|
valueEl.setAttribute("readonly", true);
|
|
valueEl.setAttribute("data-key", key);
|
|
valueEl.setAttribute("title", english);
|
|
valueEl.setAttribute("value", value);
|
|
out += valueEl.outerHTML;
|
|
out += "<span class='buttonwrapper'><button class='editbutton btn btn-xs btn-light text-warning' type='button' style='display:none;'><i class='bi bi-pencil-fill'></i></button><button class='savebutton btn btn-xs btn-light text-success' style='display: none;' type='button'><i class='bi bi-check-lg'></i></button></span>";
|
|
} else {
|
|
var valueEl = document.createElement("span");
|
|
valueEl.setAttribute("class", classes);
|
|
valueEl.setAttribute("data-key", key);
|
|
valueEl.setAttribute("title", english);
|
|
valueEl.innerText = value;
|
|
out += valueEl.outerHTML;
|
|
}
|
|
|
|
out += "</span>";
|
|
|
|
return out;
|
|
}
|
|
|
|
function buildFmtStringInput(key, value, color="text-bg-primary", fmtKey, editable=true) {
|
|
var classes = "stringTxt";
|
|
|
|
// replace RTL chars with their HTML equivalent
|
|
value = value.replace("\\u202C", "‬");
|
|
|
|
var out = "<span class='tranString badge "+color+"'><span type='text' class='"+classes+"' readonly data-key='"+
|
|
key +
|
|
"' data-fmtkey='" +
|
|
fmtKey +
|
|
"'>" +
|
|
value +
|
|
"</span>";
|
|
|
|
if (editable) {
|
|
out += "<span class='buttonwrapper'><button class='fmteditbutton btn btn-xs btn-light text-warning' type='button' style='display:none;'><i class='bi bi-pencil-fill'></i></button></span>";
|
|
}
|
|
|
|
out += "</span>";
|
|
|
|
return out;
|
|
}
|
|
|
|
function loadEventHandlers(){
|
|
|
|
$(".contextPhoto").hover(function(){
|
|
$(this).addClass("enlarged");
|
|
}, function(){
|
|
$(this).removeClass("enlarged");
|
|
});
|
|
|
|
$(".tranString").hover(function(){
|
|
let editBtn = $(this).children(".buttonwrapper").find(".editbutton");
|
|
if (editBtn.prop("disabled") == false) {
|
|
editBtn.show(); // only show when not disabled
|
|
}
|
|
let ttsEditBtn = $(this).children(".buttonwrapper").find(".fmteditbutton");
|
|
if (ttsEditBtn.prop("disabled") == false) {
|
|
ttsEditBtn.show(); // only show when not disabled
|
|
}
|
|
}, function(){
|
|
$(this).children(".buttonwrapper").find(".editbutton").hide();
|
|
$(this).children(".buttonwrapper").find(".fmteditbutton").hide();
|
|
});
|
|
|
|
$(".stringTxt").on('keyup', function (e) {
|
|
// handle enter = save
|
|
if (e.key === 'Enter' || e.keyCode === 13) {
|
|
$(this).siblings().find(".savebutton").click();
|
|
$(this).blur();
|
|
}
|
|
|
|
// adjust input size by text content
|
|
var size = $(this).val().length;
|
|
$(this).attr('size', size+8);
|
|
|
|
}).dblclick(function(){
|
|
$(this).siblings().find(".editbutton").click();
|
|
});
|
|
|
|
$(".editbutton").click(function(){
|
|
$(this).parent().siblings(".stringTxt").prop("readonly",false).focus();
|
|
$(this).prop("disabled",true).hide();
|
|
$(this).siblings(".savebutton").show();
|
|
});
|
|
|
|
$(".fmteditbutton").click(function(){
|
|
// for dist_direction_onto_street only
|
|
$(document.getElementById('fmtModalText')).val(window.modifiedSoundData['dist_direction_onto_street']);
|
|
$("#fmtModal").modal('show');
|
|
});
|
|
|
|
$(".savebutton").click(function(){
|
|
var changes = [];
|
|
|
|
$(this).parent().siblings(".stringTxt").prop("readonly",true);
|
|
$(this).hide();
|
|
$(this).siblings(".editbutton").prop("disabled",false).show();
|
|
|
|
var stringTxt = $(this).parent().siblings(".stringTxt")[0];
|
|
|
|
window.modifiedSoundData[$(stringTxt).data("key")] = $(stringTxt).val();
|
|
|
|
var soundKeys = Object.keys(window.originalSoundData);
|
|
var out = "";
|
|
var locale = $("#localeSelect").val();
|
|
|
|
for (i=0;i<soundKeys.length;i++) {
|
|
var soundKey = soundKeys[i];
|
|
var orig = window.originalSoundData[soundKey];
|
|
var mod = window.modifiedSoundData[soundKey];
|
|
|
|
if (mod != orig) {
|
|
out += " [" + soundKey + "]\n" +
|
|
"- " + locale + " = " + orig + "\n" +
|
|
"+ " + locale + " = " + mod + "\n";
|
|
$(".stringTxt[data-key='"+soundKey+"']").val(mod); // update all instances
|
|
}
|
|
|
|
}
|
|
|
|
$("#submitpopup textarea").text("Translation change request:\n```\n"+
|
|
"# data/strings/sound.txt\n" + out + "```"
|
|
);
|
|
$("#submitpopup").show();
|
|
|
|
});
|
|
|
|
|
|
$('.copyToClipboard').click(function () {
|
|
$('#submitpopup textarea').select();
|
|
document.execCommand('copy');
|
|
$(this).addClass("btn-success").text("Copied!");
|
|
});
|
|
|
|
$(".playtts").click(function(){
|
|
var myText = "";
|
|
var strings = $(this).siblings(".form-control").find(".stringTxt");
|
|
for (i=0;i<strings.length;i++) {
|
|
var string = strings[i];
|
|
// remove preceding periods from TTS text
|
|
if (myText.endsWith(".") || myText.endsWith("。") || myText.endsWith("।")) {
|
|
myText = myText.slice(0, -1);
|
|
}
|
|
if (i > 0) {
|
|
// add comma and whitespace between TTS strings
|
|
myText += ", " + $(string).val();
|
|
} else {
|
|
myText += $(string).val();
|
|
}
|
|
}
|
|
|
|
console.log("Speaking", myText);
|
|
|
|
const msg = new SpeechSynthesisUtterance(
|
|
myText
|
|
);
|
|
msg.voice = voices[$("#voiceSelect").val()];
|
|
synth.speak(msg);
|
|
});
|
|
if (window.hideTts) {
|
|
$(".playtts").hide();
|
|
}
|
|
}
|
|
|
|
function showData(){
|
|
var locale = $("#localeSelect").val();
|
|
var data = parseSoundTxt(window.soundTxtRaw)[locale];
|
|
window.originalEnglishData = parseSoundTxt(window.soundTxtRaw)['en'];
|
|
|
|
window.originalSoundData = data;
|
|
window.modifiedSoundData = Object.assign({}, data); // clone
|
|
window.fmtSoundData = {};
|
|
|
|
const distance = [
|
|
"in_50_meters",
|
|
"in_100_meters",
|
|
"in_200_meters",
|
|
"in_250_meters",
|
|
"in_300_meters",
|
|
"in_400_meters",
|
|
"in_500_meters",
|
|
"in_600_meters",
|
|
"in_700_meters",
|
|
"in_750_meters",
|
|
"in_800_meters",
|
|
"in_900_meters",
|
|
"in_1_kilometer",
|
|
"in_1_5_kilometers",
|
|
"in_2_kilometers",
|
|
"in_2_5_kilometers",
|
|
"in_3_kilometers",
|
|
"in_50_feet",
|
|
"in_100_feet",
|
|
"in_200_feet",
|
|
"in_300_feet",
|
|
"in_400_feet",
|
|
"in_500_feet",
|
|
"in_600_feet",
|
|
"in_700_feet",
|
|
"in_800_feet",
|
|
"in_900_feet",
|
|
"in_1000_feet",
|
|
"in_1500_feet",
|
|
"in_2000_feet",
|
|
"in_2500_feet",
|
|
"in_3000_feet",
|
|
"in_3500_feet",
|
|
"in_4000_feet",
|
|
"in_4500_feet",
|
|
"in_5000_feet",
|
|
"in_1_mile",
|
|
"in_1_5_miles",
|
|
"in_2_miles"
|
|
];
|
|
|
|
const direction = [
|
|
"take_the_1_exit",
|
|
"take_the_2_exit",
|
|
"take_the_3_exit",
|
|
"take_the_4_exit",
|
|
"take_the_5_exit",
|
|
"take_the_6_exit",
|
|
"take_the_7_exit",
|
|
"take_the_8_exit",
|
|
"take_the_9_exit",
|
|
"take_the_10_exit",
|
|
"take_the_11_exit",
|
|
"make_a_slight_right_turn",
|
|
"make_a_right_turn",
|
|
"make_a_sharp_right_turn",
|
|
"enter_the_roundabout",
|
|
"leave_the_roundabout",
|
|
"make_a_slight_left_turn",
|
|
"make_a_left_turn",
|
|
"make_a_sharp_left_turn",
|
|
"make_a_u_turn",
|
|
"go_straight",
|
|
"exit",
|
|
// "onto",
|
|
// "take_exit_number",
|
|
// "onto_exit_number",
|
|
"destination" // exception: shouldn't have a street afterwards
|
|
];
|
|
|
|
const nextStreets = [
|
|
"Main Street",
|
|
"Broadway Avenue",
|
|
"3rd Street",
|
|
"Highway 99",
|
|
"H1 East, Airport",
|
|
"I 278 West, Brooklyn-Queens Expressway, 48th Street, Brooklyn"
|
|
];
|
|
|
|
const nextExits = [
|
|
"3: D19, D6, Maisons Alfort, Alfortville, Saint Maurice",
|
|
"19: NY 25, Woodhaven Boulevard, Queens Boulevard",
|
|
"13B: Halawa Heights, Stadium",
|
|
"5: I 280, I 680",
|
|
"172: Priest Drive"
|
|
];
|
|
|
|
// dist_direction_onto_street
|
|
// then
|
|
// you_have_reached_the_destination
|
|
// unknown_camera
|
|
|
|
$("#out-a").html("");
|
|
$("#out-b").html("");
|
|
$("#out-c").html("");
|
|
$("#out-d").html("");
|
|
$("#out-e").html("");
|
|
$("#out-f").html("");
|
|
$("#out-g").html("");
|
|
|
|
var inputPre = "<div class='input-group mb-3'>"; // <button type='button' class='playtts btn btn-outline-secondary'>🔊</button>
|
|
inputPre += "<div class='form-control'>";
|
|
var inputPost = "</div></div>";
|
|
var tranStringTtsPre = "<span class='tranString badge text-bg-secondary'>";
|
|
|
|
$.each(direction, function(i, dir){
|
|
// can't "you'll arrive" in the present tense
|
|
if (dir != "destination") {
|
|
$("#out-a").append(inputPre +
|
|
buildTranStringInput(dir, data[dir]) +
|
|
inputPost);
|
|
}
|
|
});
|
|
|
|
$.each(direction, function(i, dir){
|
|
// can't "then" past your destination
|
|
if (dir != "destination") {
|
|
var nextDir = direction[(i + 2) % direction.length];
|
|
$("#out-b").append(inputPre +
|
|
buildTranStringInput(dir, data[dir]) +
|
|
buildTranStringInput("then", data["then"], "text-bg-success") +
|
|
buildTranStringInput(nextDir, data[nextDir]) +
|
|
inputPost);
|
|
}
|
|
});
|
|
|
|
$.each(distance, function(i, dist){
|
|
var dir = direction[i % direction.length];
|
|
$("#out-c").append(inputPre +
|
|
buildTranStringInput(dist, data[dist], "text-bg-warning") +
|
|
buildTranStringInput(dir, data[dir]) +
|
|
inputPost);
|
|
});
|
|
|
|
$.each(distance, function(i, dist){
|
|
var dir = direction[direction.length - ((i+6) % direction.length+1)];
|
|
// can't "then" past your destination
|
|
if (dir != "destination") {
|
|
var nextDir = direction[(i + 1) % direction.length];
|
|
$("#out-d").append(inputPre +
|
|
buildTranStringInput(dist, data[dist], "text-bg-warning") +
|
|
buildTranStringInput(dir, data[dir]) +
|
|
buildTranStringInput("then", data["then"], "text-bg-success") +
|
|
buildTranStringInput(nextDir, data[nextDir]) +
|
|
inputPost);
|
|
}
|
|
});
|
|
|
|
$.each(distance, function(i, dist){
|
|
var dir = direction[i % direction.length];
|
|
|
|
if (dir != "destination") {
|
|
// can't "arrive onto" your destination
|
|
//
|
|
// TODO: this entire section gets largely duplicated in the fmtModalForm handler
|
|
//
|
|
var fmtObj = {
|
|
dir: dir,
|
|
dist: dist,
|
|
nextStr: nextStreets[(i+1) % nextStreets.length]
|
|
};
|
|
var fmtKey = btoa(JSON.stringify(fmtObj));
|
|
window.fmtSoundData[fmtKey] = fmtObj;
|
|
var streetFmt = buildFmtStringInput('dist_direction_onto_street', data['dist_direction_onto_street'], "text-bg-dark", fmtKey);
|
|
|
|
var streetDir;
|
|
// overwrite the direction string if present for street TTS
|
|
if (data[dir+"_street"]) {
|
|
streetDir = buildTranStringInput(dir+"_street", data[dir+"_street"]);
|
|
} else {
|
|
streetDir = buildTranStringInput(dir, data[dir]);
|
|
}
|
|
|
|
var streetDirVerb;
|
|
if (data[dir+"_street_verb"])
|
|
streetDirVerb = data[dir+"_street_verb"];
|
|
|
|
streetFmt = streetFmt.replace("%1$s", buildTranStringInput(dist, data[dist], "text-bg-warning"));
|
|
streetFmt = streetFmt.replace("%2$s", streetDir);
|
|
streetFmt = streetFmt.replace("%3$s", buildTranStringInput('onto', data['onto'], "text-bg-info"));
|
|
streetFmt = streetFmt.replace("%4$s", buildTranStringInput("", fmtObj.nextStr, "text-bg-secondary", false)); // non-editable
|
|
streetFmt = streetFmt.replace("%5$s", buildTranStringInput(dir+"_street_verb", streetDirVerb, "text-bg-danger")); //optional
|
|
|
|
$("#out-e").append(inputPre +
|
|
streetFmt +
|
|
inputPost);
|
|
}
|
|
});
|
|
|
|
$.each(nextExits, function(i, nextStr){
|
|
var dir = "take_exit_number"; //direction[i % direction.length];
|
|
var dist = distance[((i+1) % distance.length)];
|
|
|
|
if (dir != "destination") {
|
|
// can't "arrive onto" your destination
|
|
//
|
|
// TODO: this entire section gets largely duplicated in the fmtModalForm handler
|
|
//
|
|
var fmtObj = {
|
|
dir: dir,
|
|
dist: dist,
|
|
nextStr: nextStr
|
|
};
|
|
var fmtKey = btoa(JSON.stringify(fmtObj));
|
|
window.fmtSoundData[fmtKey] = fmtObj;
|
|
var streetFmt = buildFmtStringInput('dist_direction_onto_street', data['dist_direction_onto_street'], "text-bg-dark", fmtKey);
|
|
|
|
var streetDir;
|
|
// overwrite the direction string if present for street TTS
|
|
//if (data[dir+"_street"]) {
|
|
// streetDir = buildTranStringInput(dir+"_street", data[dir+"_street"]);
|
|
//} else {
|
|
streetDir = buildTranStringInput(dir, data[dir]);
|
|
//}
|
|
|
|
var streetDirVerb;
|
|
if (data[dir+"_street_verb"])
|
|
streetDirVerb = data[dir+"_street_verb"];
|
|
|
|
// TODO: do we need this?
|
|
var ontoExitStr = ""; //data['onto_exit_number'];
|
|
// if (ontoExitStr == ".")
|
|
// ontoExitStr = "(blank)";
|
|
|
|
streetFmt = streetFmt.replace("%1$s", buildTranStringInput(dist, data[dist], "text-bg-warning"));
|
|
streetFmt = streetFmt.replace("%2$s", streetDir);
|
|
streetFmt = streetFmt.replace("%3$s", buildTranStringInput('onto_exit_number', ontoExitStr, "text-bg-info"));
|
|
streetFmt = streetFmt.replace("%4$s", buildTranStringInput("", nextStr, "text-bg-secondary", false)); // non-editable
|
|
streetFmt = streetFmt.replace("%5$s", buildTranStringInput(dir+"_street_verb", streetDirVerb, "text-bg-danger")); //optional
|
|
|
|
$("#out-f").append(inputPre +
|
|
streetFmt +
|
|
inputPost);
|
|
}
|
|
});
|
|
|
|
|
|
$.each(distance, function(i, dist){
|
|
var dir = direction[direction.length - (i % direction.length+1)];
|
|
|
|
if (dir != "destination") {
|
|
// can't "arrive onto" your destination
|
|
var nextDir = direction[(i + 1) % direction.length];
|
|
|
|
//
|
|
// TODO: this entire section gets largely duplicated in the fmtModalForm handler
|
|
//
|
|
var fmtObj = {
|
|
dir: dir,
|
|
dist: dist,
|
|
nextStr: nextStreets[(i+1) % nextStreets.length]
|
|
};
|
|
var fmtKey = btoa(JSON.stringify(fmtObj));
|
|
window.fmtSoundData[fmtKey] = fmtObj;
|
|
var streetFmt = buildFmtStringInput('dist_direction_onto_street', data['dist_direction_onto_street'], "text-bg-dark", fmtKey);
|
|
|
|
var streetDir;
|
|
// overwrite the direction string if present for street TTS
|
|
if (data[dir+"_street"]) {
|
|
streetDir = buildTranStringInput(dir+"_street", data[dir+"_street"]);
|
|
} else {
|
|
streetDir = buildTranStringInput(dir, data[dir]);
|
|
}
|
|
|
|
var streetDirVerb;
|
|
if (data[dir+"_street_verb"])
|
|
streetDirVerb = data[dir+"_street_verb"];
|
|
|
|
streetFmt = streetFmt.replace("%1$s", buildTranStringInput(dist, data[dist], "text-bg-warning"));
|
|
streetFmt = streetFmt.replace("%2$s", streetDir);
|
|
streetFmt = streetFmt.replace("%3$s", buildTranStringInput('onto', data['onto'], "text-bg-info"));
|
|
streetFmt = streetFmt.replace("%4$s", buildTranStringInput("", fmtObj.nextStr, "text-bg-secondary", false)); // non-editable
|
|
streetFmt = streetFmt.replace("%5$s", buildTranStringInput(dir+"_street_verb", streetDirVerb, "text-bg-danger")); //optional
|
|
|
|
$("#out-g").append(inputPre +
|
|
streetFmt +
|
|
buildTranStringInput('then', data['then'], "text-bg-success") +
|
|
buildTranStringInput(nextDir, data[nextDir], "text-bg-primary") +
|
|
inputPost);
|
|
}
|
|
});
|
|
|
|
$("#out-h").append(inputPre +
|
|
buildTranStringInput('you_have_reached_the_destination', data['you_have_reached_the_destination']) +
|
|
inputPost);
|
|
$("#out-h").append(inputPre +
|
|
buildTranStringInput('unknown_camera', data['unknown_camera']) +
|
|
inputPost);
|
|
|
|
$("#fmtModalForm").submit(function(){
|
|
// for dist_direction_onto_street only
|
|
var changes = [];
|
|
|
|
$("#fmtModal").modal('hide');
|
|
|
|
window.modifiedSoundData['dist_direction_onto_street'] = $(document.getElementById('fmtModalText')).val();
|
|
|
|
var soundKeys = Object.keys(window.originalSoundData);
|
|
var out = "";
|
|
var locale = $("#localeSelect").val();
|
|
|
|
for (i=0;i<soundKeys.length;i++) {
|
|
var soundKey = soundKeys[i];
|
|
var orig = window.originalSoundData[soundKey];
|
|
var mod = window.modifiedSoundData[soundKey];
|
|
|
|
if (mod != orig) {
|
|
out += " [" + soundKey + "]\n" +
|
|
"- " + locale + " = " + orig + "\n" +
|
|
"+ " + locale + " = " + mod + "\n";
|
|
$(".stringTxt[data-key='"+soundKey+"']").val(mod); // update all instances
|
|
}
|
|
}
|
|
|
|
// also update all dist_direction_onto_street instances (rebuild from metadata)
|
|
$(".stringTxt[data-key='dist_direction_onto_street']").each(function(i,o){
|
|
var fmtKey = $(o).data("fmtkey");
|
|
var fmtObj = window.fmtSoundData[fmtKey];
|
|
|
|
var dir = fmtObj.dir;
|
|
var dist = fmtObj.dist;
|
|
var onto = fmtObj.onto;
|
|
var nextStr = fmtObj.nextStr;
|
|
|
|
//
|
|
// TODO: this entire section gets largely duplicated in the showData function
|
|
//
|
|
var streetFmt = buildFmtStringInput('dist_direction_onto_street', window.modifiedSoundData['dist_direction_onto_street'], "text-bg-dark", fmtKey);
|
|
|
|
var streetDir;
|
|
// overwrite the direction string if present for street TTS
|
|
if (window.modifiedSoundData[dir+"_street"]) {
|
|
streetDir = buildTranStringInput(dir+"_street", window.modifiedSoundData[dir+"_street"]);
|
|
} else {
|
|
streetDir = buildTranStringInput(dir, window.modifiedSoundData[dir]);
|
|
}
|
|
|
|
var streetDirVerb;
|
|
if (window.modifiedSoundData[dir+"_street_verb"])
|
|
streetDirVerb = window.modifiedSoundData[dir+"_street_verb"];
|
|
|
|
streetFmt = streetFmt.replace("%1$s", buildTranStringInput(dist, window.modifiedSoundData[dist], "text-bg-warning"));
|
|
streetFmt = streetFmt.replace("%2$s", streetDir);
|
|
streetFmt = streetFmt.replace("%3$s", buildTranStringInput('onto', window.modifiedSoundData[onto], "text-bg-info"));
|
|
streetFmt = streetFmt.replace("%4$s", buildTranStringInput("", nextStr, "text-bg-secondary", false)); // non-editable
|
|
streetFmt = streetFmt.replace("%5$s", buildTranStringInput(dir+"_street_verb", streetDirVerb, "text-bg-danger")); //optional
|
|
|
|
var oldEl = $(o).parent();
|
|
var parent = $(oldEl).parent();
|
|
oldEl.remove(); // remove ourselves
|
|
parent.prepend(streetFmt); // prepend new html
|
|
});
|
|
|
|
$("#submitpopup textarea").text("Translation change request:\n```\n"+
|
|
"# data/strings/sound.txt\n" + out + "```"
|
|
);
|
|
$("#submitpopup").show();
|
|
|
|
loadEventHandlers(); // we've just redone a bunch of html, reload handlers
|
|
|
|
return false; // prevent navigation
|
|
});
|
|
|
|
|
|
loadEventHandlers();
|
|
}
|
|
|
|
function loadLocale(){
|
|
var commitHash = "1773896f531da49936fe7c5018f6a76a886ecf5f";
|
|
var sourceUrl = "https://raw.githubusercontent.com/organicmaps/organicmaps/"+commitHash+"/data/strings/sound.txt";
|
|
|
|
$("#sourceUrl").attr("href", sourceUrl).text("sound.txt");
|
|
|
|
if (!window.soundTxtRaw) {
|
|
$.get(sourceUrl, function(rawData){
|
|
window.soundTxtRaw = rawData;
|
|
showData();
|
|
});
|
|
} else {
|
|
showData();
|
|
}
|
|
}
|
|
</script>
|
|
|
|
|
|
|
|
</body>
|
|
</html>
|
|
|