Skip to content

Tutorial 5 Localization pt

James Morris edited this page Jul 29, 2026 · 1 revision

Tutorial 5 · Localização (i18n)

Meta: entender como o LockedIn CLI fala 33 idiomas — e praticar direcionar um agente para adicionar mais um. Localização é uma tarefa fantástica para um agente: é mecânica o suficiente para delegar, mas tem restrições reais (uma barreira de testes, regras de layout, revisão gramatical) que te ensinam a revisar.

← Anterior: Tutorial 4 Prompts e Revisão · Voltar para Início


O que "localizado" significa aqui

Execute a CLI em espanhol, hindi, japonês, chinês simplificado, ou qualquer idioma incluído, e tudo muda — o splash, a tabela de ajuda, a saída de cada comando, a sessão de chat, até a letra miúda legal. Não só as piadas: a superfície visível inteira.

lockedin --lang pt post
LOCKEDIN_LANG=hi lockedin
lockedin --lang zh aura

O idioma é autodetectado na inicialização, resolvido em ordem de prioridade:

  1. a flag --lang (--lang pt, --lang=fr, -l ja)
  2. a variável de ambiente LOCKEDIN_LANG
  3. seu locale (LC_ALL / LC_MESSAGES / LANG, depois o locale do sistema/runtime)
  4. inglês, como reserva

normalizeLang() normalmente usa o subtag primário do locale. Isso significa que de-DE seleciona de, mas tlh não se torna tl por acidente; os aliases reais fil e tgl mapeiam intencionalmente para tagalo (tl), o norueguês nb e nn mapeiam para no, o indonésio legado in mapeia para id, e o hebraico legado iw mapeia para he. Dois códigos regionais são preservados literalmente em vez de dobrados para seu subtag primário: pt-BR/pt_BR selecionam o código regional canônico enquanto o pt genérico continua sendo o bundle de português do Brasil compatível com versões anteriores (ambos são português do Brasil e compartilham os mesmos pools/UI), e en-SG/en_SG mantêm o singlish (o en genérico continua sendo inglês). O chinês tradicional de Hong Kong é o mesmo tipo de exceção: zh-HK, zh_HK.UTF-8 e zh-Hant-HK selecionam zh-HK, enquanto o zh genérico e as tags continentais selecionam chinês simplificado (zh).

Trocando em pleno voo — o painel /language. A CLI sempre pôde começar em outro idioma (--lang, LOCKEDIN_LANG); agora você pode trocar no meio da sessão. Digite /language (aliases /lang e /languages) para listar os 33 idiomas por código, cada um em sua própria escrita; /language el troca pelo resto da sessão. O ponto é a rota de fuga: depois de uma troca, ela redesenha no novo idioma e então, no idioma que você acabou de deixar, imprime o caminho exato de volta — /language en agora, lockedin --lang en da próxima vez — para que cair sem querer em 日本語 ou ಕನ್ನಡ nunca te deixe preso. (Troque duas vezes e o idioma que seu LOCKEDIN_LANG nomeia também é oferecido.) --lang e LOCKEDIN_LANG permanecem inalterados. Assim como o /a11y, é um utilitário sincero, não parte da sátira.

A ideia: bundles de idioma

Todo o texto traduzível vive em bundles, um por idioma, cada um com esta forma:

{ meta: { lang: 'pt', name: 'Português', dir: 'ltr' },
  pools: { HOOKS: [ /* ~25 */ ], LESSONS: [ /* ... */ ], /* ... */ },
  ui:    { buzzwordDensity: 'Densidade de buzzwords: ', /* labels, títulos */ } }
  • pools são os arrays de conteúdo (as piadas) que você viu no Capítulo 2.
  • ui são os textos de interface: labels, títulos e pequenos templates.

Inglês é o bundle de referência dentro de src/lockedin.js; os outros 32 módulos de bundle vivem em src/content/*.js: ar, bn, bo, de, el, en-SG, es, eu, fa, fi, fr, he, hi, id, is, it, ja, kn, ms, nl, no, pl, pt, pt-BR, ru, sv, tl, tr, uk, ur, zh, e zh-HK (pt-BR reutiliza os pools/UI do pt, mas é registrado separadamente). Cada um é registrado em BUNDLES; SUPPORTED_LANGS é gerado a partir dessas chaves, e renderHelp() imprime essa lista gerada. Nenhum bundle de UI codifica a lista de forma fixa.

setLang('fr');       // aponta o idioma ativo para o bundle francês
// L = pools ativos, U = ui ativo
pick(L.HOOKS)        // um gancho em francês
U.buzzwordDensity    // "Densité de jargon : "

Como todo renderizador lê L e U (nunca uma string fixa), setLang sozinho muda toda a experiência. Esse é o truque inteiro.

A rede de segurança: paridade de chaves

Aqui está a invariante que torna seguro adicionar um idioma:

Todo bundle deve expor exatamente as mesmas chaves de pools e ui que o inglês.

Um teste impõe isso nos 33 bundles. Se você adicionar uma string de UI nova em inglês e esquecer de traduzi-la em ucraniano, npm test fica vermelho e te diz qual chave está faltando. Você não consegue publicar silenciosamente um idioma meio traduzido.

A parte difícil: layout do terminal

Idiomas estressam o layout do terminal de formas diferentes:

  • Japonês, chinês simplificado e chinês tradicional de Hong Kong usam caracteres East Asian Wide / Fullwidth. vw() os conta como duas colunas, e wrap() quebra à força tokens longos sem espaço para que o texto CJK continue dentro dos cartões e caixas.
  • Hindi e canarês usam marcas combinantes não espaçadas/envolventes (Mn / Me), como matras e viramas. vw() as conta como zero colunas para que não inflem a largura medida.
  • box() quebra cada linha do corpo antes de preenchê-la, então um banner traduzido longo não consegue mais furar a borda.
  • Cada bundle define sentenceEnd e listSep (por exemplo . / , , / ) para que frases compostas por geradores soem naturais.

Quando você adiciona um idioma, as strings de cabeçalho do cartão (cardSubtitle, cardMeta, cardFooter) ainda precisam caber em ≤ 60 colunas visíveis. Árabe, persa, hebraico e urdu definem meta.dir: 'rtl'. A saída não contém controles bidi por padrão, porque alguns terminais os renderizam como labels em caixas. LOCKEDIN_BIDI=on ativa explicitamente isolamentos equilibrados depois da quebra de linha para terminais conhecidos por suportá-los, preservando ANSI, comandos ASCII e a ordem lógica de copiar/colar. A saída acessível sempre remove esses controles. Sem essa opção explícita, a ordenação RTL/LTR mista pode ser menos sofisticada; nunca sonde ou infira suporte.

A parte sorrateira: gramática em torno da entrada bruta do usuário

Alguns templates de UI inserem cláusulas brutas do usuário com placeholders como {cap}. Não os traduza posição por posição. A frase precisa continuar gramatical quando o placeholder for uma frase que o usuário digitou, não um substantivo arrumadinho.

Um bug real de cautela: templates em japonês que colocam logo depois de {cap} podem soar errados quando {cap} é uma cláusula completa. O conserto não é "traduzir com mais força"; é reestruturar o template (por exemplo, adicionar um nominalizador ou mover o placeholder) para que a entrada arbitrária do usuário ainda se encaixe.

✅ Experimente com seu agente — adicione um idioma

Este exercício continua funcionando exatamente da mesma forma. Escolha um idioma que você consiga verificar (ou peça ao agente que verifique), e conduza-o de ponta a ponta. Escreva a especificação primeiro:

Adicione dinamarquês (da). Crie src/content/da.js como um bundle { meta, pools, ui } com as mesmas chaves do inglês, traduzindo cada entrada (pools de conteúdo com ~25 cada, todas as strings de UI). Registre da em BUNDLES em src/lockedin.js. --lang da e um locale da-* devem selecioná-lo. Mantenha as strings de cabeçalho do cartão dentro do limite de largura. npm test deve continuar verde, e adicione invariantes

  • testes de detecção em dinamarquês espelhando os já localizados.

Depois rode o ciclo dos Capítulos 3–4:

  1. Plano primeiro. "Antes de escrever código, me diga quais arquivos você vai mudar e como vai manter a paridade de chaves com o inglês."
  2. Testes primeiro. "Adicione testes que falham: detecção de da, paridade de chaves para da, e uma invariante de reflect/connect em dinamarquês. Não crie o bundle ainda."
  3. Implemente. "Agora crie src/content/da.js traduzindo um bundle existente chave por chave, registre-o, e faça os testes passarem. Apenas pick/shuffle para a aleatoriedade."
  4. Barreira + revisão. npm test, depois lockedin --lang da post — e leia o diff: cada chave foi traduzida? As bordas do cartão continuam alinhadas? Os templates com {cap} sobrevivem a cláusulas brutas do usuário?

Exercícios de aquecimento menores se um idioma inteiro for demais:

  • "Adicione mais um TAGLINE a todos os 33 bundles de idioma, mantendo as contagens iguais."
  • "Verifique se o cardFooter em canarês tem ≤ 60 colunas visíveis e explique como as marcas combinantes foram medidas."
  • "Me mostre o teste que falharia se eu apagasse uma chave ui de ja.js."

Para onde ir a seguir

  • Passe os olhos por src/content/es.js — ainda é um template amigável para um bundle novo.
  • Releia docs/HANDOFF.md → "Adding a language".
  • Aproveite as piadas multilíngues na Referência de Comandos.

Esse é o tutorial completo. Você já consegue direcionar um agente de IA para construir funcionalidades e localizá-las atrás de uma barreira de testes — em 33 idiomas e pronto para mais. Concorda? 👇

📘 LockedIn CLI wiki

Tutorial

Reference


Satire · Sátira · 風刺. Not affiliated with LinkedIn. GPL-3.0-or-later.

Clone this wiki locally