"""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