170823-21

News:

Ouverture du forum Jeux1d100. Bienvenue !


Aides et Astuces pour les nuls en prog

Started by Tchey, 170702-10

previous topic - next topic
Go Down

Tchey

Internationalisation

Tchey

#1
170702-10 Last Edit: 170702-10 by Tchey
http://forum.canardpc.com/threads/102958-J-ai-un-nom-et-un-concept-Je-n-ai-aucune-affinit%C3%A9-avec-la-programmation?p=10573264&viewfull=1#post10573264

Salut Tchey :)

OK, je vais essayer de détailler tout en restant simple ;)
Comme c'est un peu long, je vais faire 2 MP.

Comme tout ton code est en anglais et qu'on imagine qu'il soit lisible/maintenable/améliorable par n'importe qui dans le monde, je vais plutôt partir du principe que ton code contient au départ
Code Select
text="It's a sentence" et que tu souhaites le traduire (ou le faire traduire) par "C'est une phrase" en français, "Es una frase" en espagnol, "Es ist eine Phrase" en allemand, etc...


Bon, le truc c'est déjà de commencer par utiliser une variable, de la même manière que tu as utilisé fenX et fenY. Mettons qu'on l'appelle strTextToDisplay par exemple.

Ton
Code Select
text="It's a sentence" va donc devenir: initialisation en haut de code par
Code Select
strTextToDisplay="It's a sentence"
puis utilisation dans Label par
Code Select
text=strTextToDisplay

Ca, j'imagine que tu maitrises déjà :p

Le truc maintenant c'est d'imaginer que ta phrase ne va plus être en dur dans l'initialisation, mais dans un "dictionnaire" de phrases. (je crois que c'est le terme utilisé en python ?)
Imaginons qu'en haut de mon fichier, je créé un dictionnaire qui s'appelle lang.

Je vais y mettre un couple dont la clé vaudra it_s_a_sentence et dont la valeur vaut "It's a sentence".
Je n'ai jamais codé en Python, mais je crois que ça donnerait un truc du genre :
lang={}
lang["it_s_a_sentence"]="It's a sentence"

L'initialisation de la variable strTextToDisplay va donc devenir
Code Select
strTextToDisplay=lang["it_s_a_sentence"]

On obtient donc comme code :
Code Select

lang={}
lang["it_s_a_sentence"]="It's a sentence"

[...]

strTextToDisplay=lang["it_s_a_sentence"]

[...]

Label(fenExplo, text=strTextToDisplay, fg="white",...



Tu comprends alors qu'on peut généraliser en mettant tous tes textes dans le dictionnaire, par exemple :
Code Select

lang["Left"]="Gauche"
lang["Right"]="Droite"
lang["Up"]="Haut"
lang["Down"]="Bas"
lang["Settings"]="Paramètres"

etc...


Maintenant, étape suivante : ne pas mettre le contenu du dictionnaire en dur dans le code, mais dans un fichier .ini à part (ou .xml ou ce que tu veux). Par exemple lang.fr-FR.ini.
Le mieux, c'est de stocker ce fichier lang.fr-FR.ini dans un sous-dossier dédié qu'on appelerait /languages par exemple.

Il y aurait donc dans ce fichier quelque chose du genre :
Code Select

# language file
# this is the french language

lang={}
lang["it_s_a_sentence"]="C'est une phrase"
lang["Left"]="Gauche"
lang["Right"]="Droite"
lang["Up"]="Haut"
lang["Down"]="Bas"
lang["Settings"]="Paramètres"


puis dans ton programme un truc du genre
Code Select

import languages/lang.fr-FR.ini

Là, je connais pas cette partie en python... il faut peut-être que ton fichier s'appelle en .py et que tu l'utilises via un objet, je te laisse voir...[/QUOTE]


On va un peu améliorer le fichier en le structurant, par exemple en créant de rubrique :
Code Select

# language file
# this is the french language

# initialisation
lang={}

# sentences used in the arena gameplay
lang["it_s_a_sentence"]="C'est une phrase"

# sentences used in the general menu
lang["Left"]="Gauche"
lang["Right"]="Droite"
lang["Up"]="Haut"
lang["Down"]="Bas"
lang["Settings"]="Paramètres"


Voilà pour l'essentiel :)

Maintenant, il ne te reste plus qu'à créer un fichier lang.us-GB.ini qui contient
rubrique :
Code Select

# language file
# this is the english language

# initialisation
lang={}

# sentences used in the arena gameplay
lang["it_s_a_sentence"]="It's a sentence"

# sentences used in the general menu
lang["Left"]="Left"
lang["Right"]="Right"
lang["Up"]="Up"
lang["Down"]="Down"
lang["Settings"]="Settings"


et un autre lang.es-ES.ini ainsi
Code Select

# language file
# this is the english language

# initialisation
lang={}

# sentences used in the arena gameplay
lang["it_s_a_sentence"]="Es una frase"

# sentences used in the general menu
lang["Left"]="Izquierda"
lang["Right"]="Derecha"
lang["Up"]="Altura"
lang["Down"]="Bajo"
lang["Settings"]="Ajustes"


et ainsi de suite avec les autres langues ;)

Bon, maintenant la dernière étape c'est de faire un joli menu qui permet à l'utilisateur de choisir sa langue.
Et là, une fois le choix fait, tu initialises une variable globale (ou alors tu la stockes dans un .ini) que tu appelles lang_file.
Imaginons que le joueur choisisses le francais, tu écris
Code Select

lang_file=fr-FR


s'il choisit l'anglais, tu mets
Code Select

lang_file=us-GB


etc...

Par ailleurs, tu te fais un petit lang.py dans lequel tu écris :
Code Select

lang_filename = "languages/lang." + lang_file + ".ini"

import lang_filename


et donc dans tes fichier .py, au lieu d'écrire import lang.fr-FR.ini comme j'avais écris plus haut, tu as juste à écrire
Code Select

import lang.py


C'est fini ! :)

Pour résumer:
- appel une fois du menu qui permet au joueur de choisir sa langue, lang_file est alors initialisé, par exemple à fr-FR
- dans tous les autres fichiers, import de lang.py qui va importer ici lang.fr-FR.ini
- ce fichier ini va créer le dictionnaire lang et toutes tes string seront initialisées :), tu pourras donc te servir de lang["it_s_a_sentence"] et ainsi cela s'affichera dans la langue choisie par l'utilisateur ;)


Quelques astuces :
- il faut que tu choisisses une langue par défaut, mettons l'anglais, car au premier lancement du jeu il faudra bien que tu affiches le menu général, puis le menu de choix de langue
- il te faut donc initialiser la variable lang_file à us-GB si elle n'est pas encore définie
- il te faut la sauvegarder pour éviter au joueur de choisir sa langue à chaque lancement du jeu
- cela implique tu as la charge (mais aussi la maitrise) du fichier lang.us-GB.ini
- j'imagine que tu vas aussi te charger du fichier lang.fr-FR.ini
- le réflexe simple à avoir désormais, c'est que dès que tu veux afficher un texte, alors tu crées une nouvelle entrée dans ton dictionnare stocké dans lang.us-GB.ini (et aussi lang.fr-FR.ini tant qu'on y est)
- si tu veux faire traduire ton fichier par quelqu'un, il suffit qu'il duplique le fichier lang.us-GB.ini en lang.<son_code_langue>.ini et traduise les valeurs à droite du = (en ne touchant surtout pas aux valeurs entre [] )
- il faut prend en compte que tes traducteurs feront peut-être des traductions partielles, ou - quand tu vas publier une nouvelle mise à jour - qu'il va y avoir une période pendant laquelle les nouvelles phrases que tu auras ajoutées dans us-GB et fr-FR en seront pas encore traduites dans toutes les autres langues (le temps que tes traducteurs traduisent ces nouvelles phrase). Ce qui veut dire que dans les autres fichiers lang, il va manquer des item. Par exemple si tu ajoutes lang["Morgue"], il sera manquant dans les langues non encore mises à jour. Il ne faut pas que ton jeu en devienne inintelligible. A défaut, il va donc te falloir afficher ces textes manquants dans la langue par défaut (anglais, us-GB). Une manière simple de gérer cela, c'est dans ton lang.py c'est d'écrire :
Code Select

lang_filename = "languages/lang." + lang_file + ".ini"

[b]import languages/lang.us-GB.ini[/b]
import lang_filename

Ainsi, tu commences par initialiser toutes tes phrases en anglais, puis tu écrases celles qui sont traduites par la langue du joueur. De cette façon tu auras toujours la totalité des phrases, même si ton traducteur n'a fait qu'une traduction partielle ;)
- l'intérêt de passer par une variable strTextToDisplay repose sur plusieurs avantages, notamment : le texte à afficher à ce moment précis ("C'est une phrase") peut parfois être contextuelle (parfois simplement un pluriel/singulier), donc le contenu de ta phrase, et donc la valeur à utiliser dans le dictionnaire, peut-être le résultat d'un calcul compliqué (de switch, de if then else, de ...). Il est donc plus simple d'initialiser une variable en dehors de ta fonction Label. Par ailleurs, ce calcul pouvant être complexe, prendre du temps et de la mémoire, mieux vaut le faire qu'une seule fois et en stocker le résultat. De plus, il est possible, si tes calculs sont inexacts, que refaire la même chose quelques secondes plus tard te donne un résultat différent, et donc une phrase différente (alors que c'est inattendu puisqu'un bug) et donc une incohérence affichée à l'écran. Donc en plus de gagner du temps et de la mémoire, tu fiabilises ton affichage en utilisant cette variable intermédiaire. Et tu gagnes aussi en lisibilité du code ;)

Bon, j'espère avoir réussi à rester simple tout en étant compréhensible :p

Si tu as la moindre question, n'hésite pas ;)

Tchey

Euh... en fait tu as raison, c'est simplement le import * qui n'est pas autorisé... mais en fait c'est pas grave, car ce qu'il faut importé, c'est simplement le dictionnaire lang, donc un from lang_FR import lang marche ;)

Je viens de tester avec ce lang.py:
Code Select

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import importlib

def trad_FR():
    lang_file = "FR"
    from lang_FR import lang
    print(lang["It_s_a_sentence"])

def trad_EN():
    lang_file = "EN"
    from lang_EN import lang
    print(lang["It_s_a_sentence"])

lang_file = "EN"
lang_filename = ("lang." + lang_file)

from lang_EN import *

print("INIT lang.py: "+lang["It_s_a_sentence"])


On voit que c'est OK dans la fenetre principale de python...

Reste à faire :
- utiliser from lang_<lang_file> à la place du nom de fichier en dur
- passer à la suite, maintenant qu'on sait que la langue française est bien chargée en mémoire (refresh du menu d'options ?)... mais ça, je ne sais pas faire :)

Go Up