Traduzindo a IU
Pivotick escreve seu próprio texto: o trilho, os menus, a barra lateral, a tabela, o painel dinâmico, o histórico, os brindes e cada dica de ferramenta title e aria-label atrás deles. A opção i18n coloca tudo no seu idioma.
const graph = new Pivotick(container, data, {
i18n: { locale: 'fr' },
})O texto que você entrega à biblioteca é desenhado exatamente como fornecido e nunca pesquisado: rótulos de nós e bordas, rótulos de facetas e legendas, nomes de pivô, modos de trilho, guias de encaixe, ações da barra superior e as linhas que você adiciona a um menu de contexto. Traduza-os antes de passá-los.
Idiomas incluídos
Cada compilação inclui traduções completas da UI integrada:
| Idioma | Local | Exemplo de tags regionais |
|---|---|---|
| Inglês (padrão) | en | en-GB, en-US |
| Chinês simplificado | zh | zh-CN, zh-Hans |
| Francês | fr | fr-FR, fr-CA |
| Alemão | de | de-DE, de-CH |
| Português | pt | pt-BR, pt-PT |
Defina i18n.locale para selecionar um. As tags regionais usam o mesmo catálogo de idiomas, mantendo suas próprias regras de formatação, classificação e plural de números. O catálogo chinês utiliza caracteres simplificados; não há tradução separada para o chinês tradicional. Um código de idioma sem um catálogo incluído usa o inglês, a menos que você forneça messages ou translate. A omissão de locale mantém o padrão em inglês existente; o idioma do navegador não foi detectado.
Os catálogos são exportados como messagesEn, messagesZh, messagesFr, messagesDe, messagesPt e juntos como bundledMessages, também disponível em Pivotick em compilações de navegador.
A opção
| Propriedade | Tipo | Padrão | Descrição |
|---|---|---|---|
locale | string | 'en' | Uma tag BCP 47 como 'fr', 'de-CH' ou 'pt-BR'. Ele escolhe as regras plurais, como os números são escritos e como as listas são classificadas. Quando fornecido, também é definido como lang da raiz do gráfico. |
messages | Partial<Messages> | {} | Substituições por chave. As chaves ausentes usam o idioma incluído e depois o inglês. |
translate | (key, params, fallback) => string | undefined | Uma ponte para sua própria biblioteca de tradução, solicitada por cada chave messages não possui. |
A linguagem é definida quando o gráfico é construído. Para trocá-lo, chame graph.destroy() e construa o gráfico novamente com as novas opções.
Como uma mensagem é encontrada
Cada trecho de texto é pesquisado nesta ordem e a primeira resposta vence:
- A opção própria do recurso, quando tiver uma:
UI.emptyState.render,UI.busyIndicator.label,UI.simplify.typeLabel, outitleeconfirmLabelvocê passa paractx.confirm(). Estes são mais específicos do que qualquer catálogo. messages, sua tabela de chaves.translate, sua ponte.- O idioma incluído, selecionado por
locale. - Inglês, quando o idioma não possui catálogo empacotado.
Substituições parciais são suportadas: altere apenas os termos que seu aplicativo precisa e o restante usa o idioma selecionado. Idiomas não suportados passam para o inglês sem aviso prévio.
Chaves e mensagens
Cada mensagem possui uma chave pontilhada estável com o nome de onde aparece: 'contextMenu.node.pin', 'history.menu.empty', 'sidebar.neighbors.connections'. As chaves são digitadas no catálogo em inglês, então em TypeScript uma chave com erro ortográfico falha na compilação e seu editor completa o resto.
Uma mensagem assume uma de três formas.
Texto com espaços reservados
Uma string, com {name} onde vai um valor:
messages: {
'search.result.inGroup': 'dans {group}',
'history.menu.count': '{count} sur {limit}',
}Um número é escrito da maneira que o código do idioma o escreve antes de entrar: 1,234 em 'en', 1.234 em 'de', 1 234 em 'fr'. Uma string entra conforme está escrita.
Formas plurais
Uma mensagem que depende de uma contagem é um objeto com uma entrada por categoria plural que a linguagem utiliza. A categoria é escolhida no parâmetro count pelo Intl.PluralRules do navegador, então as regras são aquelas que CLDR define para o código do idioma. other é obrigatório, pois todos os idiomas o possuem.
// English and French need two forms; French counts zero as one
'count.nodes': { one: '{count} nœud', other: '{count} nœuds' },
// Polish needs four: 1 węzeł, 3 węzły, 5 węzłów, 1,5 węzła
'count.nodes': { one: '{count} węzeł', few: '{count} węzły', many: '{count} węzłów', other: '{count} węzła' },As categorias são zero, one, two, few, many e other. Uma forma que a linguagem não usa nunca é escolhida e a que falta retorna para other.
O Fallback English mantém as regras plurais do inglês em qualquer localidade. Por exemplo, uma linguagem não suportada que trata zero como singular ainda obtém "0 nós" do substituto em inglês.
Uma função
Para qualquer coisa que um modelo não possa dizer, uma mensagem pode ser uma função dos parâmetros brutos e do I18n do gráfico:
'simplify.typeLabel': ({ count, type }, i18n) =>
`${i18n.formatNumber(Number(count))} ${type === 'ip' ? 'adresses IP' : type}`,Seja qual for a sua forma, uma mensagem é texto. Ele é inserido como texto, nunca analisado como HTML, então <b> aparece como está escrito.
Editando arquivos de tradução PO
O diretório locales/ do repositório contém um modelo gettext, pivotick.pot, e arquivos zh.po, fr.po, de.po e pt.po completos. Esses arquivos também são enviados no pacote npm. Abra um arquivo .po no Poedit ou qualquer editor de texto UTF-8. Cada msgctxt é a chave de mensagem estável; msgid é a fonte em inglês e msgstr é a tradução. Mantenha {placeholders} intacto. Para entradas no plural, traduza cada slot msgstr[n]: o chinês tem apenas other, e o francês, o alemão e o português têm one e depois other. O tempo de execução usa Intl.PluralRules, com many voltando para other, em vez de avaliar o cabeçalho gettext como JavaScript.
De uma verificação de origem com npm ci concluída:
# Refresh the template and merge English changes into the PO files
npm run i18n:extract
# Edit locales/*.po, finish empty entries and review any fuzzy translations
# Compile PO files into the TypeScript catalogues used by every build
npm run i18n:compile
# Check completeness, source text, placeholders, plurals and generated files
npm run i18n:check
npm run test:i18nEnvie os arquivos PO, o modelo e os arquivos src/i18n/locales/*.ts gerados juntos. Não edite os arquivos gerados diretamente. A extração preserva as traduções existentes e os comentários do tradutor, marca o texto alterado em inglês como fuzzy e deixa as novas entradas vazias. Resolva essas entradas antes de compilar. As chaves removidas são eliminadas do catálogo ativo. npm run build executa i18n:check, portanto, uma tradução incompleta ou um catálogo gerado desatualizado falha na construção. Esses comandos usam dependências existentes do Node; nenhuma instalação do sistema gettext é necessária.
Para agrupar outro idioma, adicione seu mapeamento de localidade e slot plural a scripts/i18n.mjs, extraia e traduza o novo arquivo PO, compile-o e exporte o catálogo gerado de src/i18n/locales/index.ts e adicione-o a bundledMessages. Para uma linguagem somente de aplicação, passar um catálogo como i18n.messages ainda funciona sem alterar Pivotick.
Iniciando um catálogo de messagesEn
O catálogo em inglês é exportado como messagesEn, da compilação ES e como Pivotick.messagesEn das compilações do navegador. Ele contém todas as chaves com seu texto em inglês e são dados simples, portanto podem ser escritos como o arquivo a partir do qual seus tradutores iniciam:
import { messagesEn } from 'pivotick'
console.log(JSON.stringify(messagesEn, null, 4))Carregue o arquivo traduzido de volta como messages. Em TypeScript, um catálogo declarado com satisfies Messages deve nomear cada chave, então uma chave adicionada em uma versão posterior aparece como um erro de compilação em vez de uma string perdida em inglês:
import type { Messages } from 'pivotick'
export const messagesFr = {
'count.nodes': { one: '{count} nœud', other: '{count} nœuds' },
// …every other key
} satisfies MessagesUse Partial<Messages> para traduzir conforme você avança.
Construindo uma ponte com sua própria biblioteca de tradução
Se o seu aplicativo já traduz através de uma biblioteca, translate mantém uma fonte de verdade e uma mudança de idioma. É chamado para toda chave messages não possui, com:
key: a chave da mensagem, como'count.nodes';params: os valores brutos, com números não formatados, portanto, aplicam-se as regras de plural e número da sua biblioteca;fallback: o texto em inglês, já preenchido.
Retorne uma string para usá-la ou undefined para usar o idioma incluído e depois o inglês. Aqui com i18next, cujo parâmetro count já direciona seus plurais:
const graph = new Pivotick(container, data, {
i18n: {
locale: i18next.language,
translate: (key, params, fallback) => {
const found = i18next.exists(`pivotick.${key}`)
return found ? i18next.t(`pivotick.${key}`, params) : undefined
},
},
})Seus arquivos de recursos então escrevem suas mensagens na própria sintaxe da sua biblioteca ("{{count}} nœuds" em i18next), sob as mesmas chaves.
Um translate lançado é capturado: o console diz qual chave e o idioma incluído (ou inglês para um idioma não suportado) é mostrado. O gancho ainda recebe o inglês como argumento fallback, preservando o contrato de ponte. Quando messages e translate ambos têm uma chave, messages vence e translate não é solicitado.
Números, listas, classificação e lang
locale abrange mais do que palavras. Abaixo dele:
- Contagens são escritas com
Intl.NumberFormat: "1.234 nós" em inglês, "1.234 Knoten" em alemão. O Fallback English também usa a formatação de número do local selecionado. - Listas de nomes em uma frase são unidas por
Intl.ListFormat: "a, b e c", "a, b et c". - Classifica na tabela, a lista de vizinhos e o painel de triagem pivô usam
Intl.Collator, então "Émile" classifica ao lado de "Emma", o sueco coloca "ä" depois de "z" e "item 10" vem depois de "item 9".
Quando você declara um locale, o elemento raiz do gráfico o obtém como lang, assim como as partes que a biblioteca monta fora da raiz (dicas de ferramentas, menus suspensos, listas de sugestões). Os leitores de tela leem a interface com a voz certa. Sem um locale, nenhum lang é definido: o texto da biblioteca é em inglês, mas seus dados dentro do gráfico estão no idioma da sua página, e o lang da própria página o descreve melhor.
O layout da direita para a esquerda não é suportado: não há manipulação de dir e a interface é disposta da esquerda para a direita em todos os idiomas.
Um idioma por gráfico
Cada gráfico tem sua própria linguagem. Dois gráficos em uma página podem usar dois idiomas e nenhum deles afeta o outro.
Um gráfico dentro de um gráfico fala o de seu pai: o subgráfico desenhado dentro de um cluster e o gráfico de pequenos vizinhos na barra lateral.
O texto que a biblioteca grava em seus dados é escrito uma vez, na linguagem do gráfico: um rótulo de entrada do histórico ("Hid 3 nós") e o corpo com o qual uma nova nota começa. Reconstruir o gráfico em outro idioma deixa tudo como estava.
No código: graph.i18n e plugins
graph.i18n é a linguagem do gráfico, o mesmo objeto com o qual a biblioteca escreve:
| Membro | O que isso faz |
|---|---|
locale | A tag em uso: sua ou 'en'. |
t(key, params?) | O texto de uma mensagem integrada, através do lookup acima. |
formatNumber(value, options?) | Um número nos dígitos da localidade. Leva Intl.NumberFormat opções. |
formatList(items, options?) | Itens unidos como uma frase. Leva Intl.ListFormat opções. |
compare(a, b) | Um comparador na ordem do código do idioma, seguro para passar para sort como está. |
collator(options?) | O Intl.Collator atrás de compare, numérico por padrão. |
Um plugin lê o mesmo objeto que ctx.i18n. O texto que o plugin escreve é o do plugin a ser traduzido, digitado em ctx.i18n.locale; formatar suas contagens e classificar suas listas através de ctx.i18n as mantém consistentes com o restante do gráfico.
const nodeCounter = {
name: 'node-counter',
install(ctx) {
const words = { fr: 'Total', de: 'Gesamt' }
const label = words[ctx.i18n.locale.split('-')[0]] ?? 'Total'
const count = ctx.i18n.formatNumber(ctx.graph.getNodes().length)
// …draw `${label}: ${count}`
},
}O que permanece como está
- Seus dados. Rótulos de nós e arestas, nomes de propriedades e valores são desenhados como estão. Um nome de propriedade sem um rótulo declarado é colocado no título de sua chave (
first_seenlê "Primeiro Visto"); declarenodePropertiesMapouedgePropertiesMappara nomeá-lo em seu idioma. A linhaidque as listas de propriedades adicionam acima de suas próprias chaves é escrita como a chave que é. - Texto do desenvolvedor. Os avisos do console e erros gerados permanecem em inglês.
- Glifos principais.
⌃ ⇧ ⌥ ⌘são mostrados como estão. Os nomes das teclas são mensagens (keys.ctrlCombo,keys.escape), portanto, uma interface em alemão pode dizerStrg+Z. - Badge conta na borda de um nó (
2k,99+), que deve caber em três caracteres.