- A tipografia árabe na web é um problema de infraestrutura de renderização em que se entrelaçam conexão entre letras, texto bidirecional, tratamento de números e pontuação, e alinhamento de linhas, sendo difícil tratá-lo como um simples bug de CSS
- A composição árabe clássica implementava o alinhamento justificado não aumentando o espaço entre palavras, mas sim com o kashida, alongando traços internos das letras; já o
text-align: justifydos navegadores modernos aumenta principalmente o espaço entre palavras - Em árabe, um único codepoint armazenado muda conforme o contexto para formas isolada, inicial, medial e final, e sem recursos OpenType e um motor de shaping, as letras são renderizadas separadas
- Arabic Presentation Forms no Unicode, sistemas numéricos, o algoritmo bidirecional UAX #9 e caracteres de controle invisíveis levam a problemas reais de produto, como falhas de busca, números de telefone invertidos e confusão no movimento do cursor
- Fundamentos essenciais como HarfBuzz, Amiri e os W3C Arabic Layout Requirements já foram construídos, mas o alinhamento árabe nos navegadores e o uso de
jstfcontinuam sendo lacunas de implementação
Ponto de partida: o problema de composição árabe que parecia um “bug de CSS”
- Em um dashboard voltado a clientes, parágrafos em árabe com conteúdo misto não eram renderizados com alinhamento justificado como no layout aprovado pelo design, e a borda esquerda ficava irregular
- A versão em caracteres latinos do mesmo bloco parecia “fine”, mas no árabe as linhas começam pela direita, então a borda irregular aparece à esquerda
- Mesmo aplicando
text-align: justify, não era possível preencher a linha alongando traços dentro das palavras como no formato aprovado pela equipe de design - No mesmo produto, já haviam ocorrido antes problemas com separação de letras em nomes em PDFs, falhas de indexação de busca e codepoints Unicode legados em árabe
- A essência do problema não está em um defeito de uma folha de estilo específica, mas sim no estado da tipografia árabe na web
O problema que a tradição manuscrita resolvia
- A tradição clássica de manuscritos árabes justificava a linha não aumentando o espaço entre palavras, mas alongando os traços de conexão dentro da forma das letras
- Esse método é chamado de taṭwīl ou, no termo técnico moderno, kashida, e consiste em estender o traço de ligação entre determinados pares de letras
- Uma página bem composta em Naskh do século XVII alinha as duas margens e cria uma textura densa e regular sem ampliar o espaçamento entre palavras
- O al-khaṭṭ al-mansūb, sistematizado por Ibn Muqla, organizava as formas das letras com base em elementos como o ponto em forma de losango da ponta do cálamo, a altura do alif e proporções de arcos
- Nessa tradição, o alinhamento de linhas não era um problema de distribuir espaços, mas um problema de shaping que escolhia formas de letras e glifos alternativos
Uma letra, quatro formas
- O árabe é uma escrita sempre conectada, como a cursiva, sem a distinção entre letras de forma e manuscritas
- Cada letra muda para forma isolada, inicial, medial ou final conforme as letras vizinhas, e seis letras não se conectam à frente, interrompendo o fluxo dentro da palavra
- O Unicode armazena letras abstratas, a fonte fornece glifos posicionais e o motor de shaping aplica recursos OpenType como
isol,init,medi,fina,rlig,markemkmk - Uma palavra como
محمدocupa quatro codepoints no armazenamento, mas na renderização passa por várias seleções de glifos e consultas OpenType para aparecer como um único traço contínuo - Sem um motor de shaping como o HarfBuzz, ou quando um gerador de PDF não passa por ele, os mesmos codepoints são renderizados como letras isoladas e separadas
Os fósseis do Unicode: Arabic Presentation Forms
- Nos code pages de 8 bits da era DOS e do início do Windows, codificavam-se não letras abstratas, mas as próprias formas como inicial e medial como caracteres separados
- O Unicode aceitou isso por compatibilidade de ida e volta, e isso permanece nos blocos Arabic Presentation Forms de U+FB50 até U+FEFF
- Esses codepoints não deveriam aparecer em documentos novos, mas extratores de texto de PDF ainda podem emiti-los hoje
- Se o mesmo nome for armazenado uma vez em Unicode moderno e outra em Presentation Forms, ele parecerá igual na tela, mas comparação de strings e busca o tratarão como diferente
- Aplicar normalização NFKC pode reduzir falhas de busca ao converter Presentation Forms em letras abstratas
Software que pulou shaping e tratamento bidirecional
- Softwares que ignoram o motor de shaping e o algoritmo bidirecional desenham as letras uma por uma em forma isolada e dispõem a linha da esquerda para a direita
- Esse tipo de saída é algo que leitores de árabe realmente encontram em letreiros de lojas, cartões de embarque, marcas d’água e legendas árabes em filmes antigos
- Versões antigas do Photoshop, a configuração padrão do matplotlib, vários geradores de PDF no npm e impressoras de recibo podem produzir esse problema
- Soluções alternativas comuns em Python, como
arabic_reshaperepython-bidi, usam o bloco Presentation Forms para embutir no texto uma forma já “moldada” antecipadamente - Esse desvio coloca dentro da string um trabalho que deveria ser feito pelo renderizador, revelando assim uma falha fundamental da pilha de texto
Três tipos de números e o problema da pontuação
- Os dígitos 0–9 que o mundo chama de “Arabic numerals” não são, para a maioria dos leitores de árabe, a forma de número usada no dia a dia
- Egito, Sudão, Levante, Iraque e países do Golfo usam os ARABIC-INDIC DIGITS do Unicode:
٠١٢٣٤٥٦٧٨٩ - A região do Magrebe usa glifos de números latinos, e Irã, Afeganistão e Paquistão usam os EXTENDED ARABIC-INDIC DIGITS:
۰۱۲۳۴۵۶۷۸۹ - Em UAX #9, números não são tratados como caracteres fortes, mas fracos, e são reclassificados como números europeus ou árabes conforme a direcionalidade do caractere forte anterior
- Um número de telefone como
010-1234-5678após uma palavra em árabe pode ter a ordem exibida como5678-1234-010, porque o hífen é tratado como neutro - A solução oferecida pelas plataformas é isolar a direcionalidade envolvendo o número com
ou<bdi> - Os separadores decimal e de milhar no mundo árabe são U+066B
٫e U+066C٬; eles parecem quase iguais ao ASCII.e,, mas têm codepoints e propriedades bidirecionais diferentes
Desvios e simplificações do impresso à web
- O Kitāb Ṣalāt al-Sawāʿī, impresso em Fano em 1514, foi o primeiro livro árabe em tipos móveis e mostra casos de letras desconectadas e erros na posição dos pontos
- O Qurʾān de Paganini, impresso em Veneza em 1537, acumulou erros de composição e erros de texto, fracassou comercialmente e um exemplar foi encontrado em 1987 na biblioteca de um mosteiro em Veneza
- A história da proibição otomana da impressão tem o problema de que os textos originais dos decretos de Bayezid II e Selim I não sobreviveram, e ela depende de relatos de viajantes europeus
- A Bulaq Press, no Cairo, foi fundada por Muhammad Ali em 1820 e elevou a qualidade dos tipos metálicos árabes com centenas de peças de tipo e muita paciência
- O Qurʾān do Cairo de 1924 foi produzido em tipos metálicos na Amiria Press e contribuiu para a padronização textual e tipográfica do século XX
- No fim dos anos 1950, Kamel Mrowa e a Linotype criaram o Simplified Arabic para se adequar a revistas de 90 canais, fundindo formas iniciais com mediais, finais com isoladas e reduzindo ligaturas
- O Simplified Arabic tornou possível uma produção de jornais barata e rápida e, em uma geração, dominou as redações árabes
O kashida que a web ainda não consegue desenhar
- Rascunhos iniciais do CSS Text Module Level 3 incluíam o valor
kashidaparatext-justify, e o Internet Explorer 5.5 implementou isso em 2000 - O IE 5.5 também oferecia a propriedade
text-kashida-space, mas, como nenhum outro navegador a implementou, esse valor acabou saindo da especificação - No Chrome, Firefox e Safari atuais,
text-align: justifyem árabe funciona ampliando o espaço entre palavras - A issue sobre alinhamento árabe no CSS Working Group está aberta pelo menos desde 2015, e o trabalho do W3C Arabic Layout Requirements também começou naquele ano
- O alinhamento com kashida exige que shaping e layout renegociem iterativamente em nível de linha, porque glifos alongados mudam a largura, essa mudança altera as quebras de linha e isso muda novamente o alongamento necessário
- O OpenType já tinha desde os anos 1990 a tabela
jstf, pela qual fontes poderiam informar prioridades de justificação, mas motores de shaping quase nunca a leem e criadores de fontes quase nunca a fornecem - Microsoft Word e InDesign Middle East Edition oferecem alinhamento com kashida, mas o conjunto de renderizadores de navegador em que as pessoas mais leem ainda não consegue alongar as letras
O hack com Tatweel e os problemas de ligaturas e diacríticos
- Um desvio comum na web é inserir no próprio texto o caractere U+0640 TATWEEL para fazê-lo parecer um traço alongado
- Como o Tatweel altera o conteúdo, ele causa problemas em correspondência de busca, copiar e colar, leitores de tela e refluxo de colunas
- O traço desenhado por Tatweel não é um kashida posicionado segundo as regras da fonte e dos caracteres, mas uma barra de estilo máquina de escrever inserida por tentativa do autor
- As ligaturas OpenType se dividem em
rlig,ligaedlig, e se uma ligatura obrigatória comolām-alifquebra, o texto deixa de estar apenas feio: ele fica errado - Inserir U+200C ZERO WIDTH NON-JOINER entre letras preserva os caracteres armazenados, mas força a renderização de cada letra em forma isolada
- O Safari ignora
"rlig" 0e"liga" 0, então demos para desativar ligaturas obrigatórias não têm efeito nele - Amiri é uma fonte Naskh lançada por Khaled Hosny em 2011 sob a SIL Open Font License e, após a reescrita 1.0 em 2022, passou a oferecer kashidas curvos e empilhamento refinado de diacríticos
- Componentes de cartão com
line-height: 1eoverflow: hiddenpodem cortar os diacríticos superiores de árabe totalmente vocalizado
O algoritmo bidirecional e o cursor que mente
- Números de versão, identificadores em inglês, URLs e palavras em francês dentro de um parágrafo em árabe acionam o UAX #9, o Unicode Bidirectional Algorithm
- Letras árabes são tratadas como caracteres fortes da direita para a esquerda, letras latinas como fortes da esquerda para a direita, números como fracos dependentes do contexto e espaços e pontuação como neutros
- O algoritmo atribui uma classe direcional a cada caractere, interpreta progressivamente caracteres fracos e neutros, depois atribui níveis de embedding e inverte runs com o mesmo nível
- Como a ordem visual na tela difere da ordem lógica na memória, mover o cursor, clicar com o mouse e selecionar texto exige tradução contínua entre essas duas ordens
- Nas fronteiras entre runs existem duas posições legítimas de cursor, uma lógica e outra visual, e Chrome, Firefox, Qt e Outlook podem tratá-las de formas diferentes
- Escrever texto misto árabe-inglês continua sendo, mesmo em 2026, uma experiência com alto custo cognitivo por padrão em editores importantes, clientes de e-mail e aplicativos de chat
- Um intervalo como
الصفحات 10-20pode parecer “de 20 a 10” por causa da regra W2 e do tratamento neutro do hífen, e isso pode ser corrigido colocando U+200E LEFT-TO-RIGHT MARK antes
A base que funciona e as lacunas restantes
- Khaled Hosny criou a Amiri, escreveu a ferramenta de linha de comando
hb-shapedo HarfBuzz e também atua como co-mantenedor do HarfBuzz - Behdad Esfahbod escreveu grande parte do HarfBuzz antes de Hosny e contribuiu para o motor de shaping que hoje desenha corretamente letras árabes nos navegadores
- A Brill encomendou a John Hudson a fonte Brill para incluir todos os caracteres de transliteração necessários ao catálogo Semitics e a lançou gratuitamente para uso não comercial em 2011
- O Sakhr AX-170 era um computador MSX saudita-kuwaitiano que exibia árabe em ROM por volta de 1984 e suportava identificadores em Arabic BASIC escritos da direita para a esquerda
- HarfBuzz, Amiri, Scheherazade, o suporte a Presentation Forms no GNU Unifont, Noto Arabic e a documentação do W3C Arabic Layout dependem fortemente do esforço de poucas pessoas, organizações e voluntários
- Os fornecedores de navegadores adotaram o HarfBuzz depois que ele ficou pronto e gratuito, mas contribuíram muito pouco para o loop de layout que implementaria na tela o método de alinhamento da tradição manuscrita
- A lacuna restante é um algoritmo bem compreendido que precisa ser implementado em alguns motores de layout, e a margem esquerda irregular no dashboard do cliente é a forma visível para o usuário dessa falta de investimento
1 comentários
Comentários do Lobste.rs
Texto realmente impressionante
E eu gosto do fato de que este caractere
﷽é um único code point. É curioso copiar e testarDizem que significa “Em nome de Alá, o mais misericordioso, o mais compassivo”
﷽, esta frase do texto é poética“Um monumento de uma época em que ninguém confiava nos motores de renderização, então a renderização era embutida na codificação. Como uma mosca recitadora preservada para sempre dentro do âmbar”
Foi divertido seguir as referências do link da Wikipedia citado aqui: https://lobste.rs/c/dq2ucz
Resumindo, esse caractere entrou no Unicode porque estava em uma code page do Paquistão, e entrou lá porque havia uma exigência legal de incluir essa frase em documentos jurídicos. Como o urdu é uma língua indo-europeia, com a tecnologia da época provavelmente era difícil “fazer uma chamada externa” para uma code page árabe só para escrever a Basmallah
Infelizmente, nem todos os comentários mostram o melhor daquela comunidade
Meta: este é mais um ótimo exemplo de que textos assim precisam da tag
typographyNo lobste.rs, as tags servem principalmente para filtragem
A propriedade
text-justifydo IE, nossa, havia muitas coisas interessantes naquela época. Também existiatext-justify: newspaper, e décadas depois alguns passaram a descrever isso como Knuth-Plass ou algo parecido, mas não acredito que fosse isso de fatohttps://mediumwell.com/wp-content/uploads/… mostra um comportamento que na época era apresentado como
text-justify: newspapere que bate com otext-justify: inter-characterda especificação atualO IE realmente tinha muitos recursos legais bem cedo, e outros navegadores deixaram esse tipo de recurso na cesta do “difícil demais”. No fim, alguns nunca voltaram, e outros só voltaram 15 ou 30 anos depois. O Firefox ganhou
text-justify: inter-characterem 2017, o Chromium só implementou essa parte há alguns meses, e o Safari ainda não tem issoArtigo incrivelmente excelente e informativo. Gostei especialmente do contexto histórico, que deu uma visão ampla para toda a história
Como alguém com formação em história e também carreira em TI, este texto acertou em cheio nos meus dois interesses
Há algo no texto que faz meu detector de LLM apitar, o que é uma pena. Isso porque ele tem profundidade e trata de partes menos documentadas da stack tecnológica moderna
Um exemplo de trecho que soa como LLM é este, e senti isso ao longo do texto:
“A razão pela qual nenhum navegador oferece isso é estrutural, e como obstáculo essa estrutura é bastante elegante. A justificação latina trata o texto já modelado como algo fixo, mede as palavras, despeja o espaço restante nos espaçamentos e termina. Shaping e layout ficam cada um em sua própria caixa, e toda stack de texto em operação é projetada em torno dessa separação. A justificação com Kashida abre essa caixa à força.”
Eu gostaria de perguntar ao @lr0 se o corpo deste texto foi gerado, refinado ou traduzido com LLM. Se sim, talvez valha a pena ajustar o nível de controle que o LLM tem sobre a saída final. Posts antigos do blog, por exemplo https://lr0.org/blog/p/gpt/ e https://lr0.org/blog/p/linux_new_users/ , pareciam muito mais humanos