O MOJ roda competições com times de vários países. A interface existe em português, inglês e espanhol, e toda tela ou string nova nasce nos três. String só em PT é bug, como doc atrasada.
Há dois eixos de idioma, e eles não se misturam:
| Eixo | O que decide | Onde mora |
|---|---|---|
| Interface | rótulos, botões, avisos, datas, papel impresso, relatório, DM de convite | web/shared/i18n.js (LANG) +
LOCALE do contest |
| Documentos | enunciado, caderno, info sheet, folha de TL, editorial | STATEMENT_LANGS, DOC_LANGS,
?lang= do /contest/statement e
/contest/doc |
Um contest pode ter a interface em espanhol e oferecer o enunciado em português e espanhol, por exemplo.
JavaScript. Toda string de exibição passa por
T(pt, en, es):
T('Enviar solução', 'Submit solution', 'Enviar solución')es é: ausente cai no en, e o
en ausente cai no pt. Passar null
num argumento vale como ausente.t('chave') lê o dicionário STR do
i18n.js, que também tem o es.uiLocale() (pt-BR /
en-US / es-419). Nunca escreva
'pt-BR' fixo.T() no topo do módulo congela o idioma antes de o
LOCALE do contest ser aplicado. Rótulo de aba, estado ou
tipo é fábrica preguiçosa:
const TABS = () => [...], chamada no render.pt/en/es e o render chama
T(x.pt, x.en, x.es).HTML estático. O PT fica no conteúdo; o inglês e o
espanhol vão em atributos que o shared/i18n-dom.js
aplica:
| Atributo | Alvo |
|---|---|
data-en / data-es |
textContent |
data-en-html / data-es-html |
innerHTML (raro) |
data-en-ph / data-es-ph |
placeholder |
data-en-title / data-es-title |
title |
<html data-en-doctitle data-es-doctitle> |
document.title |
A troca é reversível. Na primeira aplicação o PT é guardado em
data-pt*, e voltar a PT restaura. Sem data-es,
o espanhol mostra o data-en.
Precedência do idioma.
LOCALE do contest, quando explícito.
As páginas de contest chamam
setLang(basic.locale, {persist:false}) e não mostram
seletor.?lang= da URL. É o idioma da visita,
da interface e do enunciado. Serve para o link que alguém manda
(convocação de sede, tutorial). Ele grava a escolha.shared/lang-toggle.js), guardado em moj_lang
no localStorage.es-* dá es,
pt-* dá pt, e o resto dá en.Não se traduz: veredictos (a string vem do servidor; só o rótulo em volta), enunciados, título de problema, nome de contest, de time ou de pessoa, corpo de notícia, tags e nomes de país das bandeiras.
O servidor fala o idioma do contest (LOCALE =
pt|en|es).
contest_locale_ok (lib/common.sh) é a fonte
única do que os escritores aceitam: admin/settings,
admin/config (basic.locale),
create, duplicate e template.
Valor fora da lista dá 422 locale_invalid,
sempre antes de qualquer escrita.
| Saída | Como escolhe o texto |
|---|---|
Folha de rosto da impressão e folha de balão
(lib/print.sh) |
_pr_t <lang> <chave>; nome da cor por
pr_color_name <hex> <lang> |
Documentos da prova (lib/contest-docs.sh) |
_doc_t <lang> <chave> (eixo dos
documentos) |
Relatório offline (score/report-gen.sh) |
rep_t <chave> pelo LOC; os módulos
JS inlinados ganham um T() com a mesma cascata |
DM de convite (lib/invite-notify.sh) |
contest en ou es manda o idioma do contest
e o PT no mesmo texto |
| Checklist da Central, encerrar evento, bloqueios de rodada | cada item leva label/detail (PT) +
label_en/detail_en +
label_es/detail_es |
Mensagens de erro da API (error.message) ficam em PT. O
cliente mostra o code, ou traduz.
Papel impresso. O idioma entra na validade do cache.
O meta da tarefa carimba sheet_lang, e a troca do
LOCALE refaz a folha no próximo pedido. O nome da cor do
balão é gravado na tarefa no idioma do contest daquele momento
(color_name + color_lang), então a fila do
staff e o relatório mostram o nome gravado. A folha usa o nome no idioma
atual. O carimbo de rodapé das páginas de código é ASCII (filtro do
ImageMagick): a palavra "tarefa/task/tarea" não leva acento.
O espanhol é latino-americano neutro, com o vocabulário da ICPC LATAM. Instruções usam tú ("revisa", "actívalo", "no cuentes esta portada").
| PT | ES | Nota |
|---|---|---|
| time, equipe | equipo | |
| submissão, envio | envío | "enviar solución" |
| placar | marcador | "tabla de posiciones" quando o contexto pedir |
| balão | globo | |
| juiz / juiz-chefe | juez / juez principal | |
| sede | sede | |
| congelamento (freeze) | congelamiento | "freeze" pode ficar entre parênteses |
| enunciado | enunciado | |
| prova, competição, contest | competencia | |
| revisão | revisión | |
| calibração | calibración | |
| caderno de problemas | cuadernillo | |
| lista de problemas | lista de problemas | |
| inscrição | inscripción | |
| convite | invitación | |
| rodada | ronda | |
| aquecimento | calentamiento | |
| coorte | cohorte | |
| impressão | impresión | |
| fila | cola | |
| linguagem (de programação) | lenguaje | "idioma" é só língua natural |
| veredicto | veredicto | o texto do veredicto não se traduz |
| login | usuario | "login" fica em contexto técnico (conta .admin,
campo) |
| sessão | sesión | |
| telão | pantalla | o sistema Animeitor mantém o nome |
| clarification | aclaración | nunca "consulta"/"pregunta" |
| gate (de UA, de navegador) | gate | jargão, como no PT |
| trava (de sede, de login) | bloqueo | "cola trabada" = fila travada é outro sentido |
| reservar (pegar p/ responder/julgar) | reservar | nunca "reclamar" |
| relatório (report) | informe | nunca "reporte" |
| log (do juiz) | registro |
Nomes do painel de admin (a Central, os avisos e os tutoriais citam com o mesmo nome):
| PT | EN | ES |
|---|---|---|
| Central | Home | Central |
| Prova | Contest | Competencia |
| Pessoas | People | Personas |
| Operação | Operations | Operación |
| Evento | Event | Evento |
| Máquinas | Machines | Máquinas |
| Módulos | Modules | Módulos |
| Documentos | Documents | Documentos |
| Coortes | Cohorts | Cohortes |
| Rodadas | Rounds | Rondas |
| Balões | Balloons | Globos |
| Situação | Status | Situación |
| Sessões | Sessions | Sesiones |
| Times | Teams | Equipos |
| Regras (Central › Regras) | Rules | Reglas |
| Juízes | Judges | Jueces |
| Gate & trava | Gate & lock | Gate y bloqueo |
| Clarification (botão da nav) | Clarification | Aclaraciones |
A documentação de USUÁRIO também existe em inglês e espanhol: os manuais de papel e os guias de autoria que as telas trilíngues linkam. A documentação técnica (OVERVIEW, FLOW, API, DEPLOY…) fica só em português.
Onde mora. O PT docs/<DOC>.md é a
fonte. As traduções ficam em docs/en/<DOC>.md e
docs/es/<DOC>.md, com o mesmo nome. A lista dos docs
traduzidos é UMA: o DOCS_I18N do docs/i18n.sh.
O espelho em JS é o DOCS_I18N de
web/shared/i18n.js.
Carimbo. A 1ª linha de cada tradução diz de qual PT
ela veio:
<!-- i18n-source: <DOC>.md blob:<git hash-object do PT> -->.
Mudou um doc da lista? No MESMO commit:
bash docs/i18n.sh diff <DOC>. Ele mostra o
que mudou no PT desde o carimbo.docs/en/<DOC>.md e em
docs/es/<DOC>.md.bash docs/i18n.sh stamp <DOC>.O server/test/smoke-docs-i18n.sh é a porta (também roda
no make check). Ele reprova tradução atrasada, estrutura
diferente do PT (títulos, blocos de código, tabelas, imagens), comando
alterado, link quebrado, marca de português no espanhol e as duas listas
diferentes. bash docs/i18n.sh status mostra o estado de
cada doc.
Doc novo na lista. Acrescente o nome nas DUAS
listas, crie en/ e es/, rode
stamp. Troque os links da interface:
<a href="/docs/X.html" data-en-href="/docs/en/X.html" data-es-href="/docs/es/X.html">;docHref('X').O i18n-coverage.sh reprova link para doc traduzido sem
isso.
Regras de tradução:
Estilo. O inglês segue o STE (Simplified Technical English):
O espanhol é latino-americano neutro, com as mesmas regras e o glossário acima.
Não se traduz: código, comando, caminho, chave
de conf/JSON, rota, sufixo de papel (.admin,
.cjudge…) e saída da CLI (a CLI fala português).
bash/sh/console/conf/json
fica igual ao PT, byte a byte. Só os comentários # se
traduzem, inclusive o texto em português dentro de um comando.Rótulo de tela. Escreva exatamente como a
interface o mostra naquele idioma. A fonte é o
T('pt','en','es') e o
data-en/data-es da tela citada.
Exemplo de enunciado. O bloco
```markdown do ENUNCIADO e do PACOTE é traduzido, porque é
o que o autor daquele idioma escreve. Use os títulos de seção do idioma:
## Input, ## Output, ## Notes, e
## Entrada, ## Salida,
## Observaciones.
Links. O build (docs/build-html.sh
+ docs/md2html-links.lua) resolve os links sozinho:
X.md vai para o doc do mesmo idioma, ou para o PT se
X não é traduzido;/docs/X.html vai para
/docs/<lang>/X.html;?lang=<lang>. O
?lang= GRAVA a escolha, então o leitor do manual em inglês
chega ao site em inglês.smoke-lang-toggle.gjs.sh: seletor, cascata do
T, data-es ida e volta, ?lang=es
e navegador es-AR. Também
data-en-href/data-es-href e
docHref().smoke-docs-i18n.sh: a documentação traduzida em dia com
o PT. Ele se prova numa árvore sintética.i18n-coverage.sh: T() de 3 argumentos,
data-es junto de cada data-en, marca de
português no espanhol e link para doc traduzido.smoke-print-render.sh: tabelas
_pr_t/pr_color_name, sheet_lang e
refazer na troca.smoke-contest-report.sh: bloco LOCALE=es,
sem PT nem EN vazando.smoke-registration.sh: DM ES + PT.smoke-contest-{settings,admin,create}.sh:
es aceito, inválido = 422.smoke-preflight.sh,
smoke-contest-finish.sh,
smoke-contest-rounds.sh: *_es em todo
item.