Cela est resté finalement assez discret jusqu’ici, mais en y regardant de plus près, les programmes que nous avons réalisés sont en fait destinés à un environnement anglophone. En effet, prenez par exemple les entrées : si nous souhaitons fournir un nombre flottant à notre programme, nous devons utiliser le point comme séparateur entre la partie entière et décimale. Or, dans certains pays, on pourrait vouloir utiliser la virgule à la place. Cela nous paraît moins étrange étant donné que les constantes flottantes sont écrites de cette manière en C, mais il n’en va pas de même pour nos utilisateurs.
Ce qu’il faudrait finalement, c’est que nos programmes puissent s’adapter aux usages, coutumes et langues de notre utilisateur et c’est que nous allons voir (partiellement) dans ce chapitre.
Définitions
Avant toute chose, il nous est nécessaire de définir deux concepts afin de bien cerner de quoi nous allons parler.
L’internationalisation
L'internationalisation (parfois abrégée « i18n ») est un procédé par lequel un programme est rendu capable de s’adapter aux préférences linguistiques et régionales d’un utilisateur.
La localisation
La localisation (parfois abrégée « l10n ») est une opération par laquelle un programme internationalisé se voit fournir les informations nécessaires pour s’adapter aux préférences linguistiques et régionales d’un utilisateur.
La fonction setlocale
De manière générale, les programmes que nous avons conçus jusqu’ici étaient déjà partiellement internationalisés, car la bibliothèque standard du langage C l’est dans une certaine mesure. Toutefois, nous n’avons jamais recouru à un processus de localisation pour que ceux-ci s’adaptent à nos usages. Nous vous le donnons en mille : la localisation en C s’effectue à l’aide de… la fonction setlocale()
.
char *setlocale(int categorie, char *localisation);
Cette fonction attends deux arguments : une catégorie et la localisation qui doit être employée pour cette catégorie. Elle retourne la localisation demandée si elle a pu être appliquée, un pointeur nul sinon.
Les catégories
La bibliothèque standard du C divise la localisation en plusieurs catégories, plus précisément cinq :
- La catégorie
LC_COLLATE
qui modifie le comportement des fonctionsstrcoll()
etstrxfrm()
; - La catégorie
LC_CTYPE
qui adapte le comportement des fonctions de traduction entre chaîne de caractères et chaînes de caractères larges (nous y viendrons bientôt), ainsi que les fonctions de l’en-tête<ctype.h>
; - La catégorie
LC_MONETARY
qui influence le comportement de la fonctionlocaleconv()
; - La catégorie
LC_NUMERIC
qui altère le comportement des fonctions*printf()
et*scanf()
ainsi que des fonctions de conversions de chaînes de caractères en ce qui concerne les nombres flottants ; - La catégorie
LC_TIME
qui change le comportement de la fonctionstrftime()
.
Enfin, la catégorie LC_ALL
(qui n’en est pas vraiment une) représente toutes les catégories en même temps.
Nous ne nous attarderons que sur les catégories LC_NUMERIC
et LC_TIME
dans la suite de ce chapitre.
Les localisations
La bibliothèque standard prévoit deux localisations possibles :
- La localisation
"C"
qui correspond à celle par défaut. Celle-ci utilise les usages anglophones ; - La localisation
""
(une chaîne vide) qui correspond à celle utilisée par votre système.
Il est également possible de fournir un pointeur nul comme localisation, auquel cas la localisation actuelle est retournée.
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *s;
s = setlocale(LC_ALL, NULL);
puts(s);
if (setlocale(LC_ALL, "") == NULL)
{
perror("setlocale");
return EXIT_FAILURE;
}
s = setlocale(LC_ALL, NULL);
puts(s);
return 0;
}
C
fr_BE.UTF-8
Comme vous le voyez, la localisation de départ est bien C
.
La forme que prend la localisation dépend de votre système. Sous unixoïdes et dans notre exemple, elle prend la forme de la langue en minuscule (au format ISO 639) suivie d’un tiret bas et du pays en majuscule (au format ISO 3166–1) et, éventuellement, terminée par un point et par l’encodage utilisé.
La catégorie LC_NUMERIC
La catégorie LC_NUMERIC
permet de modifier le comportement des fonctions scanf()
et printf()
afin qu’elles adaptent leur gestion et leur affichage des nombres flottants.
La catégorie LC_NUMERIC
affecte également les fonctions atoi()
, atol()
, atoll()
, strtol()
, strtoll()
, strtoul()
, strtoull()
, strtoimax()
, strtoumax()
, atof()
, strtof()
, strtod()
et strtold()
qui forment une suite de fonctions dédiées à la conversion de chaînes de caractères vers des nombres. Toutefois, nous ne nous étendrons pas sur ces dernières.
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
double f;
if (setlocale(LC_NUMERIC, "") == NULL)
{
perror("setlocale");
return EXIT_FAILURE;
}
printf("Veuillez entrer un nombre flottant : ");
if (scanf("%lf", &f) != 1)
{
perror("scanf");
return EXIT_FAILURE;
}
printf("Vous avez entré : %f.\n", f);
return 0;
}
Veuillez entrer un nombre flottant : 45,5
Vous avez entré : 45,500000.
Veuillez entrer un nombre flottant : 45.5
Vous avez entré : 45,000000.
Comme vous le voyez, avec une locale francophone et après l’appel à setlocale()
, seule la virgule est considérée comme séparateur de la partie entière et de la partie décimale.
La catégorie LC_TIME
La catégorie LC_TIME
modifie le comportement de la fonction strftime()
.
size_t strftime(char *chaine, size_t taille, char *format, struct tm *date);
Cette fonction, déclarée dans l’en-tête <time.h>
, écrit dans la chaîne de caractères chaine
différents éléments décrivant la date date
en suivant la chaîne de format format
(à l’image de la fonction snprintf()
). S’il y a assez de place dans la chaîne chaine
pour écrire l’entièreté des données, la fonction retourne le nombre de caractères écrits, sinon elle retourne zéro.
tm
La date doit être sous la forme d’une structure tm
(déclarée dans l’en-tête <time.h>
), structure qui peut être obtenue via la fonction localtime()
.
struct tm *localtime(time_t *date);
Cette fonction attend simplement l’adresse d’un objet de type time_t
et retourne l’adresse d’une structure tm
.
La fonction strftime()
supporte un grand nombre d’indicateurs de conversion pour construire la chaîne de format. En voici une liste non exhaustive.
Indicateur de conversion | Signification |
---|---|
A | Nom du jour de la semaine |
B | Nom du mois de l’année |
d | Jour du mois |
Y | Année sur quatre chiffres |
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int
main(void)
{
char buf[255];
time_t t;
if (setlocale(LC_TIME, "") == NULL)
{
perror("setlocale");
return EXIT_FAILURE;
}
if (time(&t) == (time_t)-1)
{
perror("time");
return EXIT_FAILURE;
}
struct tm *tm = localtime(&t);
if (tm == NULL)
{
perror("localtime");
return EXIT_FAILURE;
}
if (!strftime(buf, sizeof buf, "%A %d %B %Y", tm))
{
perror("strftime");
return EXIT_FAILURE;
}
printf("%s\n", buf);
return 0;
}
Wednesday 07 November 2018
mercredi 07 novembre 2018
À nouveau, comme vous pouvez le voir, suivant la locale utilisée la chaîne produite n’est pas la même.
En résumé
- L’internationalisation permet de rendre un programme sensible aux préférences régionales d’un utilisateur ;
- La localisation permet à un programme d’appliquer les préférences régionales d’un utilisateur ;
- La fonction
setlocale()
permet de modifier la localisation de certaines fonctions de la bibliothèque standard ; - La localisation par défaut (notée
C
) correspond aux usages anglophones.