// SLIDESHOW modified from: https://www.w3schools.com/howto/howto_js_slideshow.asp
// Postman for formatting requests and guaranteeing keys work before translating request into JS: https://www.postman.com/
// OpenAI API docs for formatting chatgpt requests: https://platform.openai.com/docs/guides/
// Google Cloud docs for formatting Google requests: https://cloud.google.com/docs
// Microsoft computer vision API docs consulted: https://learn.microsoft.com/en-us/azure/ai-services/computer-vision/
// Microsoft Azure AI api docs consulted: https://learn.microsoft.com/en-us/azure/ai-services/translator/
// CSS based on the way CSS is organised in Darius Beril's language quizzer: https://ancientbrain.com/world.php?world=2000799532
// "Set API Key" buttons based on design in Darisu Beril's language quizzer: https://ancientbrain.com/world.php?world=2000799532
// DeepL API docs consulted: https://developers.deepl.com/docs
// Cloned by Shahin de Faoite Houshidari on 25 Oct 2024 from World "Language Translator and Reader" by Darius Beril
// Please leave this clone trail here.
// Cloned by Darius Beril on 7 Dec 2023 from World "Language Quizzer" by Darius Beril
// Please leave this clone trail here.
// Cloned by Darius Beril on 6 Dec 2023 from World "Chat with GPT model" by Starter user
// Please leave this clone trail here.
// talk to OpenAI GPT model (ChatGPT)
// adapted from:
// https://platform.openai.com/docs/api-reference/making-requests
// the OpenAI model we are going to talk to
// MH edit
var microsoft_translate_key = ""
var microsoft_vision_key = ""
var google_key = ""
var chatgpt_key = ""
var chatgpt_pid = ""
var d_path = null
var proxy_key = ""
var apikey = "" // not used!
const W = 1024
const H = 768
const N_OF_SLIDES = 53;
const google_path = "https://vision.googleapis.com/v1/images:annotate" // ?key={key}
const google_t_path = "https://translation.googleapis.com/language/translate/v2" // ?key={key}
const m_path = "https://ancientbrain.cognitiveservices.azure.com/computervision/imageanalysis:analyze?api-version=2023-04-01-preview"
const m_t_path = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&from=ja&to=en";
const chatgpt_path = 'https://api.openai.com/v1/chat/completions';
var abs_index = 0;
var slide_number = 0;
var slide_strings = generateSlides(N_OF_SLIDES);
// default body is margin 0 and padding 0
// give it more whitespace:
$('body').css( "margin", "20px" );
$('body').css( "padding", "20px" );
document.write ( `
<div class="body">
<div class="container">
<h1> Using Multiple AI API’s to Extract and Translate Text </h1>
<p><em>AI’s Applicability in Bolstering Confidence Abroad
Using Japanese Signs as Case-Studies
</em></p>
<br>
Enter your API key below
<br>
<div class="keys">
<br>
<!-- Buttons from Darius Beril's Language Quizzer: https://ancientbrain.com/world.php?world=2000799532 -->
Enter Google API key:
<input style='width:25vw;' maxlength='2000' NAME="apikey" id="gk" VALUE='' >
<button onclick="setGoogle()" class=ab-normbutton >Set API key</button>
<br>
Enter Microsoft COMPUTER VISION API key:
<input style='width:25vw;' maxlength='2000' NAME="apikey" id="mvk" VALUE='' >
<button onclick="setMicrosoftVision()" class=ab-normbutton >Set API key</button>
<br>
Enter Microsoft TRANSLATE API key:
<input style='width:25vw;' maxlength='2000' NAME="apikey" id="mtk" VALUE='' >
<button onclick="setMicrosoftTranslate()" class=ab-normbutton >Set API key</button>
<br>
<br>
Enter OpenAI ChatGPT API key:
<input style='width:25vw;' maxlength='2000' NAME="apikey" id="cgptk" VALUE='' >
<button onclick="setChatGPTKey()" class=ab-normbutton >Set API key</button>
<br>
<br>
Enter OpenAI ChatGPT Project ID:
<input style='width:25vw;' maxlength='2000' NAME="apikey" id="cgptpid" VALUE='' >
<button onclick="setChatGPTProjectId()" class=ab-normbutton >Set API key</button>
<br>
To test the App on a Custom Image (i.e. not from the slideshow), enter a URL pointing toward an image (for example, an Ancient Brain Upload):
<input style='width:25vw;' maxlength='2000' NAME="custom_img_url" id="ciu" VALUE='' >
<button onclick='setCustomUrl()' class=ab-normbutton >Set URL</button>
<br>
</div>
<br><br>
<h1> How to use: </h1>
<strong>
<ol>
<li> Select an image from the slideshow/enter a <em>custom url pointing to an image</em></li>
<li> Hit "Transpose" to extract text. <em> (Skip this step if entering a custom url, when hitting "set", the translation occurs automatically.)</em> </li>
<li> Hit "Translate" to translate the extracted text. <em>Note: if DeepL is activated, DeepL shall also translate the text. See the DeepL section below.</em></li>
<li> Hit ChatGPT Assess to translate Google and Microsoft's <em> two text extractions </em> and <em> each of their translations of both their transposition, AND the others </em>.</li>
</ol>
</strong>
<p><em>Once an image has been transposed, hit translate to translate the transposed text.</em></p>
<div class="slideshow-container">
${slide_strings}
<!-- Slideshow modified from: https://www.w3schools.com/howto/howto_js_slideshow.asp -->
<!-- Next and previous buttons -->
<a class="prev" onclick="plusSlides(-1)">❮</a>
<a class="next" onclick="plusSlides(1)">❯</a>
</div>
<br>
<div style="text-align:center">
<span class="dot" onclick="currentSlide(1)"></span>
<span class="dot" onclick="currentSlide(2)"></span>
<span class="dot" onclick="currentSlide(3)"></span>
</div>
<br>
<br>
<br>
<button onclick='classify();' class=ab-normbutton >Transpose Slide</button>
<button onclick='translateText();' class=ab-normbutton >Translate Current Extracted Text</button>
<button onclick='chatgptButton();' class=ab-normbutton >ChatGPT Assess</button>
<div class="main-container">
<div class="transpositions">
<div class="wordbox">
<p id="g_ocr">Waiting on Google's transposition</p>
<em><hp id="g_confidence"></p></em>
<br>
</div>
<br>
<div class="wordbox">
<p id="m_ocr">Waiting on Microsoft's transposition</p>
<em><p id="m_confidence"></p></em>
</div>
<br>
<div class="wordbox">
<p id="c_ocr">Waiting on ChatGPT's transposition & assessment</p>
<em><p id="c_confidence"></p></em>
</div>
<br>
</div>
<br>
<br>
<div class="translations">
<div class="wordbox">
<h2>Translating Google's Transposition:</h2>
<h4>Google's Translation:</h4>
<br>
<p id="g_translation1">Waiting on Google's translation</p>
<br>
<br>
<h4>Microsoft's Translation:</h4>
<p id="m_translation1">Waiting on Microsoft's translation</p>
</div>
<br>
<div class="wordbox">
<h2>Translating Microsoft's Transposition:</h2>
<h4>Google's Translation:</h4>
<p id="g_translation2">Waiting on Google's translation</p>
<br>
<br>
<h4>Microsoft's Translation:</h4>
<p id="m_translation2">Waiting on Microsoft's translation</p>
</div>
<br>
<br>
<br>
<div class="wordbox">
<h1>DeepL:</h1>
<h4>DeepL Translation:</h4>
<p id="d_translation">DeepL will translate Google's reading and place it here.</p>
<br>
<hr>
<br>
<p>DeepL translation happens via <em>Proxy API</em>. The link to the GitHub repo containing the Django code to set up and run a local instance of this proxy API is: <br><br><strong>https://github.com/Shahinhou/public_deepL_proxy</strong></p><br>
<p><em>If you are viewing this page between 15/11/2024 and 1/2/2025, a proxy API is being hosted at:</em><br><br> <strong>https://privatedeeplproxy-production.up.railway.app/proxy/</strong></p><br>
<br>
<p>Enter the URL for your proxy API to make a verifying request to DeepL:</p>
<input style='width:25vw;' maxlength='2000' NAME="deeplproxy" id="dlp" VALUE='http://127.0.0.1:8000/proxy/' >
<button onclick='setDeepLProxy()' class=ab-normbutton >Set URL</button>
<p><strong>Please note that if you are hosting your own Proxy API, you must have your own API Key. Instructions to set up the local proxy are at the link above.</strong></p>
<p><em>Example: "http:127.0.0.1:8000/proxy/"</em</p>
<p>DeepL Proxy Key: </p>
<input style='width:25vw;' maxlength='2000' NAME="deeplproxykey" id="dlpk" VALUE='' >
<button onclick='setDeepLProxyKey()' class=ab-normbutton >Set Proxy Key</button>
<p><em>This is different from the DeepL key. This is specifically for the proxy. If it is later than 1/2/2025, instructions for setting up your proxy with your own DeepL key and custom Secret Key are at the Git link above.</em></p>
<br>
</div>
</div>
</div>
<br>
<div class="gptbox">
<h4>ChatGPT assessing Google's Transposition:</h4>
<p id="google_assessment">Waiting on ChatGPT's assessment and comparison of both translations of Google's transposition</p>
</div>
<br>
<br>
<br>
<div class="gptbox">
<h4>ChatGPT assessing Microsoft's Transposition:</h4>
<p id="microsoft_assessment">Waiting on ChatGPT's assessment and comparison of both translations of Microsoft's transposition</p>
</div>
<pre>
</pre>
</div>
<pre>
</pre>
</div>
</div>
` );
//
function getCurrent(){
console.log(slideIndex);
}
/* Setters for keys etc - logic modified from Darius Beril's Language Quizzer: https://ancientbrain.com/world.php?world=2000799532 */
function setCustomUrl(){
var url = jQuery("input#ciu").val();
url = url.trim();
console.log(url)
classify(url);
}
function setDeepLProxy(){
var url = jQuery("input#dlp").val();
url = url.trim();
console.log(url)
d_path = (url);
}
function setDeepLProxyKey(){
proxy_key = jQuery("input#dlpk").val().trim();
}
function setMicrosoftTranslate(){
microsoft_translate_key = jQuery("input#mtk").val().trim();
}
function setMicrosoftVision(){
microsoft_vision_key = jQuery("input#mvk").val().trim();
}
function setGoogle(){
google_key = jQuery("input#gk").val().trim();
}
function setChatGPTKey(){
chatgpt_key = jQuery("input#cgptk").val().trim();
}
function setChatGPTProjectId(){
chatgpt_pid = jQuery("input#cgptpid").val().trim();
}
/* ChatGPT button */
function chatgptButton(custom){
if (custom == null){
imgUrl = document.getElementById(slideIndex-1).src;
}
else {
imgUrl = custom;
}
var url = jQuery("input#ciu").val();
url = url.trim();
console.log(url)
let ckey = chatgpt_key
let pid = chatgpt_pid
let ot1 = document.getElementById("g_ocr").textContent
let tt1_1 = document.getElementById("g_translation1").textContent
let tt1_2 = document.getElementById("m_translation1").textContent
let ot2 = document.getElementById("m_ocr").textContent
let tt2_1 = document.getElementById("g_translation2").textContent
let tt2_2 = document.getElementById("m_translation2").textContent
chatgptTranspose(ckey, imgUrl, document.getElementById('g_ocr').textContent, document.getElementById('m_ocr').textContent, pid);
chatgptAssessTranslation(ckey, ot1, tt1_1, tt1_2, "google", pid);
chatgptAssessTranslation(ckey, ot2, tt2_1, tt2_2, "microsoft", pid);
}
async function chatgptAssessTranslation(ckey, originalText, translatedText1, translatedText2, target, project_id) {
console.log('click');
const payload = {
model: "gpt-4o-mini",
messages: [
{
role: "system",
content: "You are an expert in Japanese and English. Please assess the accuracy and quality of two translations of a Japanese text to English."
},
{
role: "user",
content: `Here is the original Japanese text:\n\n${originalText}\n\nHere is Google's English translation:\n\n${translatedText1}\n\nHere is the Microsoft's English translation:\n\n${translatedText2}\n\nPlease evaluate the translations for accuracy, fluency, and faithfulness to the original meaning, and compare the two. Please give an indication as to which is superior.`
}
],
temperature: 0.7,
};
try {
const response = await fetch(chatgpt_path, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${ckey}`,
"OpenAI-Organization": "org-9GqX5v167YXP8VuHb4fPUi3a",
"OpenAI-Project": `${project_id}`
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`HTTP error, status: ${response.status}`);
}
const data = await response.json();
console.log("Translation Assessment:", data.choices[0].message.content);
console.log(data);
document.getElementById(`${target}_assessment`).innerHTML = `${data.choices[0].message.content}`;
} catch (error) {
console.error("Error making API request:", error);
}
}
/* Text Extraction */
function classify(custom=null) {
let gkey = google_key
let mkey = microsoft_vision_key
let imgUrl = "";
if (custom == null){
imgUrl = document.getElementById(slideIndex-1).src;
}
else {
imgUrl = custom;
}
googleTranspose(gkey, imgUrl);
microsoftTranspose(mkey, imgUrl);
}
async function chatgptTranspose(ckey, imgUrl, t1, t2, project_id){
// Built using OpenAI API docs: https://platform.openai.com/docs/guides/vision#quickstart
console.log('click');
const payload = {
model: "gpt-4o-mini",
messages: [
{
role: "user",
content: [
{
type:"text",
text: "You are an expert in Japanese and English. Please read the text from an image given a URL, and compare two other readings to assess which reading is superior."
},
{
type: "image_url",
image_url: {
"url":`${imgUrl}`
}
},
{
type:"text",
text: `Here is the Google reading:${t1}`
},
{
type:"text",
text: `Here is the Microsoft reading:${t2}`
}
]
}
],
temperature: 0.7,
};
try {
const response = await fetch(chatgpt_path, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${ckey}`,
"OpenAI-Organization": "org-9GqX5v167YXP8VuHb4fPUi3a",
"OpenAI-Project": `${project_id}`
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`HTTP error, status: ${response.status}`);
}
const data = await response.json();
console.log("Translation Assessment:", data.choices[0].message.content);
console.log(data);
document.getElementById(`c_ocr`).innerHTML = `${data.choices[0].message.content}`;
} catch (error) {
console.error("Error making API request:", error);
}
}
function googleTranspose(gkey, imgUrl){
// Used google cloud docs: https://cloud.google.com/docs
fetch(`${google_path}?key=${gkey}`, {
method:"POST",
header: {
"Content-type":"application/json"
},
body: JSON.stringify(
{
"requests":[
{
"image":{
"source": {
"imageUri": `${imgUrl}`
}
},
"features":[
{
"type":"DOCUMENT_TEXT_DETECTION",
}
],
"imageContext": {
//"languageHints": ["en-t-i0-handwrit"]
"languageHints": ["ja"]
}
}
]
}
)}
)
.then(response => response.json())
.then(response => {
if (response.responses.length > 0){
document.getElementById("g_ocr").innerHTML = response.responses[0].fullTextAnnotation.text
document.getElementById("g_confidence").innerHTML = `Google's confidence: ${response.responses[0].fullTextAnnotation.pages[0].confidence}`
console.log(response.responses[0].fullTextAnnotation.text);
console.log(response)
return response;
}
})
}
function microsoftTranspose(mkey, imgUrl){
// Used Postman - modified postman request until it worked, then generated "fetch javascript" code from postman request. Then heavily modified to work in this program.
const myHeaders = new Headers();
myHeaders.append("Ocp-Apim-Subscription-Key", `${mkey}`);
myHeaders.append("Content-Type", "application/json");
const raw = JSON.stringify({
"url": `${imgUrl}`
});
const requestOptions = {
method: "POST",
headers: myHeaders,
body: raw,
redirect: "follow"
};
fetch("https://ancientbrain.cognitiveservices.azure.com/computervision/imageanalysis:analyze?api-version=2023-04-01-preview&features=read", requestOptions)
.then((response) => response.json())
.then((result) => {
document.getElementById("m_ocr").innerHTML = result.readResult.content;
let conf = 0.0;
let i = 0;
for (d in result.readResult.pages[0].words){
console.log(d)
conf += result.readResult.pages[0].words[d].confidence;
i+=1;
}
conf = conf / i
console.log(conf);
console.log(result);
document.getElementById("m_confidence").innerHTML = `Microsoft's confidence: ${conf}`;
})
.catch((error) => console.error(error));
}
function translateText() {
let gkey = google_key
let mkey = microsoft_translate_key
let imgUrl = document.getElementById(abs_index).src;
let ot1 = document.getElementById("g_ocr").textContent;
let ot2 = document.getElementById("m_ocr").textContent;
googleTranslate(gkey,1, ot1);
microsoftTranslate(mkey,1, ot1);
googleTranslate(gkey,2, ot2);
microsoftTranslate(mkey,2, ot2);
if (d_path != null){
deepLTranslate();
}
}
function googleTranslate(gkey,target,ot){
// Used google cloud docs: https://cloud.google.com/docs
fetch(`${google_t_path}?key=${gkey}`, {
method:"POST",
header: {
"Content-type":"application/json"
},
body: JSON.stringify(
{
q: ot,
source: "ja",
target: "en",
format: "text"
}
)}
)
.then(response => response.json())
.then(response => {
if (response.data.translations.length > 0){
document.getElementById(`g_translation${target}`).innerHTML = response.data.translations[0].translatedText;
console.log("google:")
console.log(response)
return response;
}
})
}
function microsoftTranslate(m_key, target, ot, m_key_region="eastus"){
// Used Postman - modified postman request until it worked, then generated "fetch javascript" code from postman request. Then heavily modified to work in this program.
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Ocp-Apim-Subscription-Key", `${m_key}`);
myHeaders.append("Ocp-Apim-Subscription-Region", `${m_key_region}`);
const raw = JSON.stringify([
{
"text": ot //`${document.getElementById("m_ocr").textContent}`
}
]);
const requestOptions = {
method: "POST",
headers: myHeaders,
body: raw,
redirect: "follow"
};
fetch(`${m_t_path}`, requestOptions)
.then((response) => response.json())
.then((response) => {
if (response[0].translations.length > 0){
document.getElementById(`m_translation${target}`).innerHTML = response[0].translations[0].text;
console.log("microsoft:")
console.log(response)
return response;
}
})
.catch((error) => console.error(error));
}
function deepLTranslate(){
// Used Postman - modified postman request until it worked, then generated "fetch javascript" code from postman request. Then heavily modified to work in this program.
const dlHeaders = new Headers();
dlHeaders.append("Content-Type", "application/json");
console.log(proxy_key)
const dlraw = JSON.stringify(
{
text: `${document.getElementById("g_ocr").textContent}`,
target_lang: "EN",
source_lang: "JA",
key: `${proxy_key}`
}
)
const dlrequestOptions = {
method: "POST",
headers: dlHeaders,
body: dlraw,
redirect: "follow"
};
fetch(`${d_path}`, dlrequestOptions)
.then((response) => response.json())
.then((result) => {
console.log(result);
document.getElementById("d_translation").innerHTML = result.translations[0].text;
return result;
})
.catch((error) => console.error(error));
}
/* W3 Schools Slides modified from: https://www.w3schools.com/howto/howto_js_slideshow.asp */
let slideIndex = 1;
abs_index = 1;
showSlides(slideIndex);
// Next/previous controls
function plusSlides(n) {
let length = document.getElementsByClassName("mySlides").length
slide_number = (slide_number + n) % length;
abs_index = Math.abs(slide_number);
console.log(abs_index);
showSlides(slideIndex+n);
}
// Thumbnail image controls
function currentSlide(n) {
showSlides(slideIndex = n);
abs_index = n;
slide_number = n;
}
function showSlides(n) {
let i;
let slides = document.getElementsByClassName("mySlides");
let dots = document.getElementsByClassName("dot");
slideIndex = n;
if (n > slides.length) {slideIndex = 1}
if (n < 1) {slideIndex = slides.length}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
//for (i = 0; i < dots.length; i++) {
//dots[i].className = dots[i].className.replace(" active", "");
//}
slides[slideIndex-1].style.display = "block";
//dots[slideIndex-1].className += " active";
}
/* End of w3schools modified content */
function generateSlides(length) {
let index = 0;
let slide_strings = "";
while (index < length){
slide_strings = slide_strings.concat(`<div class="mySlides fade">
<div class="numbertext">${index} / ${length}</div>
<img id="${index}" src="https://ancientbrain.com/uploads/shahindfh/${index}.jpg" style="width:100%">
<div class="text">Demo image ${index}</div>
</div>`);
//console.log(slide_strings);
index+=1;
}
return slide_strings;
}
/* CSS styling method based on Darius Beril's Language Quizzer's CSS setup: https://ancientbrain.com/world.php?world=2000799532 */
$('button').css("padding", "10px");
$('*').css("font-family", "Georgia");
$('*').css("font-weight", "light");
$('img').css("padding", "10px");
$('.body').css("background-color", "#a6daff");
$('.body').css("padding", "20px");
$('.container').css("background-color", "#FAF9F6");
$('.container').css("padding", "20px");
$('.container').css("margin", "auto");
$('.container').css("max-width", "85%");
$('.slideshow-container').css("max-width", "500px");
$('.slideshow-container').css("position", "absolute");
$('.slideshow-container').css("left", "200px");
$('.slideshow-container').css("top", "1000px");
$('.transpositions').css("background-color", "#fbfcb8");
$('.transpositions').css("max-width", "900px");
$('.transpositions').css("padding", "20px");
$('.translations').css("background-color", "#fbfcb8");
$('.translations').css("max-width", "2000px");
$('.translations').css("padding", "20px");
$('.main-container').css("background-color", "#feffdb");
$('.main-container').css("margin-left", "45%");
$('.main-container').css("padding", "5px");
$('.main-container').css("max-width", "2000px");
$('.gptbox').css("background-color", "#ffffed");
$('.gptbox').css("max-width", "600px");
$('.gptbox').css("padding", "20px");
$('.wordbox').css("background-color", "#ffffed");
$('.wordbox').css("margin", "auto");
$('.wordbox').css("max-width", "800px");
$('.wordbox').css("padding", "20px");
$('.prev').css("cursor", "pointer");
$('.prev').css("position", "absolute");
$('.prev').css("top", "50%");
$('.prev').css("width", "auto");
$('.prev').css("margin-top", "-22px");
$('.prev').css("padding", "16px");
$('.prev').css("color", "white");
$('.prev').css("font-weight", "bold");
$('.prev').css("font-size", "18px");
$('.prev').css("transition", "0.6s ease");
$('.prev').css("border-radius", "0 3px 3px 0");
$('.prev').css("user-select", "none");
$('.next').css("cursor", "pointer");
$('.next').css("position", "absolute");
$('.next').css("top", "50%");
$('.next').css("width", "auto");
$('.next').css("margin-top", "-22px");
$('.next').css("padding", "16px");
$('.next').css("color", "white");
$('.next').css("font-weight", "bold");
$('.next').css("font-size", "18px");
$('.next').css("transition", "0.6s ease");
$('.next').css("border-radius", "0 3px 3px 0");
$('.next').css("user-select", "none");
$('.next').css("right", "0");
$('.next').css("border-radius", "3px 0 0 3px");
$('.text').css("color", "#f2f2f2");
$('.text').css("font-size", "15px");
$('.text').css("padding", "8px 12px");
$('.text').css("position", "absolute");
$('.text').css("bottom", "8px");
$('.text').css("width", "100%");
$('.text').css("text-align", "center");
$('.numbertext').css("color", "#f2f2f2");
$('.numbertext').css("font-size", "12px");
$('.numbertext').css("padding", "8px 12px");
$('.numbertext').css("position", "absolute");
$('.numbertext').css("top", "0");
/* IMAGES */
/*
https://tabimaniajapan.com/japan-trip/japanese-road-signs-be-mindful-of-the-unique-shape-of-the-%E6%AD%A2%E3%81%BE%E3%82%8C-sign
https://japantravel.navitime.com/en/area/jp/guide/NTJnews0429-en/
https://japan-top-10.com/the-top-10-strangest-road-signs-you-will-find-in-japan/
https://www.tripadvisor.com/LocationPhotoDirectLink-g1120812-d11904798-i233781584-Mama_Cafe-Kin_cho_Kunigami_gun_Okinawa_Prefecture_Kyushu.html
https://dynamic-media-cdn.tripadvisor.com/media/photo-o/2d/e1/70/42/caption.jpg?w=900&h=500&s=1
https://dynamic-media-cdn.tripadvisor.com/media/photo-o/1c/20/c2/90/dsc-0698-largejpg.jpg?w=800&h=400&s=1
https://dynamic-media-cdn.tripadvisor.com/media/photo-o/11/9a/b6/03/menu-2.jpg?w=900&h=500&s=1
https://dynamic-media-cdn.tripadvisor.com/media/photo-o/11/0b/3d/fe/photo0jpg.jpg?w=900&h=-1&s=1
https://dynamic-media-cdn.tripadvisor.com/media/photo-o/21/87/55/db/caption.jpg?w=900&h=500&s=1
https://dynamic-media-cdn.tripadvisor.com/media/photo-o/21/3a/9a/cc/caption.jpg?w=900&h=500&s=1
https://www.japantimes.co.jp/life/2017/11/06/language/cants-donts-japanese-society-writ-large-signage/
https://i0.wp.com/100travelstories.com/wp-content/uploads/2014/11/japan-funny-sign-1.jpg?resize=563%2C750
https://bbqboy.net/wp-content/uploads/2017/03/hat-sign-japan.jpg
https://ankiweb.net/shared/mpreview/135266511/1.jpg?1414627200
https://100travelstories.com/blog/funny-signs-japan/
https://landingaway.blogspot.com/2010/11/signs.html
https://ktotokyo.wordpress.com/wp-content/uploads/2012/03/dscn11831.jpg
https://discoverdiscomfort.com/learning-language-to-order-food/
https://unseen-japan.com/tackling-food-kanji-in-japanese-menus/
https://www.reddit.com/r/trains/comments/16cvu8e/one_for_the_only_in_japan_category_instructions/#lightbox
https://www.alamy.com/an-information-sign-on-a-dedicated-shinkansen-bullet-train-platform-showing-where-specific-carriages-will-be-positioned-for-boarding-image354111590.html?imageid=E36828D8-42AE-4B63-A3C7-38EAE4127CF6&p=810080&pn=2&searchId=1a78009a577d33431859f87aab9aceef&searchtype=0
https://www.flickr.com/photos/22749160@N06/7165000339/
https://asia.nikkei.com/Life-Arts/Life/Lost-in-translation-Signs-puzzle-overseas-tourists-in-Japan
https://www.turbosquid.com/FullPreview/1139856
https://wanderthemap.com/2015/04/lost-in-translation-engrish-in-japan/
https://www.japanese-vintage.org/vintage-shop-sign-1950s
https://www.flickr.com/photos/188326905@N04/50821851578
https://aucview.aucfan.com/yahoo/b1026628638/
https://saitoshika-west.com/wp/wp-content/uploads/2022/06/005.jpg
https://japantoday.com/category/features/opinions/The-noise-problem-in-conflict-averse-Japan
https://pt.3dexport.com/3dmodel-japanese-store-signs-142940.htm
https://www.asahi.com/ajw/articles/14829277
https://www.freepik.com/free-photo/close-up-japanese-street-food-shop_22898150.htm
https://figureculture.wordpress.com/wp-content/uploads/2012/05/japaneseracoon.jpg
https://www.alamy.com/yellow-monkey-crossing-road-sign-in-rural-japan-image341086625.html
https://weathernews.jp/s/topics/202010/300115/
https://www.alamy.com/beware-of-wild-bears-sign-akita-japan-image358285942.html?imageid=0A3F5F9A-3ED5-4A9E-A9A9-3D2B9BF651F7&p=14768&pn=1&searchId=2dff3243da58ded39db6ca2148b1c04d&searchtype=0
https://www.upguides.com/nor/trips/japan-road-trip-hokkaido
https://yamap.com/activities/13370370/article
https://en.photo-ac.com/photo/357092/shrine-signs
https://www.istockphoto.com/photos/omikuji?page=3
https://www.dreamstime.com/editorial-image-sign-japanese-park-trelling-people-must-have-their-dog-dog-leash-forbidden-to-leave-dog-poo-image52233760
https://www.photo-ac.com/main/detail/24152724?title=%E9%9D%92%E7%A9%BA%E3%81%A8%E9%A7%90%E7%A6%81
https://textureofjapan.com/products/6-sign-no-bike-parking
*/