Ξεκίνησα το blog μου στο blogger τον Αύγουστο του 2009. Όταν ξεκίνησα αγνοούσα τη δυνατότητα του να έχω πολυγλωσσικές αναρτήσεις. Πίστευα πως όταν χρειαζόταν να κάνω μια ανάρτηση σε άλλη γλώσσα από τη μητρική μου, απλά θα την έκανα. Η έννοια του να έχω μια ανάρτηση σε δύο γλώσσες δεν ήταν κάτι που με απασχολούσε. Λάθος μου!
Όταν άρχισαν να διαβάζουν τις αναρτήσεις μου ακόμα και τα ανήψια μου, εκεί κατάλαβα πόσο σημαντικό είναι οι αναρτήσεις μου να είναι στα Ελληνικά. Ταυτόχρονα, οι αναρτήσεις θα έπρεπε να είναι και στα Αγγλικά (δυστυχώς δε γνωρίζω άλλη γλώσσα) διότι αφορούν τεχνολογικό περιεχόμενο. Συνεπώς, καλό είναι να μπορούν να το καταλάβουν και άλλοι αναγνώστες οι οποίοι ενδιαφέρονται για το αντικείμενο που περιγράφεται, εκτός Ελλάδας. Παράδειγμα υπήρξε ακόμα και στις λίστες του FreeBSD όπου έκανα αναφορά σε ένα how-to που έχω γράψει, το οποίο όμως είναι γραμμένο στα Ελληνικά. Ο ενδιαφερόμενος φυσικά και δυσκολεύτηκε να πετύχει αυτά που περιέγραφε το άρθρο γιατί ήταν χωμένος μέσα σε εντολές κονσόλας και σε... μεταφραστικό...
Η απόφαση του να προσπαθήσω να κάνω το blog μου δίγλωσσο δεν άργησε (αντίθετα με την υλοποίησή του...).
Τι θα δούμε σε αυτό το άρθρο
What's in this article
Σε αυτό το άρθρο θα παρουσιαστούν τα ακόλουθα κομμάτια:
- Πολυγλωσσική λειτουργία - βασικές ανάγκες
- Επιλογή Γλώσσας
- Εφαρμογή Προτύπου
- Δομικά Στοιχεία
- Προσθήκη κανόνων στο CSS
- Βασική Λειτουργία του Κώδικα JavaScript
- Ο Κώδικας Βήμα Βήμα
- Ορισμοί Γενικών Μεταβλητών
- Προσθήκη Εικονιδίων Σημαίων Επιλογής Γλώσσας στον Τίτλο
- Ανάγνωση Παραμέτρου από τη URL
- Διαχείριση Cookies
- Απόφαση Γλώσσας Αναγνώστη
- Εφαρμογή Γλώσσας Στις Αναρτήσεις
- Τελευταίες Πινελιές στον Κώδικα
- Το Συνολικό Πρόγραμμα της JavaScript
- Παράδειγμα Χρήσης
- Συμπεράσματα
Πολυγλωσσική λειτουργία - βασικές ανάγκες
Multilingual Function - Basic Functionality
Για να μπορέσει να γίνει σωστά η λειτουργία της πολυγλωσσικής μορφής ενός άρθρου θα πρέπει το σύστημα τα ακολουθεί κάποιους κανόνες:
- Όταν κάποιος επισκέπτεται τη σελίδα για πρώτη φορά, το σύστημα θα πρέπει να αποφασίζει σε ποια γλώσσα θα δείξει τα άρθρα.
- Θα πρέπει ο αναγνώστης να μπορεί να αλλάξει γλώσσα εύκολα.
- Θα πρέπει να μπορεί το σύστημα να καταλάβει σε ποιες γλώσσες είναι γραμμένο το άρθρο, ώστε να δίνονται οι αντίστοιχες επιλογές στον αναγνώστη.
- Όταν ο αναγνώστης κάνει μια επιλογή μιας γλώσσας, το σύστημα θα πρέπει να τη θυμάται.
- Όταν ο αναγνώστης επιστρέψει μια άλλη μέρα στο blog θα πρέπει η πρώτη επιλεγμένη γλώσσα να είναι αυτή που χρησιμοποιήθηκε τελευταία φορά.
- Το σύστημα να μπορεί να διαχειριστεί άρθρα τα οποία είναι γραμμένα μόνο σε μια γλώσσα.
- Θα πρέπει να υπάρχει link parameter που να υποχρεώνει την εμφάνιση ενός άρθρου/άρθρων σε συγκεκριμμένη γλώσσα.
Οι δύο βασικοί τρόποι για να συμβεί κάτι τέτοιο είναι:
- Συγγραφή ξεχωριστού άρθρου για κάθε γλώσσα και χρήση links που να οδηγούν από τη μια γλώσσα στην άλλη
- Χρήση JavaScript η οποία να εμφανίζει τα στοιχεία HTML της επιλεγμένης γλώσσας και να εξαφανίζει αυτά που ανήκουν στις άλλες.
Ο κάθε τρόπος έχει τα υπέρ και τα κατά του. Ο τρόπος που προτιμάει να χρησιμοποιήσει ο καθένας είναι καθαρά αντικειμενικός. Σε αυτό το blog χρησιμοποιείται ο δεύτερο· χρήση JavaScript.
Επιλογή Γλώσσας
Language Selection
Για να υλοποιηθεί η διαδικασία της πολυγλωσσικότητας πρώτα απ' όλα θα πρέπει να υπάρχει ο κατάλληλος τρόπος για την επιλογή μιας από τις διαθέσιμες γλώσσας από τον χρήστη. Η εμφάνιση μιας σημαίας για κάθε διαθέσιμη γλώσσα είναι κάτι βολικό για μια τέτοια λειτουργία. Το σημείο και ο τρόπος με τον οποίο θα εμφανίζεται η εν λόγω επιλογή είναι καθαρά θέμα του συγγραφέα του blog στο οποίο θα εφαρμοστεί η πολυγλωσσικότητα. Άλλη μια ιδέα για την επιλογή είναι η εμφάνιση μιας λίστας με τις διαθέσιμες γλώσσες μέσα από την οποία ο χρήστης θα επιλέγει αυτή που επιθυμεί.
Στο παρόν blog κρίθηκε κατάλληλο το να εμφανίζονται όλες οι διαθέσιμες επιλογές επάνω στον τίτλο του κάθε άρθρου, έτσι ώστε ο αναγνώστης να βλέπει αμέσως τις διαθέσιμες επιλογές. Κρίθηκε, επίσης, σκόπιμο η γλώσσα στην οποία εμφανίζεται το άρθρο να μην υπάρχει στις διαθέσιμες επιλογές (μιας και δεν υπάρχει νόημα στο να επιλέξει κανείς μια γλώσσα την οποία ήδη χρησιμοποιεί).
Και πως μπορεί να ελέγχεται ποια κομμάτια θα εμφανίζονται, ώστε κάθε φορά με την επιλογή μιας γλώσσας να εμφανίζονται μόνο τα επιθυμητά; Η λύση βρίσκεται στη δυνατότητα της HTML να μπορεί να περιέχει κρυφά και φανερά κομμάτια. Αν με κάποιο τρόπο σηματοδοτήσουμε ότι μια παράγραφος ανηκει στο Ελληνικό κείμενο και μια άλλη ανήκει σε κείμενο μιας άλλης γλώσσας, τότε σαρώνωντας τα δομικά στοιχεία της σελίδας θα μπορούν να αποκρύπτωνται τα στοιχεία που ανήκουν σε γλώσσα εκτός της επιλεγμένης και να εμφανίζονται μόνο αυτά που ανήκουν στην επιλεγμένη. Τα στοιχεία τα οποία δεν έχουν τέτοια σηματοδότηση θα εμφανίζονται πάντα. Ο τρόπος κατά τον οποίο γίνεται εύκολη αυτή η διεργασία της σηματοδότησης είναι, ποιος άλλος, η εφαρμογή μιας κλάσης με το όνομα της γλώσσας στην οποία ανήκει το δομικό στοιχείο. Έτσι, μια παράγραφος που ανήκει στην κλάση "el" ανήκει στο Ελληνικό κείμενο, ενώ μια άλλη που ανήκει στην κλάση "en" θα ανήκει στο Αγγλικό κείμενο.
Και πως γίνεται να προσθέσουμε τα δομικά στοιχεία και τον κώδικα που θα εκτελεί όλες τις λειτουργίες; Πρώτα θα πρέπει να δούμε τι εργαλεία υπάρχουν για εφαρμογή θέματος στη σελίδα του blog μας.
Εφαρμογή Προτύπου
Apply Template
Το blogger.com μας δίνει τη δυνατότητα εφαρμογής προτύπων στη σελίδα μας. Δε θα μπορούσε να είναι σελίδα κατασκευής blogs αν δεν υπήρχε αυτή η δυνατότητα. Φυσικά, κάθε πρότυπο έχει και τη δική του δομή. Σε γενικές γραμμές, ο τρόπος που περιγράφεται εδώ είναι ίδιος με αυτόν που μπορείτε να ακολουθήσετε και σε blog με το δικό σας πρότυπο. Λίγο ο κώδικας του προτύπου, λίγο ο firebug, μπορούμε να βρούμε τα δομικά στοιχεία και τον τρόπο με τον οποίο θα κάνουμε τη παρέμβασή μας.
Ξεκινάμε από την εφαρμογή του προτύπου που μας ενδιαφέρει. Κάνουμε login στο blog μας και εκεί έχουμε τη δυνατότητα να επιλέξουμε πρότυπο εμφάνισης.
Εδώ μπορούμε να κάνουμε επιλογή του προτύπου που μας ενδιαφέρει. Το βασικό, όμως, είναι πως έχουμε τη δυνατότητα να επέμβουμε στον κώδικά του με τη χρήση του πλήκτρου "Επεξεργασία HTML". Με τη χρήση αυτού του πλήκτρου εμφανίζεται μπροστά μας όλος ο κώδικας που φτιάχνει την εμφάνιση της σελίδας μας.
Δομικά Στοιχεία
Structural Components
Κοιτάζοντας λίγο τον κώδικα του προτύπου μας, μπορούμε να δούμε όλα τα gadgets της σελίδας μας. Εκεί, μπορούμε να δούμε ότι η λίστα με τις αναρτήσεις αποτελείται από:
- Στοιχείο HTML <div> που ανήκει στην κλάση blog-posts. Αυτό περιέχει όλες τις αναρτήσεις που εμφανίζονται στην ιστοσελίδα.
- Μέσα σε αυτό περιέχειται ένα <div> που ανήκει στην κλάση date-outer. Αυτό φιλοξενεί τις αναρτήσεις μιας ημέρας.
- Το τμήμα των αναρτήσεων μιας ημέρας αποτελείται από μια επικεφαλίδα (στη δικιά μας περίπτωση <h2> που ανήκει στην κλάση date-header) που δηλώνει την ημερομηνία που έγιναν οι ακόλουθες αναρτήσεις και ένα <div> που ανήκει στην κλάση date-posts. Εκεί μέσα είναι που θα φιλοξενηθούν οι αναρτήσεις της ίδιας ημέρας.
- Κάθε ανάρτηση είναι από μόνη της ένα <div> που ανήκει στην κλάση post-outer και περιέχει δύο <div> στοιχεία, ένα που περιέχει την ανάρτησή μας (ανήκει στην κλάση post) κι ένα που περιέχει τα σχόλια και τη φόρμα ανάρτησης σχολίων από τους αναγνώστες (ανήκει στην κλάση comments). Αυτό που μας ενδιαφέρει, φυσικα, είναι το πρώτο από τα δύο.
- Κάθε ανάρτησή μας αποτελείται από τέσσερα βασικά τμήματα. Το πρώτο είναι ο τίτλος, το δεύτερο είναι κάποιου είδους επικεφαλίδα (στη δικιά μας περίπτωση είναι πάντα κενό), το τρίτο είναι το κείμενο της ανάρτησης και το τελευταίο είναι το τέλος της ανάρτησης που περιέχει κοινά στοιχεία σε όλες τις αναρτήσεις, όπως ονομα του συγγραφέα, εικονίδια για διαμοιρασμό της ανάρτησης σε facebook, google+, κ.λ.π.
- Ο τίτλος της ανάρτησης είναι κάτι που μας ενδιαφέρει. Είναι ένα HTML στοιχείο τύπου <h3> που ανήκει στην κλάση post-title. Μας ενδιαφέρει γιατί εκεί θα ενσωματωθούν οι ενδείξεις για τις διαθέσιμες γλώσσες. Επίσης, από τον τίτλο θα μπορεί να καταλάβει ο κώδικας JavaScript και ποιες είναι αυτές οι διαθέσιμες γλώσσες στις οποίες έχει γραφτεί η ανάρτηση.
- Το επόμενο κομμάτι της ανάρτησης που μας ενδιαφέρει είναι το HTML στοιχείο <div> που περιέχει το κυρίως κείμενο. Αυτό μας ενδιαφέρει, γιατί εκεί είναι που θα γίνεται η παρέμβαση της JavaScript για να εμφανίσει μόνο τα στοιχεία που ανήκουν στην επιλεγμένη γλώσσα. Το εν λόγω <div> ανήκει στην κλάση post-body.
Προσθήκη Κανόνων στο CSS
Adding CSS Rules
Η πρώτη προσθήκη που έχουμε να κάνουμε στον κώδικα είναι να προσθέσουμε κάποιους κανόνες στο CSS κομμάτι που δηλώνεται μέσα στο πρότυπο που χρησιμοποιούμε για την εμφάνιση της ιστοσελίδας μας. Όταν πατήσουμε το πλήκτρο "Επεξεργασία HTML" που φαίνεται και στο προηγούμενο στιγμιότυπο, κάτω από την προεπισκόπιση της σελίδας μας, μεταφερόμαστε στον κειμενογράφο όπου μπορούμε να "πειράξουμε" τον κώδικα του προτύπου.
Εκεί μπορούμε να βρούμε το σημείο στο οποίο βρίσκονται οι κανόνες CSS που στέλνονται για τη μορφοποίηση της σελίδας. Μια μικρή παρέμβαση που κάνουμε είναι η ακόλουθη:
...Some template code... <b:skin> ...Some CSS code... /*Added for multilingual support*/ .flag { height:24px; width:24px; margin-top:-3px; background-size:24px; float:right; cursor:pointer; } .flgen { background-image:url(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhevngcbkeTVwuM79NIvECzw-c8ZDzPx1ueBR_uMxZT79MzzsyOCfd_XnzsChqU2F0sGclwpb5NMTite-y16niyB37Py5plX-SDq7hwsFOWEHkhvds6pdLgrzoIQVKSgtYfXluB47JVymTb/s320/United-Kingdom-flag-icon.png); } .flgel { background-image:url(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMMfgCwXuktRQ6cQlLeCD76uvA_2aHdNmdTrHW-HnsspX4fccXA03KUanP8eI72HyzWk8gMrKp_Y9UntV45F2GGTiQSkfYUSeqSd-MeW_WTjU0xGMQEmH3nt0bJpQ0tkhyw315gEBFbFyZ/s1600/Greece-Flag2.png); } en { display:none; } //End of multilingual support edditions ...Some more CSS code... </b:skin> ...Some more template code...
Εδώ χρειάζονται λίγες διευκρινήσεις σχετικά με το τμήμα του κώδικα που προσθέσαμε. Κάθε ένα σημαιάκι που θα εμφανίζεται για την επιλογή γλώσσας θα ανήκει στην κλάση flag η οποία ορίζει τα οπτικά χαρακτηριστικά, όπως το μέγεθος και το ότι θα εμφανίζεται στα δεξιά του τμήματος στο οποίο προστίθεται· κοινώς, στα δεξιά στον τίτλο του άρθρου. Για κάθε μια γλώσσα που χρησιμοποιούμε, δημιουργούμε από μια κλάση που έχει όνομα flg και το όνομα της γλώσσας. Για την Ελληνική γλώσσα, δηλαδή, η ονομασία της κλάσης είναι η flgel, ενώ για την Αγγλική (γενικά) θα είναι flgen. Αν υποστηρίζαμε και άλλη μια γλώσσα π.χ. την Ισπανική, τότε θα δημιουργούσαμε ακόμα μια κλάση με όνομα flges, μιας και το es είναι το χαρακτηριστικό της Iσπανικής γλώσσας. Κάθε μια από αυτές τις κλάσεις θα εφαρμόζεται στο αντίστοιχο ενδεικτικό σημαιάκι επιλογής γλώσσας, μαζί με την προηγούμενη κλάση που περιγράφηκε και ο μόνος κανόνας που περιλαμβάνεται είναι αυτός που θέτει ως υπόβαθρο την εικόνα της σημαίας που μας ενδιαφέρει να απεικονίζεται. Εδώ μπορείτε να αλλάξετε το URL της εικόνας που χρησιμοποιώ και να θέσετε το δικό σας. Τέλος, για κάθε άλλη γλώσσα, εκτός από αυτή που θέλουμε να είναι προεπιλεγμένη, δημιουργούμε μια κλάση με το όνομα της γλώσσας, όπου κάνουμε το συστατικό που ανήκει σε αυτή να μην εμφανίζεται στην οθόνη μας. Γι' αυτό το λόγο υπάρχει η κλάση en, μιας και η προεπιλεγμένη γλώσσα για το παρόν blog θεωρείται η Ελληνική· η Αγγλική αποκρύπτεται. Αν υποστηρίζαμε και την Ισπανική γλώσσα, μιας και δεν είναι η προεπιλεγμένη, θα έπρεπε να δημιουργήσουμε άλλη μια κλάση με το όνομα es που να περιέχει τον κανόνα απόκρυψης, δηλαδή το display:none.
Βασική Λειτουργία του Κώδικα JavaScript
Basic Functionality Of JavaScript Program
Ήρθε η ώρα να δούμε τι λειτουργίες και με ποια σειρά θα πρέπει να κάνει ο κώδικας της JavaScript. Εν συντομία έχουμε τα ακόλουθα βήματα:
- Ο κώδικας θα πρέπει να εκτελείται αμέσως μόλις φορτωθεί η σελίδα (HTML τμήμα· δε μας ενδιαφέρει να έχουν φορτωθεί και οι εικόνες, αλλά μόνο το DOM). Συνεπώς, ο κώδικας προστίθεται στο τέλος της σελίδας, πριν κλείσει το </body>.
- Το πρώτο πράγμα που πρέπει να γίνει στην εμφάνιση της σελίδας είναι η προσθήκη των διαθέσιμων γλωσσών στον τίτλο κάθε άρθρου. Για να μπορέσει να βρει ο κώδικας τις διαθέσιμες γλώσσες του ενός άρθρου, αρκεί να κοιτάξει τον τίτλο του και να δει σε ποιες γλώσσες είναι γραμμένος.
- Αν υπάρχει μόνο μια γλώσσα στον τίτλο του άρθρου, τότε ενεργοποιεί μόνο αυτή τη γλώσσα και στο κείμενό του. Χρήσιμο κυρίως για τα άρθρα που έχουν γραφτεί παλιότερα και γίνεται τώρα η μετάφρασή τους. Κατά τη διάρκεια της μετάφρασης, το μεταφρασμένο κείμενο δεν εμφανίζεται, αν δε προστεθεί και ο τίτλος στη δεύτερη γλώσσα.
- Αν δε βρεθεί καμιά γλώσσα στον τίτλο του άρθρου, τότε δε γίνεται καμιά επεξεργασία στο κείμενο.
- Θα πρέπει να μπορεί να διαβαστεί μια παράμετρος GET (δηλαδή από τη γραμμή διεύθυνσης) για την επιθυμητή γλώσσα. Με αυτό τον τρόπο, αν κάποιος θέλει να στείλει ένα link σε κάποιον άλλο γι διαμοιρασμό του άρθρου που διαβάζει, μπορεί να προσθέσει την εν λόγω παράμετρο έτσι ώστε ο αποδέκτης να ενεργοποιήσει τη προτοποθετημένη γλώσσα αυτόματα. Αυτό βοηθάει και στην προεπισκόπιση του άρθρου κατά τη διάρκεια της συγγραφής του. Με τη προσθήκη της παραμέτρου στη URL της προεπισκόπισης μπορούμε να δουμε την προεπισκόπιση του άρθρου σε μια άλλη γλώσσα.
- Για να μπορεί να θυμάται το σύστημα την επιλογή γλώσσας του αναγνώστη θα πρέπει να γίνει χρήση Cookies.
- Θα πρέπει να μπορεί να διαβαστεί η επιλογή γλώσσας που έχει γίνει από τον φυλλομετρητή του αναγνώστη.
- Αν από η γλώσσα που αποφασίστηκε να ακολουθηθεί δεν υπάρχει στο παρόν άρθρο τότε θα πρέπει να εμφανιστεί η προεπιλεγμένη. Το σύστημα θα πρέπει να λαμβάνει υπόψη του και την κοντινότερη γλώσσα επιλογής. Δηλαδή, αν η γλώσσα επιλογής είναι τα Αγγλικά Ηνωμένων Πολιτειών (με χαρακτηριστικό en_US), όταν αυτή δε βρεθεί, πρώτα θα πρέπει να ελέγχεται η ύπαρξη της κοντινότερης γλώσσας, δηλαδή η Αγγλική γενικότερα (με χαρακτηριστικό en).
- Από τις σημαίες επιλογής γλώσσας πρέπει να αποκρύπτεται η γλώσσα στην οποία εμφανίζεται το άρθρο.
- Όταν ο χρήστης επιλέγει κάποια σημαία για αλλαγή γλώσσας εμφάνισης ενός άρθρου, θα πρέπει να ενημερώνεται το Cookie, να αποκρύπτεται η σημαία επιλογής, να εμφανίζεται η σημαία της προηγούμενης επιλογής, ενώ από το κείμενο να αποκρύπτονται όλα τα στοιχεία το οποία ανήκουν μόνο σε άλλες γλώσσες από την επιλεγμένη.
Κάτι που θα πρέπει να προσεχθεί είναι η χρήση της παραμέτρου display στα στοιχεία της ιστοσελίδας. Για κανονική εμφάνιση δεν αρκεί να πάρει την τιμή block. Κάποια στοιχεία για να εμφανιστούν σωστά πρέπει να έχουν άλλη τιμή, όπως τα στοιχεία <span> και τα στοιχεία <li>
Ο Κώδικας Βήμα Βήμα
The Code Step By Step
Ας δούμε τον κώδικα βήμα προς βήμα.
Ορισμοί Γενικών Μεταβλητών
Global Variables
Ο κώδικας όπως προαναφέραμε προστίθεται ακριβώς πριν το κλείσιμο του tag </body>. Ας δούμε βήμα βήμα τον κώδικα. Ξεκινάμε απο τα "προκαταρκτικά"
...Previous Template Code... <script type='text/javascript'> //Script for making the blog multilingual. var PREFEREDLANGS = "el en"; var LANGCOOKIENAME = "echlang"; var EXPIREDAYS = 7; var TITLES = {}; TITLES["el"] = "Δείτε το άρθρο στα Ελληνικά"; TITLES["en"] = "View the article in English"; ...More code, will be presented later...
Πρώτα ορίζουμε μερικές μεταβλητές. Αυτές είναι που θα πειράξετε για να προσθέσετε γλώσσες και να παραμετροποιήσετε το πολυγλωσσικό σύστημα. Θα παρατηρήσατε, βέβαια, πως κάποιοι χαρακτήρες γράφονται με την HTML κωδικοποίηση, όπως π.χ. τα εισαγωγικά γράφονται με την έκφραση ". Αυτό συμβαίνει γιατί στην ουσία πειράζουμε ένα αρχείο xml και αυτό θα πρέπει να μπορεί να το χειριστεί χωρίς προβλήματα ο xml parser του blogger.com. Για τα εισαγωγικά δεν τίθεται θέμα, μιας και από μόνο του το σύστημα τα μετατρέπει. Το πρόβλημα βρίσκεται σε άλλους χαρακτήρες, όπως π.χ. το '<' και το '>'. Αν αυτούς τους χαρακτήρες τους γράψουμε κανονικά και όχι με τη μορφή HTML, δηλαδή < και > αντίστοιχα, τότε το σύστημα θα παραπονεθεί.
Ας επανέλθουμε στο τμήμα του κώδικα που δώθηκε και ας δούμε μια προς μια τις μεταβλητές που ορίστηκαν:
- PREFEREDLANGS: Λίστα από τις υποστηριζόμενες γλώσσες. Η πρώτη είναι η βασική. Οι γλώσσες διαχωρίζονται από κενό .
- LANGCOOKIENAME: Το όνομα του Cookie που θα δημιουργείται. Αυτό θα περιέχει και τη προτίμιση της γλώσσας του χρήστη .
- EXPIREDAYS: Ο χρόνος διάρκειας του Cookie που δημιουργείται. Όταν ο αναγνώστης επισκέπτεται και πάλι τη σελίδα, το Cookie θα ανανεώνεται για άλλο τόσο χρονικό διάστημα .
- TITLES: Πρόκειται για ένα map. Ο λόγος ύπαρξής του είναι για το μικρό tooltip που θα εμφανίζεται όταν ο αναγνώστης αφήσει για λίγη ώρα τον κέρσορα του ποντικιού στο σημαιάκι επιλογής της αντίστοιχης γλώσσας .
Προσθήκη Εικονιδίων Σημαίων Επιλογής Γλώσσας στον Τίτλο
Adding Small Selection Flags On Post Title
Ας δούμε το κομμάτι του κώδικα που προσθέτει τις σημαίες επιλογής γλώσσας:
...Previous JavaScript code... function setupFlags() { var availLangs = PREFEREDLANGS.split(" "); var headings = document.getElementsByClassName("post-title"); var usedLangs = new Array(); for(i=0; i<headings.length; i++) { var tempHead = headings[i]; usedLangs.length = 0; if(tempHead != undefined) { for(j=0; j<availLangs.length; j++) { var tempElems = tempHead.getElementsByClassName(availLangs[j]); if(tempElems.length>0) { usedLangs.push(availLangs[j]); } } if(usedLangs.length>0) { for(j=0; j<usedLangs.length; j++) { newDiv = document.createElement("div"); newDiv.className = "flag flg" + usedLangs[j]; newDiv.setAttribute("onclick", "applyLang('" +usedLangs[j]+ "')"); newDiv.title = TITLES[usedLangs[j]]; tempHead.appendChild(newDiv); } } } } } ...More JavaScript code...
Στη γραμμή 4 φτιάχνεται ένας πίνακας με τις υποστηριζόμενες γλώσσες. Στη γραμμή 5 διαβάζονται όλοι οι διαθέσιμοι τίτλοι αναρτήσεων που υπάρχουν στη σελίδα που εμφανίζεται. Μια σελίδα μπορεί να προβάλει περισσότερες από μία αναρτήσεις. Αρκεί να θυμηθούμε ότι κάθε τίτλος ανάρτησης ανήκει στην κλάση post-title. Το επόμενο βήμα είναι να βρούμε σε πόσες και ποιες γλώσσες είναι διαθέσιμη κάθε ανάρτηση. Αυτό κάνει το for loop. Για κάθε τίτλο που έχει βρεθεί, μηδενίζει αρχικά τον πίνακα των χρησιμοποιούμενων γλωσσών (usedLangs - γραμμή 9) και αν πραγματικά έχει βρεθεί κάποιος τίτλος ανάρτησης, τότε μέσα σε αυτόν ελέγχει ποιες από τις διαθέσιμες γλώσσες χρησιμοποιούνται (εσωτερικό for loop - γραμμές 11 έως 16). Οι γλώσσες που βρίσκονται προστίθενται στη μεταβλητή usedLangs.
Ας θυμηθούμε λίγο μια προΥπόθεση που έχουμε θέσει προτύτερα· αν κάποιο άρθρο δεν έχει καθόλου μετάφραση, τότε ο τίτλος δεν περιέχει καμιά κλάση γλώσσας ενώ αν ο τίτλος περιέχει μόνο μια γλώσσα, τότε βρισκόμαστε σε κατάσταση μεταγλώτισης η οποία δεν έχει τελειώσει κι έτσι ο κώδικας θα πρέπει να αποκρύπτει τα τμήματα των μη δηλωμένων γλωσσών. Η σημαία επιλογής της τρέχουσας γλώσσας πρέπει να μην εμφανίζεται. Για περισσότερες δηλωμένες γλώσσες στον τίτλο της ανάρτησης, δε νομίζω πως θα πρέπει να πούμε κάτι παραπάνω.
Αν λοιπόν βρέθηκαν δηλωμένες γλώσσες στον τίτλο, τότε θα πρέπει να δημιουργηθούν οι σημαίες επιλογής για κάθε μία. Αυτό κάνει και ο κώδικας των γραμμών 17 έως 25.
Ανάγνωση Παραμέτρου από τη URL
Read URL Parameters
Το τμήμα που θα δούμε ακολούθως είναι αυτό που διαβάζει τις παραμέτρους τύπου GET από το URL του φυλλομετρητή μας. Πρόκειται για μια υπορουτίνα που δέχεται σαν παράμετρο εισόδου τη παράμετρο που αναζητάμε. Αν Αυτή βρεθεί, τότε επιστρέφει την τιμή της. Αν δε βρεθεί επιστρέφεται η τιμή null:
...Previous JavaScript code... function getParam(p_name) { pArray = location.search.substring(1).split("&"); retVal = null; pLength = pArray.length; for(i=0; i < pLength; i++) { keys = pArray[i].split("="); if(decodeURIComponent(keys[0]) == p_name) { retVal = decodeURIComponent(keys[1]); break; } } return retVal } ...More JavaScript code...
Στη γραμμή 4 διαβάζεται το τμήμα της URL που περιέχει τις παραμέτρους. Ο πρώτος χαρακτήρας είναι ο "?" και γι' αυτό αποκόπτεται (substring(1)) ενώ το υπόλοιπο δημιουργεί ένα πίνακα που περιέχει τις παραμέτρους που δηλώνωνται. Η μια παράμετρος από την επόμενη χωρίζονται από τον χαρακτήρα "&". Αν βρεθούν παράμετροι, τότε εξετάζονται μια προς μία για να βρούμε αυτή που δηλώθηκε κατά την κλήση της υπορουτίνας. Προσέξτε ότι χρησιμοποιείται η decodeURIComponent για να αποκωδικοποιηθούν σωστά οι ειδικοί χαρακτήρες που μπορεί να περιέχονται στο URL. Αν η παράμετρος βρεθεί τότε σταματάει το ψάξιμο και επιστρέφεται η τιμή της, ενώ αν δε βρεθεί επιστρέφεται η προτοποθετημένη τιμή null.
Θα μπορούσε κάποιος να παρατηρήσει πως η συγκεκριμμένη ρουτίνα δεν ξέρει να ασχοληθεί με παραμέτρους που μπορούν να πάρουν πολλές τιμές ταυτόχρονα (όπως επιλογές από checkboxes με το ίδιο όνομα). Αυτό δεν είναι κάτι που μας ενδιαφέρει γιατί η μόνη παράμετρος που διαχειριζόμαστε είναι η lang. Θα ήταν, λοιπόν, άσκοπο να προσθέσουμε κάτι παραπάνω σε αυτή τη ρουτίνα για κάτι που δε χρειαζόμαστε.
Διαχείριση Cookies
Cookies Manipulation
Ο κώδικας πρέπει να θυμάται την επιλογή της γλώσσας του αναγνώστη. Είναι αρκετά άβολο, κάθε φορά που ένας αναγνώστης επιλέγει να δει μια καινούργια ανάρτηση να πρέπει να ξαναεπιλέξει και τη γλώσσα που τον ενδιαφέρει να διαβάζει το άρθρο. Για να μπορεί να θυμάται το σύστημα την επιλογή της γλώσσας για τον κάθε ένα αναγνώστη ξεχωριστά, ο μόνος τρόπος είναι η χρήση ενός Cookie. Ας δούμε τις ρουτίνες που τα διαχειρίζονται.
...Previous JavaScript code... function setCookie(c_name, c_inval, exdays) { if (exdays) { var exdate = new Date(); exdate.setTime(exdate.getTime()+(exdays*24*60*60*1000)); var expires = "; expires=" + exdate.toGMTString(); } else { var expires = ""; } var c_value = escape(c_inval); document.cookie = c_name + "=" + c_value + expires + "; path=/"; } function getCookie(c_name) { var nameEQ = c_name + "="; var ca = document.cookie.split(";"); var caLength = ca.length; for(var i=0; i < caLength; i++) { var c = ca[i]; while (c.charAt(0)==" ") c = c.substring(1,c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); } return null; } function updCookie(c_name, c_newval) { var c_val = c_newval || getCookie(c_name); if (c_val) { setCookie(c_name, c_val, EXPIREDAYS) } } ...More JavaScript code...
Σε αυτό το τμήμα του κώδικα βλέπουμε τρεις υπορουτίνες. Η πρώτη (setCookie) δημιουργεί ένα Cookie με όνομα που δηλώνεται στην παράμετρο c_name, η τιμή του καθορίζεται από τη παράμετρο c_inval ενώ ο χρόνος εγκυρότητάς του δηλώνεται από τη παράμετρο exdays.
Η δεύτερη υπορουτίνα διαβάζει το Cookie με όνομα που δηλώνεται στη παράμετρο εισόδου c_name κι επιστρέφει την τιμή του. Αν δε το βρει επιστρέφει null.
Η τρίτη κι τελευταία υπορουτίνα χρησιμοποιεί τη setCookie για να κάνει τη δουλειά της. Αν υπάρχει το Cookie που δηλώνεται στην παράμετρο c_name τότε το ενημερώνει με μια πιθανά καινούργια τιμή, αν αυτή έχει δηλωθεί στη παράμετρο c_newval και μια ημερομηνία που ορίζεται από τις αρχικές μεταβλητές που δηλώσαμε στην αρχή, την EXPIREDAYS.
Απόφαση Γλώσσας Αναγνώστη
Readers Language Decision
Ήρθε η ώρα να αποφασίσουμε τελικά σε ποια από τις διαθέσιμες γλώσσες θα εμφανίσουμε το άρθρο. Η απόφαση πρέπει να γίνει με βάση τα εξής κριτήρια:
- Αν υπάρχει παράμετρος με όνομα lang στη URL του φυλλομετρητή, τότε η απόφαση ορίζεται από αυτή την τιμή .
- Αν δεν υπάρχει η παράμετρος τότε εξετάζεται το ενδεχόμενο να έχει ξαναεπισκευτεί τη σελίδα ο αναγνώστης, δηλαδή το να υπάρχει αποθηκευμένο Cookie με το όνομα που δηλώνει η αρχική μεταβλητή LANGCOOKIENAME. Αν υπάρχει τότε η γλώσσα επιλέγεται από αυτό .
- Αν ο αναγνώστης επισκέπτεται για πρώτη φορά τη σελίδα μας, ή έχει καιρό να την επισκευτεί έτσι ώστε να έχει λήξει η προθεσμία του Cookie, τότε η απόφαση θα παρθεί από τις ρυθμίσεις του φυλλομετρητή .
- Τέλος, αν όλες οι προηγούμενες προσπάθειες αποτύχουν, ορίζεται ως γλώσσα η πρώτη από τη λίστα που ορίζει η αρχική μεταβλητή PREFEREDLANGS .
Όλα τα παραπάνω φαίνονται στο ακόλουθο κομμάτι κώδικα:
...Previous JavaScript code... function getLang() { var langParam = getParam("lang"); var availLangs = PREFEREDLANGS.split(" "); var browserLang = langParam || getCookie(LANGCOOKIENAME) || window.navigator.userLanguage || window.navigator.language || availLangs[0]; var langCnt = availLangs.length; retVal = 0; for(i=0; i < langCnt; i++) { if(browserLang == availLangs[i]) { retVal = i; break; } else if(browserLang.substring(0, browserLang.indexOf("_")) == availLangs[i]) { retVal = i; break; } } return availLangs[retVal]; } ...More JavaScript code...
Στη γραμμή 6, εξετάζονται μια προς μια οι παράμετροι, με τη σειρά που εξηγήσαμε. Όποια βρεθεί πρώτη είναι και αυτή που θα δώσει την τιμή της στη μεταβλητή browserLang. Για να μπορέσουμε, όμως, να εξασφαλίσουμε ότι η γλώσσα που θα επιστραφεί είναι μια από τις αποδεκτές που ορίζονται στην αρχή του όλου κώδικα, με τη μεταβλητή PREFEREDLANGS, θα πρέπει να γίνει μια αντιπαράθεση με μια προς μια τις διαθέσιμες γλώσσες. Αυτό κάνει και το for loop στις γραμμές 9 έως 17. Μια μικρή λεπτομέρεια είναι πως η γλώσσα μπορεί να αποτελείται από το γενικό κομμάτι της (π.χ. "en" για την Αγγλική) αλλά μπορεί να περιέχει και το χαρακτηριστικό της περιοχής (όπως π.χ. "en_US" για την Αγγλική γλώσσα των Ηνωμένων Πολιτειών). Αυτό ο κώδικας το λαμβάνει υπόψη του.
In line 6, the parameters are checked ony by one in the described order. The first found one sets the value of browserLang. To be able to secure that the returned language value to be used is one of the available ones, set by PREFEREDLANGS global variable, we should compare their values. This is done by the for loop in lines 9 to 17. One small detail is that a language literal characteristic may contain only the general part of the language (ie. "en" for English) or may include the country literal (as in "en_US" for United States English). The code takes it into account, also.
Εφαρμογή Γλώσσας Στις Αναρτήσεις
Apply Language Selection On Posts
Γνωρίζωντας, πλέον, τη γλώσσα στην οποία θα πρέπει να εμφανιστεί το άρθρο, το μόνο που μένει είναι να εφαρμόσουμε αυτή την επιλογή. Η εφαρμογή γίνεται από την ίδια ρουτίνα που χρησιμοποιείται και από τις σημαίες επιλογής γλώσσας που εμφανίσαμε στον τίτλο της ανάρτησης. Αν γυρίσουμε, για μια στιγμή μόνο, πίσω στο κομμάτι του κώδικα που πρόσθεσε τα ενδεικτικά σημαιάκια στον τίτλο. Βλέπουμε στη γραμμή 21 εκείνου του κώδικα να ορίζεται το event onclick να καλεί μια υπορουτίνα με όνομα applyLang και παράμετρο τη γλώσσα που αντιπροσωπεύει το αντίστοιχο ενδεικτικό σημαιάκι. Ας δούμε τον κώδικα της υπορουτίνας:
...Previous JavaScript code... function applyLang(inLang) { var posts = document.getElementsByClassName("post"); setCookie(LANGCOOKIENAME, inLang, EXPIREDAYS); if(posts[0] == undefined) return; for(k=0; k<posts.length; k++) { var flags = posts[k].getElementsByClassName("flag"); var langExist = (posts[k].getElementsByClassName("flag flg" + inLang) != undefined); var flagsCnt = flags.length; if(flagsCnt==0) continue; var tempLang = inLang; if((flagsCnt==1) || !langExist) { tempLang = flags[0].className.indexOf("flg"); tempLang = flags[0].className.substring(tempLang+3); } for(i=0; i<flagsCnt; i++){ curI = flags[i].className.indexOf("flg"+tempLang); if(curI >= 0) { flags[i].style.display = "none"; } else { flags[i].style.display = "inline"; } } var availLangs = PREFEREDLANGS.split(" "); for(i=0; i<availLangs.length; i++){ var currLang = availLangs[i]; if(currLang == tempLang) continue; var divs = document.getElementsByClassName(currLang); var divsCnt = divs.length; for(j=0; j<divsCnt; j++) { divs[j].style.display = "none"; } } var divs = document.getElementsByClassName(tempLang); var divsCnt = divs.length; for(j=0; j<divsCnt; j++) { elemType = divs[j].tagName.toLowerCase(); divDisplay = "block"; switch(elemType) { case "a": case "span": divDisplay = "inline"; break; case "li": divDisplay = "list-item"; break; } divs[j].style.display = divDisplay; } } } ...More JavaScript code...
Πιθανόν κάποιος να αναρωτηθεί για τον τρόπο με τον οποίο είναι γραμμένη αυτή η υπορουτίνα. Ας δούμε λίγο τι κάνει.
Αρχικά ανανεώνει το Cookie για τη γλώσσα που πρόκειται να παρουσιαστεί και φυσικά το χρόνο λήξης της ισχύος του (γραμμή 5). Στη συνέχεια αν δεν υπάρχει κάποια διαθέσιμη ανάρτηση, τότε δεν υπάρχει κάτι να κάνει, οπότε και τερματίζεται (γραμμές 6 και 7).
Για κάθε ανάρτηση που βρίσκει αναγνωρίζει ποιες είναι οι διαθέσιμες γλώσσες και αν η ανάρτηση περιέχεται στη γλώσσα που επιλέχθηκε. Αν δε βρεθεί κάποια γλώσσα για την ανάρτηση την οποία ελέγχει τότε προχωράει στην επόμενη (γραμμή 12).
Το τμήμα που αποτελείται από τις γραμμές 13 έως 17, αποφασίζει ποια γλώσσα από τις διαθέσιμες του άρθρου είναι αυτή στην οποία θα εμφανιστεί. Ο λόγος που γίνεται αυτό, είναι γιατί ένα άρθρο μπορεί να είναι ολοκληρωμένο μόνο σε μια γλώσσα, η οποία να είναι διαφορετική από την επιλεγμένη, οπότε και θα εμφανιστεί στη γλώσσα στην οποία είναι γραμμένο, ή να μην έχει γραφτεί καθόλου στην επιλεγμένη γλώσσα, συνεπώς εμφανίζεται στην προεπιλεγμένη. Μην ξεχνάμε πως ο λόγος να έχει δηλωθεί μόνο μια γλώσσα στον τίτλο ενός άρθρου, είναι κατά τη διάρκεια της μεταγλώτισής του ενώ αυτό έχει αναρτηθεί, έτσι ώστε να αποκρύπτεται η ημιτελής μετάφραση.
Από τη γραμμή 18 έως την 25 ενημερώνεται η εμφάνιση των σημαιών επιλογής γλώσσας. Εμφανίζονται, δηλαδή, οι σημαίες των γλωσσών που δεν είναι επιλεγμένες και αποκρύπτεται αυτή στην οποία εμφανίζεται η παρούσα ανάρτηση.
Τα επόμενο βήμα είναι να εμφανιστούν τα HTML στοιχεία που ανήκουν στη γλώσσα που έχει αποφασιστεί να προβληθεί η ανάρτηση. Αυτό γίνεται σε δύο κομμάτια. Το πρώτο αποτελείται από τις γραμμές 27 έως 36, το οποίο αποκρύπτει όλες τις παραγράφους που έχουν επισήμανση γλώσσας. Το δεύτερο κομμάτι αποτελείται από τις γραμμές 37 έως και 52. Αυτό εμφανίζει τα στοιχεία τα οποία ανήκουν στη γλώσσα προβολής του άρθρου. Εδώ δίνεται και η δυνατότητα να μπορέσουν τα διαφορετικά στοιχεία να πάρουν διαφορετική τιμή στη παράμετρο display.
Ο λόγος για τον οποίο η εμφάνιση γίνεται με διπλό πέρασμα των στοιχείων της ανάρτησης είναι γιατί ένα στοιχείο μπορεί να ανήκει σε δύο γλώσσες. Παραδείγματος χάρην, αν το άρθρο έχει γραφτεί σε Ελληνικά, Αγγλικά και Κινέζικα, τότε ένα στοιχείο που εμφανίζεται και στα Ελληνικά, αλλά και στα Αγγλικά θα πρέπει να ανήκει και στις δύο κλάσεις γλώσσας (class="el en"). Αν δεν περνούσαμε την εμφάνιση σε δύο βήματα, τότε η λειτουργία της εμφάνισης δε θα γινόταν σωστά· ναι μεν στην επιλογή της εμφάνισης του άρθρου σε Κινέζικα δε θα εμφανιζόταν το εν λόγω στοιχείο, αλλά αναλόγως με τη θέση της γλώσσας των Ελληνικών και των Αγγλικών στη λίστα των διαθέσιμων γλωσσών δε θα είχαμε εμφάνιση και στις δύο γλώσσες...
Τελευταίες Πινελιές στον Κώδικα
Some Code's Finishing Touches
Τι δεν έχουμε δει ακόμα; Το κομμάτι του κώδικα που ξεκινάει την αυτόματη εκτέλεσή του. Μιας και δεν έχουμε τον πλήρη έλεγχο όλου του κώδικα που τρέχει στη σελίδα, παρά μόνο στο δικό μας κομμάτι, δε μπορούμε να χρησιμοποιήσουμε την onload. Μπορεί ήδη να τη χρησιμοποιεί κάποιο άλλο κομμάτι κώδικα από όλα αυτά που φορτώνονται για την επιβολή των στατιστικών κ.λ.π. που μας παρέχει το blogger.com. Κατα συνέπεια, ο μόνος διαθέσιμος τρόπος είναι οι αυτόματα εκτελέσιμες υπορουτίνες της JavaScript:
...Previous JavaScript code... (function(){ setupFlags(); setupLang(); })(); function setupLang() { currLang = getLang(); applyLang(currLang); } </script> </body> </html>
Οι γραμμές 8 έως 11 δεν κάνουν τίποτα άλλο από το να διαβάσουν τη γλώσσα που θα πρέπει να χρησιμοποιηθεί, την πρώτη φορά που φορτώνεται η σελίδα, ενώ οι γραμμές 3 έως και 6 είναι αυτές που εκτελούνται αυτόματα με το που φορτώνεται η σελίδα μας. Αυτές είναι που ξεκινάνε την εμφάνιση των σημαιών επιλογής γλώσσας κι εμφανίζουν τα άρθρα που υπάρχουν στη σελίδα στη γλώσσα που είναι πιο κοντά στον χρήστη, όπως περιγράφτηκε στην παράγραφο "Απόφαση Γλώσσας Αναγνώστη". Σε αυτό το σημείο ολοκληρώνεται και ο κώδικας που περιέχεται σε αυτό εδώ το blog για την πολυγλωσσική εμφάνιση των αναρτήσεών του.
Το Συνολικό Πρόγραμμα της JavaScript
The Whole JavaScript Program
Μιας και ο κώδικας περιγράφτηκε σε τμήματα, για να είναι πιο εύκολο για τον αναγνώστη να μπορέσει να τον αντιγράψει και να τον χρησιμοποιήσει/παραλλάξει σύμφωνα με τις ανάγκες του, ο κώδικας παρατίθεται ολόκληρος σε αυτό το σημείο. Μπορείτε να τον χρησιμοποιήσετε ελεύθερα.
<script type='text/javascript'> //Script for making the blog multilingual. //Written by Elias Chrysocheris /*THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ var PREFEREDLANGS = "el en"; var LANGCOOKIENAME = "echlang"; var EXPIREDAYS = 7; var TITLES = {}; TITLES["el"] = "Δείτε το άρθρο στα Ελληνικά"; TITLES["en"] = "View the article in English"; (function(){ setupFlags(); setupLang(); })(); function setCookie(c_name, c_inval, exdays) { if (exdays) { var exdate = new Date(); exdate.setTime(exdate.getTime()+(exdays*24*60*60*1000)); var expires = "; expires=" + exdate.toGMTString(); } else { var expires = ""; } var c_value = escape(c_inval); document.cookie = c_name + "=" + c_value + expires + "; path=/"; } function getCookie(c_name) { var nameEQ = c_name + "="; var ca = document.cookie.split(";"); var caLength = ca.length; for(var i=0; i < caLength; i++) { var c = ca[i]; while (c.charAt(0)==" ") c = c.substring(1,c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); } return null; } function updCookie(c_name, c_newval) { var c_val = c_newval || getCookie(c_name); if (c_val) { setCookie(c_name, c_val, EXPIREDAYS) } } function getParam(p_name) { pArray = location.search.substring(1).split("&"); retVal = null; pLength = pArray.length; for(i=0; i < pLength; i++) { keys = pArray[i].split("="); if(decodeURIComponent(keys[0]) == p_name) { retVal = decodeURIComponent(keys[1]); break; } } return retVal } function getLang() { var langParam = getParam("lang"); var availLangs = PREFEREDLANGS.split(" "); var browserLang = langParam || getCookie(LANGCOOKIENAME) || window.navigator.userLanguage || window.navigator.language || availLangs[0]; var langCnt = availLangs.length; retVal = 0; for(i=0; i < langCnt; i++) { if(browserLang == availLangs[i]) { retVal = i; break; } else if(browserLang.substring(0, browserLang.indexOf("_")) == availLangs[i]) { retVal = i; break; } } return availLangs[retVal]; } function setupLang() { currLang = getLang(); applyLang(currLang); } function applyLang(inLang) { var posts = document.getElementsByClassName("post"); setCookie(LANGCOOKIENAME, inLang, EXPIREDAYS); if(posts[0] == undefined) return; for(k=0; k<posts.length; k++) { var flags = posts[k].getElementsByClassName("flag"); var langExist = (posts[k].getElementsByClassName("flag flg" + inLang) != undefined); var flagsCnt = flags.length; if(flagsCnt==0) continue; var tempLang = inLang; if((flagsCnt==1) || !langExist) { tempLang = flags[0].className.indexOf("flg"); tempLang = flags[0].className.substring(tempLang+3); } for(i=0; i<flagsCnt; i++){ curI = flags[i].className.indexOf("flg"+tempLang); if(curI >= 0) { flags[i].style.display = "none"; } else { flags[i].style.display = "inline"; } } var availLangs = PREFEREDLANGS.split(" "); for(i=0; i<availLangs.length; i++){ var currLang = availLangs[i]; if(currLang == tempLang) continue; var divs = document.getElementsByClassName(currLang); var divsCnt = divs.length; for(j=0; j<divsCnt; j++) { divs[j].style.display = "none"; } } var divs = document.getElementsByClassName(tempLang); var divsCnt = divs.length; for(j=0; j<divsCnt; j++) { elemType = divs[j].tagName.toLowerCase(); divDisplay = "block"; switch(elemType) { case "a": case "span": divDisplay = "inline"; break; case "li": divDisplay = "list-item"; break; } divs[j].style.display = divDisplay; } } } function setupFlags() { var availLangs = PREFEREDLANGS.split(" "); var headings = document.getElementsByClassName("post-title"); var usedLangs = new Array(); for(i=0; i<headings.length; i++) { var tempHead = headings[i]; usedLangs.length = 0; if(tempHead != undefined) { for(j=0; j<availLangs.length; j++) { var tempElems = tempHead.getElementsByClassName(availLangs[j]); if(tempElems.length>0) { usedLangs.push(availLangs[j]); } } if(usedLangs.length>0) { for(j=0; j<usedLangs.length; j++) { newDiv = document.createElement("div"); newDiv.className = "flag flg" + usedLangs[j]; newDiv.setAttribute("onclick", "applyLang('" +usedLangs[j]+ "')"); newDiv.title = TITLES[usedLangs[j]]; tempHead.appendChild(newDiv); } } } } } </script> </body> </html>
Απλά θυμηθείτε πως υπάρχει και το τμήμα του CSS καθώς επίσης θα πρέπει να παραλλάξετε τις global μεταβλητές σύμφωνα με τις δικές σας ανάγκες.
Παράδειγμα Χρήσης
An Example Of Usage
Για να δούμε πώς μπορούμε να φτιάξουμε ένα πολυγλωσσικό κείμενο. Μιας και στο παρόν blog χρησιμοποιούμε Ελληνική και Αγγλική γλώσσα, το παράδειγμα που θα δοθεί είναι γι' αυτές. Ας δούμε ένα κομμάτι κειμένου που αναρτούμε σε ένα άρθρο μας. Να σημειωθεί ότι το κέιμενο είναι γραμμένο σε καθαρή HTML:
<p class="el">Αυτό είναι το κείμενο της παραγράφου στα Ελληνικά. Εφόσον η κλάση που δηλώνεται στο tag της παραγράφου είναι <tt>el</tt>, η παράγραφος αυτή θα εμφανίζεται όταν βλέπετε το Ελληνικό κείμενο!</p> <p class="en">This is the English text of the paragraph. Since the <p> tag belongs to <tt>en</tt> class, this paragraph will be visible only when the English text is displayed!</p>
Το αποτέλεσμα είναι η ακόλουθη παράγραφος στο γκρι πλαίσιο. Η ενδεικτική σημαία δεν προστίθεται με αυτό τον HTML κώδικα, αλλά την έχουμε προσθέσει εμείς για την ευκολία της παρατήρησης του αναγνώστη. Δοκιμάστε να επιλέξετε άλλη γλώσσα από τον τίτλο του κειμένου (ή από τη σημαία στα δεξιά) και παρατηρείστε τι εμφανίζεται σε αυτή την παράγραφο:
Αυτό είναι το κείμενο της παραγράφου στα Ελληνικά. Εφόσον η κλάση που δηλώνεται στο tag της παραγράφου είναι el, η παράγραφος αυτή θα εμφανίζεται όταν βλέπετε το Ελληνικό κείμενο! |
|
Κάτι ακόμα που θα πρέπει να αναφερθεί, είναι πως κατά τη διάρκεια της προεπισκόπισης ενός άρθρου που ακόμα συντάσεται, χωρίς να έχει αναρτηθεί, επειδή το blogger κόβει κάποιες από τις λειτουργίες, ένας απλός τρόπος για να γίνει προεπισκόπιση σε άλλη γλώσσα, είναι η χρήση της παραμέτρου lang στο URL του παραθύρου της προεπισκόπισης. Δηλαδή, όταν πατήσουμε το πλήκτρο προεπισκόπιση κατά τη διάρκεια της συγγραφής ενός άρθρου, ανοίγει μια καινούργια καρτέλα (ή καινούργιο παράθυρο, ανάλογα με τις ρυθμίσεις του φυλλομετρητή) και μας δειχνει πως θα φαίνεται το άρθρο όταν αναρτηθεί. Αν στο URL προσθέσουμε το "&lang=en", τότε υποχρεώνουμε το σύστημα να μας εμφανίσει το άρθρο στην Αγγλική γλώσσα.
Συμπεράσματα
Conclusions
Το να μπορεί κάποιος να διαβάσει ένα κείμενο που τον ενδιαφέρει στη μητρική του γλώσσα, είναι κάτι πολύ σημαντικό. Σκεφτείτε πόσες φορές έχετε βρει ένα κείμενο σε μια γλώσσα που δεν καταλαβαίνετε· είτε δεν το προσπαθήσατε καθόλου, είτε χωθήκατε μέσα σε ένα μεταφραστικό και... ότι βγάλατε βγάλατε. Μην ξεχνάμε ότι παντού γίνονται προσπάθειες μετάφρασης. Από κλειστά λογισμικά μέχρι ανοικτά, ιστοσελίδες και ό,τι μπορεί να περιέχει κείμενο, κρύβουν μια ομάδα, μεγάλη ή μικρή που δουλειά της είναι να μεταφράζει τα κείμενα σε διάφορες γλώσσες. Όσοι ασχολείστε με το ανοικτό λογισμικό πιστεύω πως θα ασχοληθήκατε, ή έστω θα διαπιστώσατε τη μεγάλη προσπάθεια που γίνεται για τη μετάφραση των προγραμμάτων, τόσο του γραφικού περιβάλλοντός τους όσο και του κειμένου βοήθειας.
Το blogger.com δυστυχώς δε μας δίνει τη δυνατότητα να έχουμε μεταφράσεις του κειμένου μιας ανάρτησής μας. Αυτό το εμπόδιο, με λίγη προσπάθεια, το προσπερνάμε και έχουμε μεταφρασμένες αναρτήσεις. Με αυτό τον τρόπο η απήχηση του blog μας αυξάνει.
Μια μικρή ματιά σε ιστότοπους, όπως αυτό της Transifex, νομίζω πως μπορεί να σας πείσει για την αναγκαιότητα της μετάφρασης.