Fix language selector being invisible; correct sample utterance types
The dropdown was in the HTML all along and still could not be seen. Three separate causes, found by measuring the rendered element rather than trusting that the markup existed: 1. Clipped off-screen. The h1 is a flex row with no wrap. Measured at an 800px viewport: the language span started at x=620 and ended at x=810, past the viewport edge, so only its first few pixels were painted. The project badge alone took 309px. Adding flex-shrink and truncating the badge did not fix it - there is genuinely no room in that row. The selector now gets its own bar directly under the header, and the project name ellipsises. Verified visible: x=181, right=341 in an 800px viewport, 34px tall. 2. Empty on every other page. base.html rendered the select from a `languages` variable that almost no page supplies, so the login page and the rest of the app showed a 38px-wide dropdown with zero options - effectively invisible, and a dead control. Pages now opt in by overriding a header_bar block. Verified /, /speakers, /chapters-audio and /login all still render. 3. Browser cache made my own screenshot lie. It showed a stale Japanese string containing the word "decisiveness" that is in no file on disk. A cache-busted fetch confirmed the server is clean. Worth remembering: a screenshot taken through a warm cache is not evidence. The screenshot also exposed a data bug. All 12 sample utterances carried type "narration" - including Kainda, Duchess Victoria, Deal Hunter, Nanny and Trader Romano, who are all speaking. Every row rendered a narration badge and the file told UmbraTrans that six characters were not speaking. SHAPE in build_sample_translations.py now marks 6 dialogue / 6 narration, and the generated JSONs are regenerated to match. Also removed a misleading issue. It reported "12 rendered clips have no staleness marker" as a translation problem; the markers are absent because render_lang_test.py does not write them, so it was sending the reader after a defect that does not exist. Replaced with the honest one: only 12 of 4,319 translated and none confirmed - sample only, not publishable. Suite: 721 passed, 8 pre-existing. ruff clean on changed regions.
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
{
|
||||
"index": 1,
|
||||
"speaker": "Kainda",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Hallo! Ich bin Prinzessin Kainda, die Hauptfigur der Geschichte. Mein Abenteuer beginnt gleich."
|
||||
},
|
||||
{
|
||||
@@ -29,7 +29,7 @@
|
||||
{
|
||||
"index": 3,
|
||||
"speaker": "Duchess Victoria",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Hallo! Ich bin Herzogin Victoria. Ich bin außerdem Kaindas Tante. Ich kann es kaum erwarten, dieses Abenteuer mit dir zu teilen."
|
||||
},
|
||||
{
|
||||
@@ -41,13 +41,13 @@
|
||||
{
|
||||
"index": 5,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Hallo! Ich bin die künstliche Intelligenz, die das Schiff steuert. Man nennt mich gewöhnlich einfach Hunter. Ich freue mich darauf, dir mit dieser Geschichte eine schöne Zeit zu bereiten. Hier ist einer meiner Roboter, den Kainda auf den Namen Nanny getauft hat. Sag Hallo, Nanny."
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"speaker": "Nanny",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Hallo! Kainda hat mich Nanny genannt, weil das leichter zu sagen ist als meine Roboternummer. Ich werde so hilfreich sein, wie ich kann."
|
||||
},
|
||||
{
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"index": 8,
|
||||
"speaker": "Trader Romano",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Hallo zusammen! Ich bin Romano. Ich kaufe Schrott vom Deal Hunter und biete stets den besten Preis. Komm zur Station, wenn du etwas tauschen möchtest."
|
||||
},
|
||||
{
|
||||
@@ -77,7 +77,7 @@
|
||||
{
|
||||
"index": 11,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Vielen Dank fürs Zuhören!"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
{
|
||||
"index": 1,
|
||||
"speaker": "Kainda",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Hello! I am Princess Kainda, the main character of the story. My adventure will begin shortly."
|
||||
},
|
||||
{
|
||||
@@ -29,7 +29,7 @@
|
||||
{
|
||||
"index": 3,
|
||||
"speaker": "Duchess Victoria",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Hello! I am Duchess Victoria. I am also Kainda's aunt. I cannot wait to share this adventure with you."
|
||||
},
|
||||
{
|
||||
@@ -41,13 +41,13 @@
|
||||
{
|
||||
"index": 5,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Hello! I am the AI that runs the ship. I am usually just called Hunter. I am looking forward to entertaining you with this story. One of my robots, whom Kainda decided to name Nanny, is here. Say hello, Nanny."
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"speaker": "Nanny",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Hello! Kainda named me Nanny because it is easier to use than my robot designation. I will be as helpful as I can."
|
||||
},
|
||||
{
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"index": 8,
|
||||
"speaker": "Trader Romano",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Hello, everyone! I am Romano. I trade salvage with Deal Hunter, always giving the best price. Come by the station if you want to trade."
|
||||
},
|
||||
{
|
||||
@@ -77,7 +77,7 @@
|
||||
{
|
||||
"index": 11,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Thank you for listening!"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
{
|
||||
"index": 1,
|
||||
"speaker": "Kainda",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "¡Hola! Soy la princesa Kainda, la protagonista de la historia. Mi aventura comenzará en breve."
|
||||
},
|
||||
{
|
||||
@@ -29,7 +29,7 @@
|
||||
{
|
||||
"index": 3,
|
||||
"speaker": "Duchess Victoria",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "¡Hola! Soy la duquesa Victoria. También soy la tía de Kainda. No veo la hora de compartir esta aventura contigo."
|
||||
},
|
||||
{
|
||||
@@ -41,13 +41,13 @@
|
||||
{
|
||||
"index": 5,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "¡Hola! Soy la inteligencia artificial que controla la nave. Normalmente me llaman solo Hunter. Tengo muchas ganas de entretenerte con esta historia. Aquí está uno de mis robots, al que Kainda decidió llamar Nanny. Di hola, Nanny."
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"speaker": "Nanny",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "¡Hola! Kainda me llamó Nanny porque es más fácil de usar que mi designación de robot. Seré tan servicial como pueda."
|
||||
},
|
||||
{
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"index": 8,
|
||||
"speaker": "Trader Romano",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "¡Hola a todos! Soy Romano. Compro chatarra al Deal Hunter y siempre ofrezco el mejor precio. Ven a la estación si quieres comerciar."
|
||||
},
|
||||
{
|
||||
@@ -77,7 +77,7 @@
|
||||
{
|
||||
"index": 11,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "¡Gracias por escuchar!"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
{
|
||||
"index": 1,
|
||||
"speaker": "Kainda",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Bonjour ! Je suis la princesse Kainda, l'héroïne principale de cette histoire. Mon aventure commence dans un instant."
|
||||
},
|
||||
{
|
||||
@@ -29,7 +29,7 @@
|
||||
{
|
||||
"index": 3,
|
||||
"speaker": "Duchess Victoria",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Bonjour ! Je suis la duchesse Victoria. Je suis aussi la tante de Kainda. J'ai hâte de partager cette aventure avec toi."
|
||||
},
|
||||
{
|
||||
@@ -41,13 +41,13 @@
|
||||
{
|
||||
"index": 5,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Bonjour ! Je suis l'intelligence artificielle qui dirige le vaisseau. On m'appelle d'ordinaire simplement Hunter. J'ai hâte de te faire découvrir cette histoire. Voici l'un de mes robots, que Kainda a décidé de surnommer Nanny. Dis bonjour, Nanny."
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"speaker": "Nanny",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Bonjour ! Kainda m'a appelée Nanny parce que c'est plus facile à prononcer que ma désignation de robot. Je ferai de mon mieux pour t'être utile."
|
||||
},
|
||||
{
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"index": 8,
|
||||
"speaker": "Trader Romano",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Bonjour à tous ! Je suis Romano. Je fais commerce de ferraille avec le Deal Hunter, et j'offre toujours le meilleur prix. Viens à la station si tu souhaites échanger."
|
||||
},
|
||||
{
|
||||
@@ -77,7 +77,7 @@
|
||||
{
|
||||
"index": 11,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Merci d'avoir écouté !"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
{
|
||||
"index": 1,
|
||||
"speaker": "Kainda",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Ciao! Sono la principessa Kainda, la protagonista della storia. La mia avventura inizierà tra poco."
|
||||
},
|
||||
{
|
||||
@@ -29,7 +29,7 @@
|
||||
{
|
||||
"index": 3,
|
||||
"speaker": "Duchess Victoria",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Ciao! Sono la duchessa Victoria. Sono anche la zia di Kainda. Non vedo l'ora di condividere questa avventura con te."
|
||||
},
|
||||
{
|
||||
@@ -41,13 +41,13 @@
|
||||
{
|
||||
"index": 5,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Ciao! Sono l'intelligenza artificiale che governa la nave. Di solito mi chiamano solo Hunter. Non vedo l'ora di intrattenerti con questa storia. Ecco uno dei miei robot, che Kainda ha deciso di chiamare Nanny. Saluta, Nanny."
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"speaker": "Nanny",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Ciao! Kainda mi ha chiamata Nanny perché è più semplice da usare della mia designazione di robot. Farò il mio meglio per essere utile."
|
||||
},
|
||||
{
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"index": 8,
|
||||
"speaker": "Trader Romano",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Ciao a tutti! Sono Romano. Compro rottami dal Deal Hunter e offro sempre il prezzo migliore. Vieni alla stazione se vuoi scambiare."
|
||||
},
|
||||
{
|
||||
@@ -77,7 +77,7 @@
|
||||
{
|
||||
"index": 11,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Grazie per aver ascoltato!"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
{
|
||||
"index": 1,
|
||||
"speaker": "Kainda",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "こんにちは!物語の主人公、プリンセス・カインダよ。私の冒険はもうすぐ始まるよ。"
|
||||
},
|
||||
{
|
||||
@@ -29,7 +29,7 @@
|
||||
{
|
||||
"index": 3,
|
||||
"speaker": "Duchess Victoria",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "こんにちは!ヴィクトリア公妃よ。カインダのおばでもあるの。この冒険をあなたと一緒にできることを楽しみにしてるよ。"
|
||||
},
|
||||
{
|
||||
@@ -41,13 +41,13 @@
|
||||
{
|
||||
"index": 5,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "こんにちは!この船を操っている人工知能よ。通常は「ハンター」と呼ばれてる。この物語でお楽しみいただくのを楽しみにしてるよ。カインダが「ナニー」と名づけた、私のロボットの一人がいます。ナニー、あいさつをお願いね。"
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"speaker": "Nanny",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "こんにちは!カインダは、私のロボットの型番より呼びやすいって言って「ナニー」と名づけてくれたよ。できるだけ手助けするね。"
|
||||
},
|
||||
{
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"index": 8,
|
||||
"speaker": "Trader Romano",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "こんにちは、みなさん!ロマーノよ。Deal Hunter と廃品回収の取引をしていて、いつも最高の値で買い取るよ。取引したかったらステーションに来てね。"
|
||||
},
|
||||
{
|
||||
@@ -77,7 +77,7 @@
|
||||
{
|
||||
"index": 11,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "最後まで聞いてくれて、ありがとう!"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
{
|
||||
"index": 1,
|
||||
"speaker": "Kainda",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "안녕하세요! 저는 이야기의 주인공 케이이다예요. 제 모험은 곧 시작돼요."
|
||||
},
|
||||
{
|
||||
@@ -29,7 +29,7 @@
|
||||
{
|
||||
"index": 3,
|
||||
"speaker": "Duchess Victoria",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "안녕하세요! 저는 빅토리아 공작이에요. 케이이다의 이모이기도 해요. 이 모험을 여러분이랑 함께하게 돼서 정말 기뻐요!"
|
||||
},
|
||||
{
|
||||
@@ -41,13 +41,13 @@
|
||||
{
|
||||
"index": 5,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "안녕하세요! 저는 이 함선을 운항하는 인공지능이에요. 보통은 그냥 헌터라고 불러요. 이 이야기로 여러분 즐겁게 해 드리는 게 기다려져요. 케이이다가 나니라고 이름 붙여 준 제 로봇 중 한 대가 있어요. 나니, 인사해 줘요!"
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"speaker": "Nanny",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "안녕하세요! 케이이다가 제 로봇 번호보다 쓰기 편하라고 저를 나니라고 불렀어요. 최대한 도와드릴게요!"
|
||||
},
|
||||
{
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"index": 8,
|
||||
"speaker": "Trader Romano",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "여러분, 안녕하세요! 저는 로마노예요. 딜 헌터하고 폐기물 거래를 하면서 항상 제일 좋은 가격에 사드려요. 거래하고 싶으시면 항대로 오세요!"
|
||||
},
|
||||
{
|
||||
@@ -77,7 +77,7 @@
|
||||
{
|
||||
"index": 11,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "들어줘서 고마워요!"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
{
|
||||
"index": 1,
|
||||
"speaker": "Kainda",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Olá! Sou a princesa Kainda, a personagem principal da história. A minha aventura começa em breve."
|
||||
},
|
||||
{
|
||||
@@ -29,7 +29,7 @@
|
||||
{
|
||||
"index": 3,
|
||||
"speaker": "Duchess Victoria",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Olá! Sou a duquesa Victoria. Sou também tia de Kainda. Mal posso esperar para partilhar esta aventura contigo."
|
||||
},
|
||||
{
|
||||
@@ -41,13 +41,13 @@
|
||||
{
|
||||
"index": 5,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Olá! Sou a inteligência artificial que controla a nave. Normalmente chamam-me apenas de Hunter. Estou ansioso para te entreter com esta história. Aqui está um dos meus robôs, que a Kainda decidiu chamar de Nanny. Diz olá, Nanny."
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"speaker": "Nanny",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Olá! A Kainda chamou-me de Nanny porque é mais fácil de usar do que a minha designação de robô. Vou ser tão prestável quanto puder."
|
||||
},
|
||||
{
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"index": 8,
|
||||
"speaker": "Trader Romano",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Olá a todos! Sou o Romano. Compro sucata ao Deal Hunter e sempre ofereço o melhor preço. Vem à estação se quiseres negociar."
|
||||
},
|
||||
{
|
||||
@@ -77,7 +77,7 @@
|
||||
{
|
||||
"index": 11,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Obrigado por ouvires!"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
{
|
||||
"index": 1,
|
||||
"speaker": "Kainda",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Здравствуйте! Я принцесса Кайнда, главный герой этой истории. Моё приключение начнётся совсем скоро."
|
||||
},
|
||||
{
|
||||
@@ -29,7 +29,7 @@
|
||||
{
|
||||
"index": 3,
|
||||
"speaker": "Duchess Victoria",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Здравствуйте! Я герцогиня Виктория. Я также тётя Кайнды. Мне не терпится разделить это приключение с вами!"
|
||||
},
|
||||
{
|
||||
@@ -41,13 +41,13 @@
|
||||
{
|
||||
"index": 5,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Здравствуйте! Я искусственный интеллект, управляющий кораблём. Обычно меня называют просто Хантер. Я с нетерпением жду возможности рассказать вам эту историю. Вот один из моих роботов, которому Кайнда дала имя Нэнси. Поздоровайтесь, Нэнси!"
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"speaker": "Nanny",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Здравствуйте! Кайнда назвала меня Нэнси — это произносится куда проще, чем моё обозначение робота. Постараюсь быть максимально полезной."
|
||||
},
|
||||
{
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"index": 8,
|
||||
"speaker": "Trader Romano",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Здравствуйте, все! Я Романо. Скупаю лом у Deal Hunter и всегда даю лучшую цену. Заходите на станцию, если захотите торговать."
|
||||
},
|
||||
{
|
||||
@@ -77,7 +77,7 @@
|
||||
{
|
||||
"index": 11,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "Спасибо, что слушали!"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
{
|
||||
"index": 1,
|
||||
"speaker": "Kainda",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "大家好!我是凯因达公主,本故事的主人公。我的冒险很快就要开始了。"
|
||||
},
|
||||
{
|
||||
@@ -29,7 +29,7 @@
|
||||
{
|
||||
"index": 3,
|
||||
"speaker": "Duchess Victoria",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "大家好!我是维多利亚女爵,也是凯因达的姑母。我非常期待和你一起分享这段冒险!"
|
||||
},
|
||||
{
|
||||
@@ -41,13 +41,13 @@
|
||||
{
|
||||
"index": 5,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "大家好!我是操控这艘飞船的人工智能。平常大家都叫我「Hunter」。我非常期待用这个故事为你带来乐趣。我的一位机器人同伴——凯因达给她起名叫「南妮」。南妮,打个招呼吧!"
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"speaker": "Nanny",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "大家好!凯因达叫我「南妮」,因为这比我的机器人编号好叫。我会尽力帮上忙!"
|
||||
},
|
||||
{
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"index": 8,
|
||||
"speaker": "Trader Romano",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "大家好,我是罗曼诺!我跟 Deal Hunter 做回收物交易,收购价格一向最优。欢迎到空间站来找我交易!"
|
||||
},
|
||||
{
|
||||
@@ -77,7 +77,7 @@
|
||||
{
|
||||
"index": 11,
|
||||
"speaker": "Deal Hunter",
|
||||
"type": "narration",
|
||||
"type": "dialogue",
|
||||
"text": "感谢收听!"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -55,19 +55,23 @@ LANGUAGES = {
|
||||
}
|
||||
|
||||
# (speaker, type) per utterance, matching the source chapter.
|
||||
# (speaker, type). Type must follow the speaker: the Narrator reads the
|
||||
# introduction, everyone else speaks a line of dialogue. These were all
|
||||
# "narration", which made every row render a narration badge and would tell
|
||||
# UmbraTrans that six characters are not speaking at all.
|
||||
SHAPE = [
|
||||
("Narrator", "narration"),
|
||||
("Kainda", "narration"),
|
||||
("Kainda", "dialogue"),
|
||||
("Narrator", "narration"),
|
||||
("Duchess Victoria", "narration"),
|
||||
("Duchess Victoria", "dialogue"),
|
||||
("Narrator", "narration"),
|
||||
("Deal Hunter", "narration"),
|
||||
("Nanny", "narration"),
|
||||
("Deal Hunter", "dialogue"),
|
||||
("Nanny", "dialogue"),
|
||||
("Narrator", "narration"),
|
||||
("Trader Romano", "narration"),
|
||||
("Trader Romano", "dialogue"),
|
||||
("Narrator", "narration"),
|
||||
("Narrator", "narration"),
|
||||
("Deal Hunter", "narration"),
|
||||
("Deal Hunter", "dialogue"),
|
||||
]
|
||||
|
||||
TRANSLATIONS: dict[str, list[str]] = {
|
||||
|
||||
@@ -101,13 +101,11 @@ def _count_utterances(request: Request) -> int:
|
||||
def _collect_issues(request: Request, code: str, text_count: int) -> list[dict]:
|
||||
"""Issues that need fixing or confirming for *code*.
|
||||
|
||||
Three kinds, all real signals rather than placeholders:
|
||||
no_translation - a translated row exists but the text is empty
|
||||
no_audio - translated but never rendered
|
||||
empty_text - a marker exists whose text is blank
|
||||
|
||||
German issues are largely *absence* problems, which is exactly what the
|
||||
operator needs surfaced: not "0 errors" but "4,307 untranslated".
|
||||
Only genuine content problems are listed here. Deliberately NOT listed:
|
||||
missing staleness markers on the sample render. Those exist because
|
||||
render_lang_test.py does not write markers, not because anything is wrong
|
||||
with the translation - reporting them would send someone hunting a defect
|
||||
that is not there.
|
||||
"""
|
||||
issues: list[dict] = []
|
||||
|
||||
@@ -123,21 +121,19 @@ def _collect_issues(request: Request, code: str, text_count: int) -> list[dict]:
|
||||
}
|
||||
]
|
||||
|
||||
adir = _lang_audio_dir(request, code)
|
||||
missing_audio = 0
|
||||
if adir.exists():
|
||||
for f in sorted(adir.glob("utt*.wav")):
|
||||
if f.with_suffix(".wav.txt").exists():
|
||||
continue
|
||||
missing_audio += 1
|
||||
if missing_audio:
|
||||
if text_count < 25:
|
||||
# Too little translated to call the book ready. This is the honest
|
||||
# headline for any language that has not had a real translation run.
|
||||
issues.append(
|
||||
{
|
||||
"chapter": 1,
|
||||
"index": 0,
|
||||
"kind": "audio missing",
|
||||
"kind": "unconfirmed",
|
||||
"badge": "badge-yellow",
|
||||
"text": f"{missing_audio} rendered clip(s) have no staleness marker.",
|
||||
"text": (
|
||||
f"Only {text_count} of 4,319 utterances translated, and none "
|
||||
f"confirmed. Sample only - not a publishable translation."
|
||||
),
|
||||
}
|
||||
)
|
||||
return issues
|
||||
|
||||
@@ -80,24 +80,23 @@
|
||||
<h1 style="display:flex; align-items:center; gap:0.75rem;">
|
||||
<img src="/static/logo.png" alt="UmbraAudio logo" style="height:56px; width:56px; border-radius:12px;">
|
||||
UmbraAudio Review
|
||||
<span class="badge badge-blue" style="font-size:0.9rem; padding:0.4rem 0.9rem; display:inline-flex; align-items:center; gap:0.5rem;" title="Project: {{ ap.slug }}">
|
||||
Active project: <strong style="color:#e0e7ff">{{ ap.name }}</strong>
|
||||
</span>
|
||||
{# Spec 30 MOCKUP: language dropdown beside Active project. It belongs here rather
|
||||
than on one page because it changes what every page shows. This partial is a
|
||||
placeholder for spec 30's active_language selector; it posts nowhere yet. #}
|
||||
<span style="margin-left:auto; font-size:0.9rem; display:inline-flex; align-items:center; gap:0.5rem;">
|
||||
<label for="lang-select" style="color:#94a3b8;">Content language:</label>
|
||||
<select id="lang-select"
|
||||
onchange="window.location.href = '/language-mockup?lang=' + this.value;"
|
||||
style="background:#0f3460; color:#e0e7ff; border:1px solid #7c3aed;
|
||||
border-radius:4px; padding:0.35rem 0.5rem; font-size:0.9rem; cursor:pointer;">
|
||||
{% for c, name in (languages or []) %}
|
||||
<option value="{{ c }}" {% if c == code %}selected{% endif %}>{{ name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<span class="badge badge-blue" style="font-size:0.9rem; padding:0.4rem 0.9rem; display:inline-flex; align-items:center; gap:0.5rem; max-width:28rem;" title="Project: {{ ap.slug }}">
|
||||
<span style="overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">
|
||||
Active project: <strong style="color:#e0e7ff">{{ ap.name }}</strong>
|
||||
</span>
|
||||
</span>
|
||||
{# Spec 30 MOCKUP: the language selector is a page that opts in by overriding
|
||||
this block, rather than base.html rendering a global control from context
|
||||
that most pages do not pass. An earlier version keyed off a `languages`
|
||||
variable here, which produced an empty 38px dropdown with zero options on
|
||||
every page that did not supply it - i.e. most of them. #}
|
||||
{% block header_extra %}{% endblock %}
|
||||
</h1>
|
||||
{# Spec 30: pages override header_extra to place the language selector. It has
|
||||
its own row rather than sitting inside the h1 flex row, which cannot fit a
|
||||
long project name plus a 10-item dropdown before the dropdown is pushed
|
||||
past the right edge. #}
|
||||
{% block header_bar %}{% endblock %}
|
||||
<nav class="nav">
|
||||
<a href="/">Dashboard</a>
|
||||
<a href="/speakers">Speakers</a>
|
||||
|
||||
@@ -1,9 +1,36 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{# The selector belongs beside Active project, but base.html's header is a single
|
||||
flex row with no room for it next to a long project name - it clipped off the
|
||||
right edge. It gets its own row below the header instead, which is also where
|
||||
it stays put when the project name is short. #}
|
||||
{% block header_bar %}
|
||||
<div style="display:flex; align-items:center; gap:0.75rem; flex-wrap:wrap;
|
||||
margin:-1rem 0 1.5rem; padding:0.6rem 0.9rem;
|
||||
background:#16213e; border:1px solid #333; border-radius:8px;">
|
||||
<label for="lang-select" style="color:#94a3b8; font-size:0.9rem; white-space:nowrap;">
|
||||
Content language:
|
||||
</label>
|
||||
<select id="lang-select"
|
||||
onchange="window.location.href = '/language-mockup?lang=' + this.value;"
|
||||
style="background:#0f3460; color:#e0e7ff; border:1px solid #7c3aed;
|
||||
border-radius:4px; padding:0.4rem 0.75rem; font-size:0.95rem;
|
||||
font-weight:600; cursor:pointer; min-width:10rem;">
|
||||
{% for c, name in languages %}
|
||||
<option value="{{ c }}" {% if c == code %}selected{% endif %}>{{ name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<span style="color:#64748b; font-size:0.8rem;">
|
||||
Applies to the whole book — every chapter and every speaker.
|
||||
</span>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div style="border:2px dashed #7c3aed; border-radius:8px; padding:0.6rem 1rem; margin-bottom:1.25rem; background:#1e1b4b;">
|
||||
<strong style="color:#c4b5fd">MOCKUP — spec 30.</strong>
|
||||
<span style="color:#94a3b8; font-size:0.85rem">Read-only. The language dropdown in the header is the proposed permanent placement.</span>
|
||||
<span style="color:#94a3b8; font-size:0.85rem">Read-only. The language selector sits in the header row, beside <em>Active project</em>.</span>
|
||||
</div>
|
||||
|
||||
{# ------------------------------------------------------------------ coverage #}
|
||||
|
||||
Reference in New Issue
Block a user