Quais estratégias existem para garantir que todas as operações com reconhecimento de local sejam tratadas corretamente em todas as localidades?

9

Um pouco por necessidade, eu desenvolvo software com minha localidade definida como "C" ou "en_US". É difícil usar uma localidade diferente porque eu só falo uma língua com qualquer coisa, mesmo com uma fluência que se aproxime remotamente.

Como resultado, muitas vezes eu ignoro as diferenças de comportamento que podem ser introduzidas por ter diferentes configurações de localidade. Não surpreendentemente, ignorar essas diferenças, às vezes, leva a bugs que são descobertos apenas por algum usuário infeliz usando uma localidade diferente. Em casos particularmente ruins, esse usuário pode nem mesmo compartilhar um idioma comigo, tornando o processo de relatório de bug um desafio. E, importante , muito do meu software está na forma de bibliotecas; enquanto quase nada define a localidade, ela pode ser combinada com outra biblioteca ou usada em um aplicativo que faz definir o comportamento de geração de localidade que eu nunca experimentei.

Para ser um pouco mais específico, os tipos de erros que tenho em mente não estão faltando localizações de texto ou erros no código para usar essas localizações. Em vez disso, quero dizer erros nos quais uma localidade altera o resultado de alguma API com reconhecimento de local (por exemplo, toupper(3) ) quando o código que usa essa API não previu a possibilidade de tal alteração (por exemplo, na localidade turca, toupper não altera "i" para "I" - potencialmente um problema para um servidor de rede tentar falar um protocolo de rede específico para outro host).

Alguns exemplos desses bugs no software que mantenho:

No passado, uma abordagem que tomei para lidar com isso é escrever testes de regressão que explicitamente mudam o local para um em que o código era conhecido por não funcionar, exercitar o código, verificar o comportamento correto e restaurar o original localidade. Isso funciona bem, mas somente depois que alguém reportou um bug, e ele cobre apenas uma pequena área de uma base de código.

Outra abordagem que parece possível é ter um sistema de integração contínua (CIS) configurado para executar um conjunto completo de testes em um ambiente com um conjunto de códigos de idiomas diferente. Isso melhora um pouco a situação, dando tanta cobertura em um local alternativo como o conjunto de testes normalmente fornece. Outra falha é que existem muitos, muitos, muitos locais, e cada um deles pode causar problemas diferentes. Na prática, provavelmente existem apenas cerca de uma dúzia de maneiras diferentes de um local quebrar um programa, mas ter dezenas de configurações extras de testes está sobrecarregando os recursos (particularmente para um projeto que já está esticando seus limites de recursos testando em diferentes plataformas, contra bibliotecas diferentes versões, etc).

Outra abordagem que me ocorreu foi usar (possivelmente primeiro criando) uma nova localidade que é radicalmente diferente da localidade "C" de todas as formas possíveis - ter um mapeamento de caso diferente, usar um separador de milhares diferente, formato datas diferente, etc. Esta localidade pode ser usada com uma configuração extra do CIS e esperamos que ela seja usada para capturar quaisquer erros no código que possam ser acionados por qualquer localidade.

Esse local de teste já existe? Existem falhas com essa ideia para testar a compatibilidade de localidade?

Quais outras abordagens para testes locais foram tomadas pelas pessoas?

Estou principalmente interessado em locais POSIX, uma vez que esses são os que eu conheço. No entanto, sei que o Windows também tem alguns recursos semelhantes, portanto, informações adicionais (talvez com mais informações básicas sobre como esses recursos funcionam) talvez também possam ser úteis.

    
por Jean-Paul Calderone 28.02.2012 в 16:13
fonte

2 respostas

3

Eu apenas audito seu código para usos incorretos de funções como toupper . No modelo de localidade C, essas funções devem ser consideradas como operando apenas em texto em idioma natural no idioma do local. Para qualquer aplicativo que lide com texto potencialmente multilíngue, isso significa que funções como tolower não devem ser usadas de forma alguma .

Se seu destino for POSIX, você terá um pouco mais de flexibilidade devido à função uselocale , que possibilita a substituição temporária da localidade em um único segmento (ou seja, sem atrapalhar o estado global de seu programa). Você poderia então manter a localidade C globalmente e usar tolower etc. para texto orientado a ASCII / máquina (como arquivos de configuração e tal) e somente uselocale para a localidade selecionada do usuário ao trabalhar com texto em linguagem natural da localidade.

Caso contrário (e talvez até mesmo se você precisa é mais avançado), eu acho que a melhor solução é jogar completamente fora funções como tolower e escrever suas próprias versões ASCII para texto de configuração e similares, e usar um poderoso Unicode - biblioteca informatizada para texto em linguagem natural.

Um problema persistente que ainda não abordei é o separador decimal em relação a funções como snprintf e strtod . Alterá-lo para , em vez de . em algumas localidades pode arruinar sua capacidade de analisar arquivos com a biblioteca C. Minha solução preferida é simplesmente nunca definir o LC_NUMERIC locale qualquer. (E sou um matemático, por isso acredito que os números devem ser universais, não sujeitos a convenções culturais.) Dependendo da sua inscrição, as únicas categorias de localidade realmente necessárias podem ser apenas LC_CTYPE , LC_COLLATE e LC_MESSAGES . Também são úteis muitas vezes LC_MONETARY e LC_TIME .

    
por R.. 28.02.2012 / 17:05
fonte
2

Você tem dois problemas diferentes para resolver sua pergunta: testar seu código e lidar com problemas com o código de outras pessoas.

Testando seu próprio código - Eu lidei com isso usando 2 ou 3 configurações de localidades baseadas em inglês em um ambiente de CI: en_GB (collation), en_ZW (quase tudo muda, mas você ainda pode ler os erros) e en_AU ( data, colação)

Se você quer ter certeza de que seu código funciona com nomes de arquivos multibyte, então você também precisa testar com ja_JP

Lidar com código de outras pessoas é, em muitos aspectos, o mais difícil e minha solução para isso é armazenar os valores de data (quase sempre é datas :) em seu valor bruto de data / hora e sempre como GMT. Então, quando você cruzar o limite do seu aplicativo, converterá para o formato apropriado.

PyTZ e PyICU são muito úteis fazendo o acima.

    
por bear 28.02.2012 / 17:10
fonte