Premessa dell'argomento
Ci sono tre aspetti distinti in un sito multilingue:
- traduzione dell'interfaccia
- contenuto
- instradamento URL
Sebbene siano tutti interconnessi in modi diversi, dal punto di vista del CMS vengono gestiti utilizzando diversi elementi dell'interfaccia utente e archiviati in modo diverso. Sembri essere fiducioso nella tua implementazione e comprensione dei primi due. La domanda riguardava quest'ultimo aspetto:"Traduzione degli URL? Dovremmo farlo o no? e in che modo?"
Di cosa può essere fatto l'URL?
Una cosa molto importante è, non avere fantasia con IDN . Preferisci invece la traslitterazione (anche:trascrizione e romanizzazione). Sebbene a prima vista IDN sembri un'opzione praticabile per gli URL internazionali, in realtà non funziona come pubblicizzato per due motivi:
- alcuni browser gireranno i caratteri non ASCII come
'ч'
o'ž'
in'%D1%87'
e'%C5%BE'
- se l'utente ha temi personalizzati, è molto probabile che il carattere del tema non contenga simboli per quelle lettere
In realtà ho provato ad avvicinarmi a IDN alcuni anni fa in un progetto basato su Yii (quadro orribile, IMHO). Ho riscontrato entrambi i problemi sopra menzionati prima di raschiare quella soluzione. Inoltre, sospetto che possa essere un vettore di attacco.
Opzioni disponibili... come le vedo io.
Fondamentalmente hai due scelte, che potrebbero essere astratte come:
-
http://site.tld/[:query]
:dove[:query]
determina sia la lingua che la scelta dei contenuti -
http://site.tld/[:language]/[:query]
:dove[:language]
parte dell'URL definisce la scelta della lingua e[:query]
viene utilizzato solo per identificare il contenuto
La query è Α e Ω ..
Diciamo che scegli http://site.tld/[:query]
.
In tal caso hai una fonte primaria del linguaggio:il contenuto di [:query]
segmento; e due fonti aggiuntive:
- valore
$_COOKIE['lang']
per quel particolare browser - elenco delle lingue nell'intestazione HTTP Accept-Language
Innanzitutto, devi abbinare la query a uno dei modelli di instradamento definiti (se la tua scelta è Laravel, quindi leggi qui ). Una volta completata la corrispondenza del modello, devi quindi trovare la lingua.
Dovresti passare attraverso tutti i segmenti del modello. Trova le potenziali traduzioni per tutti quei segmenti e determina quale lingua è stata utilizzata. Le due fonti aggiuntive (cookie e intestazione) verrebbero utilizzate per risolvere i conflitti di routing, quando (non "se") si verificano.
Prendi ad esempio:http://site.tld/blog/novinka
.
Questa è la traslitterazione di "блог, новинка"
, che in inglese significa approssimativamente "blog", "latest"
.
Come puoi già notare, in russo "блог" verrà traslitterato come "blog". Ciò significa che per la prima parte di [:query]
tu (nello scenario migliore ) finirà con ['en', 'ru']
elenco delle possibili lingue. Quindi prendi il segmento successivo:"novinka". Potrebbe avere solo una lingua nell'elenco delle possibilità:['ru']
.
Quando l'elenco contiene un elemento, hai trovato correttamente la lingua.
Ma se finisci con 2 (esempio:russo e ucraino) o più possibilità .. o 0 possibilità, a seconda dei casi. Dovrai utilizzare il cookie e/o l'intestazione per trovare l'opzione corretta.
E se tutto il resto fallisce, scegli la lingua predefinita del sito.
Lingua come parametro
L'alternativa è utilizzare l'URL, che può essere definito come http://site.tld/[:language]/[:query]
. In questo caso, quando traduci query, non è necessario indovinare la lingua, perché a quel punto sai già quale usare.
C'è anche una fonte secondaria del linguaggio:il valore del cookie. Ma qui non ha senso pasticciare con l'intestazione Accept-Language, perché non hai a che fare con una quantità sconosciuta di lingue possibili in caso di "avvio a freddo" (quando l'utente apre per la prima volta il sito con una query personalizzata).
Invece hai 3 opzioni semplici e prioritarie:
- se
[:language]
il segmento è impostato, utilizzalo - se
$_COOKIE['lang']
è impostato, utilizzalo - usa la lingua predefinita
Quando hai la lingua, provi semplicemente a tradurre la query e, se la traduzione non riesce, utilizza il "valore predefinito" per quel particolare segmento (in base ai risultati di routing).
Non c'è qui una terza opzione?
Sì, tecnicamente puoi combinare entrambi gli approcci, ma ciò complicherebbe il processo e soddisferebbe solo le persone che desiderano modificare manualmente l'URL di http://site.tld/en/news
a http://site.tld/de/news
e aspettati che la pagina delle notizie cambi in tedesco.
Ma anche questo caso potrebbe essere mitigato utilizzando il valore del cookie (che conterrebbe informazioni sulla precedente scelta della lingua), da implementare con meno magia e speranza.
Quale approccio utilizzare?
Come avrai già intuito, ti consiglierei http://site.tld/[:language]/[:query]
come l'opzione più sensata.
Anche nella situazione delle parole reali avresti la terza parte principale nell'URL:"titolo". Come nel nome del prodotto nel negozio online o nel titolo dell'articolo nel sito di notizie.
Esempio:http://site.tld/en/news/article/121415/EU-as-global-reserve-currency
In questo caso '/news/article/121415'
sarebbe la query e il 'EU-as-global-reserve-currency'
è il titolo. Puramente per scopi SEO.
Si può fare in Laravel?
Un po', ma non per impostazione predefinita.
Non ho molta familiarità con esso, ma da quello che ho visto, Laravel utilizza un semplice meccanismo di routing basato su pattern. Per implementare URL multilingue probabilmente dovrai estendere le classi principali , perché il routing multilingue richiede l'accesso a diverse forme di archiviazione (database, cache e/o file di configurazione).
È instradato. E adesso?
Come risultato di tutto ciò vi ritroverete con due preziose informazioni:la lingua corrente e i segmenti di query tradotti. Questi valori possono quindi essere utilizzati per inviare alle classi che produrranno il risultato.
Fondamentalmente, il seguente URL:http://site.tld/ru/blog/novinka
(o la versione senza '/ru'
) viene trasformato in qualcosa come
$parameters = [
'language' => 'ru',
'classname' => 'blog',
'method' => 'latest',
];
Che usi solo per la spedizione:
$instance = new {$parameter['classname']};
$instance->{'get'.$parameters['method']}( $parameters );
.. o qualche sua variazione, a seconda della particolare implementazione.