case-forge / shared /i18n.py
nextmarte's picture
Add deterministic numeric-consistency checker (flags prose number slips)
f725a35 verified
Raw
History Blame Contribute Delete
7.33 kB
"""i18n compartilhado — EN default + PT. Interface inclusa (requisito do hackathon).
Uso:
from shared import i18n
i18n.t("dream.title", "en") # -> "Dream Library"
i18n.t("dream.title", "pt") # -> "Biblioteca dos Sonhos"
i18n.LANGS # [("English","en"), ("Português","pt")]
Chaves são namespaced por app (`dream.*`, `iris.*`, `common.*`) p/ os apps do
monorepo dividirem este dicionário sem colidir. Inglês é a fonte da verdade;
faltando a tradução PT, cai no EN.
"""
LANGS = [("English", "en"), ("Português", "pt")]
DEFAULT = "en"
_T = {
# ---- comum a todos os apps ----
"common.language": {"en": "Language", "pt": "Idioma"},
"common.loading": {"en": "Working…", "pt": "Processando…"},
"common.error": {"en": "Something went wrong.", "pt": "Algo deu errado."},
# ---- dream-library ----
"dream.title": {"en": "Dream Library", "pt": "Biblioteca dos Sonhos"},
"dream.tagline": {
"en": "Narrate a dream → see its image → watch your symbols connect over time.",
"pt": "Narre um sonho → veja a imagem → acompanhe seus símbolos se conectarem no tempo.",
},
"dream.tab_new": {"en": "New dream", "pt": "Novo sonho"},
"dream.tab_library": {"en": "Library", "pt": "Acervo"},
"dream.tab_graph": {"en": "Symbol graph", "pt": "Grafo de símbolos"},
"dream.record": {"en": "Narrate your dream", "pt": "Narre seu sonho"},
"dream.lang_spoken": {"en": "Spoken language", "pt": "Idioma falado"},
"dream.btn_weave": {"en": "Weave the dream", "pt": "Tecer o sonho"},
"dream.transcript": {"en": "What you said", "pt": "O que você disse"},
"dream.symbols": {"en": "Symbols", "pt": "Símbolos"},
"dream.image": {"en": "Dream image", "pt": "Imagem do sonho"},
"dream.status_stt": {"en": "Listening to your dream…", "pt": "Ouvindo seu sonho…"},
"dream.status_symbols": {"en": "Finding the symbols…", "pt": "Encontrando os símbolos…"},
"dream.status_image": {"en": "Painting the dream…", "pt": "Pintando o sonho…"},
"dream.status_done": {"en": "Added to your library.", "pt": "Adicionado ao seu acervo."},
"dream.empty_audio": {"en": "Record or upload a dream first.",
"pt": "Grave ou envie um sonho primeiro."},
"dream.library_empty": {"en": "No dreams yet — narrate your first one.",
"pt": "Nenhum sonho ainda — narre o primeiro."},
"dream.graph_empty": {"en": "Your symbol graph grows as you add dreams.",
"pt": "Seu grafo de símbolos cresce conforme você adiciona sonhos."},
"dream.graph_hint": {"en": "Click a symbol to see the dreams it appears in.",
"pt": "Clique num símbolo para ver os sonhos em que ele aparece."},
"dream.filtered_by": {"en": "Dreams with", "pt": "Sonhos com"},
"dream.clear_filter": {"en": "Show all", "pt": "Mostrar todos"},
# ---- case-forge ----
"cf.title": {"en": "Case Forge", "pt": "Case Forge"},
"cf.tagline": {
"en": "Pick a topic → forge a Harvard-style teaching case + teaching note, ready for class.",
"pt": "Escolha um tema → forje um caso de ensino estilo Harvard + nota de ensino, pronto pra aula.",
},
"cf.tab_forge": {"en": "Forge a case", "pt": "Forjar caso"},
"cf.tab_case": {"en": "The case", "pt": "O caso"},
"cf.tab_note": {"en": "Teaching note", "pt": "Nota de ensino"},
"cf.domain": {"en": "Domain", "pt": "Disciplina"},
"cf.domain_ph": {"en": "e.g. strategy, marketing, public management",
"pt": "ex.: estratégia, marketing, gestão pública"},
"cf.topic": {"en": "Topic / central tension", "pt": "Tema / tensão central"},
"cf.topic_ph": {
"en": "e.g. a coffee chain deciding whether to adopt dynamic pricing",
"pt": "ex.: uma rede de cafeterias decidindo adotar preço dinâmico",
},
"cf.level": {"en": "Audience level", "pt": "Nível do público"},
"cf.content_lang": {"en": "Case language", "pt": "Idioma do caso"},
"cf.theory": {"en": "Theory to exercise (optional)", "pt": "Teoria a exercitar (opcional)"},
"cf.theory_ph": {"en": "e.g. price elasticity, Porter's five forces",
"pt": "ex.: elasticidade-preço, cinco forças de Porter"},
"cf.btn_forge": {"en": "Forge the case", "pt": "Forjar o caso"},
"cf.btn_example": {"en": "Try an example", "pt": "Ver um exemplo"},
"cf.status_forging": {"en": "Forging your case…", "pt": "Forjando seu caso…"},
"cf.status_done": {"en": "Case ready.", "pt": "Caso pronto."},
"cf.status_invalid": {
"en": "Generated, but the structure has gaps — try forging again.",
"pt": "Gerado, mas a estrutura tem falhas — tente forjar de novo.",
},
"cf.empty_topic": {"en": "Describe a topic or tension first.",
"pt": "Descreva um tema ou tensão primeiro."},
"cf.result_empty": {"en": "Your case and teaching note will appear here.",
"pt": "Seu caso e a nota de ensino aparecem aqui."},
"cf.export": {"en": "Export", "pt": "Exportar"},
"cf.download_md": {"en": "Download Markdown", "pt": "Baixar Markdown"},
"cf.download_html": {"en": "Download printable HTML", "pt": "Baixar HTML imprimível"},
"cf.btn_regen": {"en": "Regenerate", "pt": "Regerar"},
"cf.edit_source": {"en": "Markdown (editable)", "pt": "Markdown (editável)"},
"cf.preview": {"en": "Preview", "pt": "Pré-visualização"},
"cf.edit_hint": {
"en": "Edit the text on the left — the preview and exports update live.",
"pt": "Edite o texto à esquerda — a prévia e os downloads atualizam na hora.",
},
"cf.quality": {"en": "Quality checks", "pt": "Selos de qualidade"},
"cf.q_schema": {"en": "Structure complete", "pt": "Estrutura completa"},
"cf.q_noleak": {"en": "Dilemma kept open", "pt": "Dilema sem resposta vazada"},
"cf.q_objectives": {"en": "≤4 measurable objectives", "pt": "≤4 objetivos mensuráveis"},
"cf.q_sourced": {"en": "Evidence is sourced", "pt": "Dados com fonte"},
"cf.demo_note": {
"en": "Showing a sample case (model not loaded in this environment).",
"pt": "Exibindo um caso de amostra (modelo não carregado neste ambiente).",
},
"cf.busy_note": {
"en": "⚡ The GPU is busy or the free quota was reached — showing a sample meanwhile. Try forging again in a moment.",
"pt": "⚡ A GPU está ocupada ou a cota grátis acabou — exibindo uma amostra. Tente forjar de novo em instantes.",
},
"cf.numcheck_title": {"en": "Numbers to double-check", "pt": "Números pra conferir"},
"cf.disclaimer": {
"en": "Figures are illustrative/fictional — verify them before classroom use.",
"pt": "Números são ilustrativos/fictícios — confira antes de usar em aula.",
},
}
def t(key: str, lang: str = DEFAULT) -> str:
entry = _T.get(key)
if not entry:
return key
return entry.get(lang) or entry.get(DEFAULT) or key
def code_for(label: str) -> str:
"""Mapeia o rótulo do dropdown ('English'/'Português') p/ o código ('en'/'pt')."""
for name, code in LANGS:
if name == label:
return code
return DEFAULT