Amal lida com toda a complexidade dos diacríticos árabes: 8 marcas de tashkeel (fatha, damma, kasra, shadda, sukun, fathatan, dammatan, kasratan), 4 variantes de alef (padrão, madda, hamza acima, hamza abaixo, wasla), 3 variantes de hamza (isolado, sobre waw, sobre yeh) e ligaduras Lam-Alef. O reconhecimento de fala, a renderização de texto e a pontuação de similaridade do aplicativo tratam o árabe diacritizado ("كَتَبَ") de forma diferente do árabe não diacritizado ("كتب") — uma distinção crucial que muitos apps de aprendizado de árabe ignoram.
Por que os Diacríticos São Importantes para o Aprendizado
O Problema da Ambiguidade
O árabe sem diacríticos é ambíguo:
- "كتب" pode significar:
- "kataba" (ele escreveu) — tempo passado
- "kutub" (livros) — substantivo plural
- "kutiba" (foi escrito) — voz passiva
Todos são escritos da mesma forma sem os diacríticos. Os diacríticos eliminam a ambiguidade.
Progressão do Aprendizado
- Iniciante: Aprender a ler COM diacríticos (fácil — vogais marcadas)
- Intermediário: Praticar COM diacríticos até se tornar automático
- Avançado: Gradualmente remover diacríticos, a leitura fica mais difícil
- Fluente: Ler sem diacríticos fluentemente (leitura em nível nativo)
A maioria dos apps de aprendizado de árabe ignora o passo 1 — eles não ensinam os diacríticos ou os removem. Isso gera maus hábitos. A progressão do Amal é cientificamente correta.
Nossa Implementação em Nível Unicode
Marcas Diacríticas (8 no total)
// lib/src/utils/arabic_extension.dart
class ArabicExtension {
static const Map<String, String> tashkeelMarks = {
'FATHA': '\u064E', // َ (vogal 'a')
'DAMMA': '\u064F', // ُ (vogal 'u')
'KASRA': '\u0650', // ِ (vogal 'i')
'SUKUN': '\u0652', // ْ (sem vogal)
'SHADDA': '\u0651', // ّ (letra duplicada)
'FATHATAN': '\u064B', // ً (tanween 'an')
'DAMMATAN': '\u064C', // ٌ (tanween 'un')
'KASRATAN': '\u064D', // ٍ (tanween 'in')
};
static const Map<String, String> alefVariants = {
'ALEF_STANDARD': 'ا', // ا
'ALEF_WITH_MADDA': 'آ', // آ (alongado)
'ALEF_WITH_HAMZA_ABOVE': 'أ', // أ
'ALEF_WITH_HAMZA_BELOW': 'إ', // إ
'ALEF_WASLA': 'ٰ', // ٰ (alef conectivo)
};
static const Map<String, String> hamzaVariants = {
'HAMZA_ISOLATED': 'ء', // Hamza isolado
'HAMZA_ON_WAW': 'ؤ', // Hamza sobre waw (و + hamza)
'HAMZA_ON_YEH': 'ئ', // Hamza sobre yeh (ي + hamza)
};
}
Diacríticos Corânicos e Paradas Uthmani
Para Thurayya, suportamos marcas específicas do Alcorão:
static const Map<String, String> quranicMarks = {
'STOP_FULL': 'ۖ', // Parada completa (‖)
'STOP_HALF': 'ۗ', // Parada meia
'STOP_QUA': 'ۙ', // Parada Qua
'STOP_NECESSARY': 'ۚ', // Parada necessária
'TAJWEED_ELONGATION': '', // Indicador de alongamento
};
Reconhecimento de Fala Compatível com Diacríticos
Viés de Contexto com Diacríticos
Quando uma criança está aprendendo "كَتَبَ" (ele escreveu, passado), direcionamos o reconhecimento de fala para essa vocalização exata:
# src/services/stt_client.py
def recognize_with_diacritical_context(audio_bytes, expected_text):
# expected_text = "كَتَبَ" (com diacríticos)
# Criar dica de contexto de fala
speech_context = {
'phrases': [expected_text],
'boost': 20.0 # Grande ênfase para o texto esperado
}
# Enviar para o Google Cloud STT
response = google_stt_client.recognize(
audio=audio_bytes,
language_code='ar-SA',
speech_contexts=[speech_context]
)
# Resultado: Google STT é direcionado à pronúncia "kataba"
return response
Pontuação de Similaridade Consciente de Diacríticos
def compare_pronunciations(expected, actual):
"""
expected: "كَتَبَ" (com diacríticos)
actual: "كتب" (tentativa da criança, possivelmente sem diacríticos)
"""
# Remover diacríticos para comparação grosseira
expected_base = strip_diacritics(expected) # "كتب"
actual_base = strip_diacritics(actual) # "كتب"
# Similaridade base (ignorando diacríticos)
base_similarity = string_similarity(expected_base, actual_base) # 1.0 (perfeito)
# Bônus de diacríticos (se tentativa inclui diacríticos)
diacritic_bonus = 0.0
if has_diacritics(actual):
diacritic_accuracy = diacritics_match_ratio(expected, actual)
diacritic_bonus = diacritic_accuracy * 0.15 # Até +15% por diacríticos corretos
# Pontuação final
final_score = min(base_similarity + diacritic_bonus, 1.0)
return {
'base_score': base_similarity,
'diacritic_bonus': diacritic_bonus,
'final_score': final_score,
'feedback': 'Ótimo! A pronúncia está perfeita. Agora, pratique as marcas diacríticas.'
}
Isso significa:
- Criança diz "كتب" (sem diacríticos) → pontuação 85-90% (base correta, faltando diacríticos)
- Criança diz "كَتَبَ" (totalmente diacritizado) → pontuação 98%+ (perfeito)
- Progressão clara: primeiro dominar pronúncia base, depois detalhes diacríticos
Desafios na Renderização RTL
Gerenciamento de Direção do Texto
// lib/src/screens/lesson_screen.dart
Column(
children: [
Directionality(
textDirection: TextDirection.rtl, // Para texto árabe
child: Text(
'كَتَبَ',
textAlign: TextAlign.right, // Alinhado à direita para RTL
style: TextStyle(
fontFamily: 'IBMPlexSansArabic',
fontSize: 36,
height: 1.8, // Altura extra para diacríticos
),
),
),
// Instruções em inglês abaixo
Directionality(
textDirection: TextDirection.ltr, // Para inglês
child: Text(
'Pronounce: "he wrote"',
textAlign: TextAlign.left, // Alinhado à esquerda para LTR
),
),
],
)
Formação das Letras Conectadas
Letras árabes mudam de forma dependendo da posição:
- Isolada: "ك" (Kaf)
- Inicial: "كَـــ" (Kaf no início da palavra)
- Medial: "ـــكَـــ" (Kaf no meio)
- Final: "ـــكَ" (Kaf no fim)
A fonte IBMPlexSansArabic forma automaticamente as letras, mas precisamos das sequências Unicode corretas:
// Correto: usa caracteres de ligação Unicode
String word = 'ك' + '\u0640' + 'ت' + '\u0640' + 'ب'; // Kashida (caractere de extensão)
// Incorreto: concatenação direta
String word = 'ك' + 'ت' + 'ب'; // Pode não formar corretamente em alguns dispositivos
Mixagem de Texto Bidirecional
Quando inglês e árabe aparecem juntos:
RichText(
textDirection: TextDirection.rtl, // RTL geral
text: TextSpan(
children: [
TextSpan(text: 'means ', style: englishStyle), // LTR
TextSpan(text: 'كتاب', style: arabicStyle), // RTL
TextSpan(text: ' (book)', style: englishStyle), // LTR
],
),
)
Resultado: "means كتاب (book)" exibido com fluxo bidirecional correto.
Perguntas Frequentes
P: Por que forçar diacríticos para iniciantes? Isso não dificulta?
A: Inicialmente, sim. Mas aprender com diacríticos cria associações mais fortes entre letra e som. Pesquisas mostram que o aprendizado com diacríticos acelera a fluência. Depois de dominar com diacríticos, ler sem eles é uma progressão natural.
P: E se o teclado do meu filho não suporta digitar diacríticos?
A: O app nunca pede para as crianças digitarem diacríticos. O reconhecimento e pronúncia são baseados em fala. Apenas adultos (professores, criadores de conteúdo) precisam inserir diacríticos, usando teclados árabes especializados.
P: Amal suporta combinações diacríticas não padrão?
A: Suportamos todas as combinações padronizadas pelo Unicode. Combinações raras ou customizadas podem não renderizar corretamente, mas o árabe moderno e o corânico padrão são totalmente suportados.



