Skip to content

Tutorial 5 Localization el

James Morris edited this page Jul 29, 2026 · 1 revision

Μάθημα 5 · Τοπικοποίηση (i18n)

Στόχος: κατανόησε πώς το LockedIn CLI μιλάει 33 γλώσσες — και εξασκήσου στο να καθοδηγείς έναν πράκτορα να προσθέσει άλλη μία. Η τοπικοποίηση είναι μια φανταστική εργασία για πράκτορα: είναι αρκετά μηχανική για να ανατεθεί, αλλά έχει πραγματικούς περιορισμούς (μια πύλη ελέγχου, κανόνες διάταξης, γραμματικό έλεγχο) που σε διδάσκουν να ελέγχεις.

← Προηγούμενο: Μάθημα 4 Prompting και έλεγχος · Πίσω στην Αρχική


Τι σημαίνει «τοπικοποιημένο» εδώ

Τρέξε το CLI στα Ισπανικά, Χίντι, Ιαπωνικά, Απλοποιημένα Κινέζικα, ή σε οποιαδήποτε γλώσσα διατίθεται και όλα αλλάζουν — η εναρκτήρια οθόνη, ο πίνακας βοήθειας, η έξοδος κάθε εντολής, η συνεδρία συνομιλίας, ακόμα και τα νομικά ψιλά γράμματα. Όχι μόνο τα αστεία: όλη η ορατή επιφάνεια.

lockedin --lang el post
LOCKEDIN_LANG=hi lockedin
lockedin --lang zh aura

Η γλώσσα αυτοανιχνεύεται κατά την εκκίνηση, επιλύεται με σειρά προτεραιότητας:

  1. η σημαία --lang (--lang el, --lang=fr, -l ja)
  2. η μεταβλητή περιβάλλοντος LOCKEDIN_LANG
  3. το locale σου (LC_ALL / LC_MESSAGES / LANG, μετά το locale του OS/runtime)
  4. τα Αγγλικά, ως εφεδρεία

Η normalizeLang() κανονικά χρησιμοποιεί το κύριο subtag του locale. Αυτό σημαίνει ότι το de-DE επιλέγει de, αλλά το tlh δεν γίνεται κατά λάθος tl· τα πραγματικά ψευδώνυμα fil και tgl σκόπιμα αντιστοιχίζονται στα Ταγκαλόγκ (tl), τα Νορβηγικά nb και nn αντιστοιχίζονται στο no, το παλαιό Ινδονησιακό in αντιστοιχίζεται στο id, και το παλαιό Εβραϊκό iw αντιστοιχίζεται στο he. Δύο περιφερειακοί κωδικοί διατηρούνται αυτούσιοι αντί να πτυχθούν στο κύριο subtag τους: τα pt-BR/pt_BR επιλέγουν τον κανονικό περιφερειακό κωδικό ενώ το γενικό pt παραμένει το προς-τα-πίσω-συμβατό bundle Πορτογαλικών Βραζιλίας (και τα δύο είναι Πορτογαλικά Βραζιλίας και μοιράζονται τα ίδια pools/UI), και τα en-SG/en_SG κρατούν τα Singlish (το γενικό en παραμένει Αγγλικά). Τα Παραδοσιακά Κινέζικα Χονγκ Κονγκ είναι το ίδιο είδος εξαίρεσης: τα zh-HK, zh_HK.UTF-8 και zh-Hant-HK επιλέγουν zh-HK, ενώ το γενικό zh και οι ηπειρωτικές ετικέτες επιλέγουν Απλοποιημένα Κινέζικα (zh).

Εναλλαγή εν πτήσει — ο πίνακας /language. Το CLI μπορούσε πάντα να ξεκινά σε άλλη γλώσσα (--lang, LOCKEDIN_LANG)· τώρα μπορείς να αλλάζεις μέσα στη συνεδρία. Πληκτρολόγησε /language (ψευδώνυμα /lang και /languages) για να δεις όλες τις 33 γλώσσες κατά κωδικό, καθεμία στο δικό της script· το /language el αλλάζει για την υπόλοιπη συνεδρία. Το νόημα είναι η έξοδος διαφυγής: μετά από μια εναλλαγή, ξανασχεδιάζει στη νέα γλώσσα και μετά, στη γλώσσα που μόλις άφησες, τυπώνει τον ακριβή δρόμο επιστροφής — /language en τώρα, lockedin --lang en την επόμενη φορά — ώστε αν προσγειωθείς κατά λάθος στο 日本語 ή στο ಕನ್ನಡ να μη μείνεις ποτέ αποκλεισμένος/η. (Άλλαξε δύο φορές και προσφέρεται και η γλώσσα που ονομάζει το LOCKEDIN_LANG σου.) Τα --lang και LOCKEDIN_LANG μένουν αμετάβλητα. Όπως το /a11y, είναι μια ειλικρινής χρησιμότητα, όχι μέρος της σάτιρας.

Η ιδέα: γλωσσικά bundles

Όλο το μεταφράσιμο κείμενο ζει σε bundles, ένα ανά γλώσσα, καθένα με σχήμα σαν:

{ meta: { lang: 'el', name: 'Ελληνικά', dir: 'ltr' },
  pools: { HOOKS: [ /* ~25 */ ], LESSONS: [ /* ... */ ], /* ... */ },
  ui:    { buzzwordDensity: 'Πυκνότητα buzzwords: ', /* labels, headings */ } }
  • Τα pools είναι οι πίνακες περιεχομένου (τα αστεία) που γνώρισες στο Κεφάλαιο 2.
  • Το ui είναι τα strings του chrome: labels, επικεφαλίδες και μικρά πρότυπα.

Τα Αγγλικά είναι το bundle αναφοράς μέσα στο src/lockedin.js· τα άλλα 32 bundle modules ζουν στο src/content/*.js: ar, bn, bo, de, el, en-SG, es, eu, fa, fi, fr, he, hi, id, is, it, ja, kn, ms, nl, no, pl, pt, pt-BR, ru, sv, tl, tr, uk, ur, zh, και zh-HK (το pt-BR επαναχρησιμοποιεί τα pools/UI του pt αλλά καταχωρείται ξεχωριστά). Καθένα καταχωρείται στο BUNDLES· το SUPPORTED_LANGS παράγεται από αυτά τα κλειδιά, και η renderHelp() τυπώνει αυτή την παραγόμενη λίστα κωδικών. Κανένα UI bundle δεν κάνει hard-code τη λίστα.

setLang('fr');       // στρέψε την ενεργή γλώσσα στο γαλλικό bundle
// L = ενεργά pools, U = ενεργό ui
pick(L.HOOKS)        // ένα γαλλικό hook
U.buzzwordDensity    // "Densité de jargon : "

Επειδή κάθε γεννήτρια διαβάζει το L και το U (ποτέ ένα hardcoded string), το setLang και μόνο αλλάζει όλη την εμπειρία. Αυτό είναι όλο το κόλπο.

Το δίχτυ ασφαλείας: ισοτιμία κλειδιών

Εδώ είναι το αναλλοίωτο που κάνει ασφαλή την προσθήκη μιας γλώσσας:

Κάθε bundle πρέπει να εκθέτει ακριβώς τα ίδια κλειδιά pools και ui με τα Αγγλικά.

Ένα test το επιβάλλει σε όλα τα 33 bundles. Αν προσθέσεις ένα νέο UI string στα Αγγλικά και ξεχάσεις να το μεταφράσεις στα Ουκρανικά, το npm test γίνεται κόκκινο και σου λέει ποιο κλειδί λείπει. Δεν μπορείς να δημοσιεύσεις σιωπηλά μια μισομεταφρασμένη γλώσσα.

Το δύσκολο κομμάτι: η διάταξη του terminal

Οι γλώσσες πιέζουν τη διάταξη του terminal με διαφορετικούς τρόπους:

  • Τα Ιαπωνικά, τα Απλοποιημένα Κινέζικα και τα Παραδοσιακά Κινέζικα Χονγκ Κονγκ χρησιμοποιούν χαρακτήρες East Asian Wide / Fullwidth. Το vw() τους μετρά ως δύο στήλες, και το wrap() σπάει σκληρά μακριά tokens χωρίς κενά ώστε το κείμενο CJK να μένει μέσα σε κάρτες και πλαίσια.
  • Τα Χίντι και Κανάντα χρησιμοποιούν συνδυαστικά σημάδια χωρίς διάστημα/που περικλείουν (Mn / Me), όπως matras και viramas. Το vw() τα μετρά ως μηδέν στήλες ώστε να μη φουσκώνουν το μετρημένο πλάτος.
  • Το box() αναδιπλώνει κάθε γραμμή σώματος πριν την κάνει padding, ώστε ένα μακρύ μεταφρασμένο banner να μην μπορεί πλέον να διαπεράσει το περίγραμμα.
  • Κάθε bundle ορίζει sentenceEnd και listSep (για παράδειγμα . / , , / ) ώστε οι προτάσεις που συνθέτει η γεννήτρια να διαβάζονται φυσικά.

Όταν προσθέτεις μια γλώσσα, τα strings επικεφαλίδας κάρτας (cardSubtitle, cardMeta, cardFooter) πρέπει ακόμα να χωρούν σε ≤ 60 ορατές στήλες. Τα Αραβικά, Περσικά, Εβραϊκά και Ουρντού ορίζουν meta.dir: 'rtl'. Η έξοδος δεν περιέχει bidi controls από προεπιλογή, γιατί μερικά terminals τα αποδίδουν ως labels σε πλαίσια. Το LOCKEDIN_BIDI=on ενεργοποιεί ρητά ισορροπημένα isolates μετά την αναδίπλωση για terminals γνωστά ότι τα υποστηρίζουν, διατηρώντας το ANSI, τις εντολές ASCII, και τη λογική σειρά αντιγραφής/επικόλλησης. Η προσβάσιμη έξοδος πάντα αφαιρεί αυτά τα controls. Χωρίς την προαιρετική ενεργοποίηση, η μεικτή σειρά RTL/LTR μπορεί να είναι λιγότερο εξελιγμένη· ποτέ μην ανιχνεύεις ή συμπεραίνεις υποστήριξη.

Το ύπουλο κομμάτι: γραμματική γύρω από ακατέργαστη είσοδο χρήστη

Ορισμένα πρότυπα UI μπολιάζουν ακατέργαστες προτάσεις χρήστη με placeholders όπως {cap}. Μην τα μεταφράζεις θέση-προς-θέση. Η πρόταση πρέπει να παραμένει γραμματική όταν το placeholder είναι μια φράση που πληκτρολόγησε ο χρήστης, όχι ένα καθαρό ουσιαστικό.

Ένα πραγματικό προειδοποιητικό bug: τα ιαπωνικά πρότυπα που βάζουν αμέσως μετά το {cap} μπορούν να ακούγονται λάθος όταν το {cap} είναι μια πλήρης πρόταση. Η διόρθωση δεν είναι «μετάφρασε πιο σκληρά»· είναι να αναδομήσεις το πρότυπο (για παράδειγμα, πρόσθεσε έναν ονοματοποιητή ή μετακίνησε το placeholder) ώστε η αυθαίρετη είσοδος χρήστη να ταιριάζει ακόμα.

✅ Δοκίμασέ το με τον πράκτορά σου — πρόσθεσε μια γλώσσα

Αυτή η άσκηση λειτουργεί ακόμα με ακριβώς τον ίδιο τρόπο. Διάλεξε μια γλώσσα που μπορείς να ελέγξεις για λογική (ή ζήτα από τον πράκτορα), και οδήγησέ την από άκρη σε άκρη. Γράψε πρώτα την προδιαγραφή:

Πρόσθεσε Δανικά (da). Δημιούργησε το src/content/da.js ως ένα bundle { meta, pools, ui } με τα ίδια κλειδιά με τα Αγγλικά, μεταφράζοντας κάθε εγγραφή (pools περιεχομένου ~25 το καθένα, όλα τα UI strings). Καταχώρησε το da στο BUNDLES στο src/lockedin.js. Τα --lang da και ένα locale da-* πρέπει να το επιλέγουν. Κράτα τα strings επικεφαλίδας κάρτας εντός του ορίου πλάτους. Το npm test πρέπει να μένει πράσινο, και πρόσθεσε αναλλοίωτα + tests ανίχνευσης για τα Δανικά που καθρεφτίζουν τα υπάρχοντα τοπικοποιημένα.

Μετά τρέξε τον βρόχο από τα Κεφάλαια 3–4:

  1. Πλάνο πρώτα. «Πριν γράψεις κώδικα, πες μου τα αρχεία που θα αλλάξεις και πώς θα κρατήσεις ισοτιμία κλειδιών με τα Αγγλικά.»
  2. Tests πρώτα. «Πρόσθεσε tests που αποτυγχάνουν: ανίχνευση da, ισοτιμία κλειδιών για da, και ένα δανικό αναλλοίωτο reflect/connect. Μη δημιουργήσεις ακόμα το bundle.»
  3. Υλοποίηση. «Τώρα δημιούργησε το src/content/da.js μεταφράζοντας ένα υπάρχον bundle κλειδί-προς-κλειδί, καταχώρησέ το, και κάνε τα tests να περνούν. Μόνο pick/shuffle για την τυχαιότητα.»
  4. Πύλη + έλεγχος. npm test, μετά lockedin --lang da post — και διάβασε το diff: μεταφράστηκε κάθε κλειδί; Ευθυγραμμίζονται ακόμα τα περιγράμματα των καρτών; Επιβιώνουν τα πρότυπα με {cap} σε ακατέργαστες προτάσεις χρήστη;

Μικρότερες ασκήσεις προθέρμανσης αν μια ολόκληρη γλώσσα είναι υπερβολή:

  • «Πρόσθεσε άλλο ένα TAGLINE σε όλα τα 33 γλωσσικά bundles, κρατώντας τους αριθμούς ίσους.»
  • «Έλεγξε αν το cardFooter των Κανάντα είναι ≤ 60 ορατές στήλες και εξήγησε πώς μετρήθηκαν τα συνδυαστικά σημάδια.»
  • «Δείξε μου το test που θα αποτύγχανε αν διέγραφα ένα κλειδί ui από το ja.js

Πού να πας στη συνέχεια

  • Ξεφύλλισε το src/content/es.js — παραμένει ένα φιλικό πρότυπο για ένα νέο bundle.
  • Ξαναδιάβασε το docs/HANDOFF.md → «Adding a language».
  • Απόλαυσε τα πολύγλωσσα αστεία στην Αναφορά εντολών.

Αυτό είναι το πλήρες μάθημα. Μπορείς πλέον να καθοδηγείς έναν πράκτορα AI ώστε να χτίζει χαρακτηριστικά και να τα τοπικοποιεί πίσω από μια πύλη ελέγχου — σε 33 γλώσσες και έτοιμος για περισσότερες. Συμφωνείς; 👇

📘 LockedIn CLI wiki

Tutorial

Reference


Satire · Sátira · 風刺. Not affiliated with LinkedIn. GPL-3.0-or-later.

Clone this wiki locally