Passa al contenuto principale

Internazionalizzazione

Flarum dispone di un potente sistema di traduzione (basato sul Traduttore Symfony) che consente all'interfaccia di visualizzare le informazioni praticamente in qualsiasi lingua. Dovresti considerare di sfruttare il traduttore di Flarum mentre sviluppi la tua estensione, anche se non hai intenzione di usarlo in più di una lingua.

Per prima cosa, questo sistema ti consentirà di modificare le informazioni visualizzate dalla tua estensione senza modificare il codice effettivo. Ti darà anche gli strumenti necessari per affrontare in modo efficiente fenomeni come il pluralismo e l'accordo per il genere. E non si sa mai: potrebbe tornare utile in seguito se decidi di aggiungere più lingue e rendere la tua estensione disponibile agli utenti di tutto il mondo!

Questa guida ti mostrerà come creare unf ile locale contenente traduzioni per la tua estensione, e come utilizzare il traduttore per accedere a tali risorse dall'interno del codice. Imparerai come affrontare traduzioni più complesse che coinvolgono variabili e tag HTML, così come le pluralizzazioni ed i generi.

Descriveremo anche i formati standardda seguire nello sviluppo di traduzioni per Flarum, e vi daremo alcuni consigli che può aiutarti a rendere le tue risorse più facili da localizzare. Ma prima, iniziamo con una panoramica di come Flarum assegna la priorità alle risorse durante la visualizzazione dell'output per un'estensione di terze parti.

Come traduce Flarum

È possibile impostare una chiave in modo che faccia riferimento ad un'altra sostituendo la sua traduzione con un segno di uguale (=), un segno di maggiore (>), e uno spazio, seguito dalla chiave di traduzione completa a cui fare riferimento. Quando l'estensione è installata, il compilatore di Flarum risolverà questi riferimenti per creare un set completo di traduzioni che può usare.

Flarum incorpora traduzioni da diverse fonti:

  • Come un pulsante su cui gli utenti possono fare clic quando desiderano modificare alcune cose
  • Come il titolo di una finestra di dialogo visualizzata quando gli utenti fanno clic su quel pulsante

Di norma, un sito Flarum può visualizzare solo le traduzioni corrispondenti ai language pack che sono stati installati su quel sito. Ma Flarum farà del suo meglio & mdash; entro questa limitazione & mdash; per rendere l'output della tua estensione in una sorta di linguaggio leggibile dall'utente:

  1. Inizierà cercando una traduzione nella lingua di visualizzazione preferita dall'utente.
  2. Se non riesce a trovarne una, cercherà una traduzione nella lingua predefinita del forum.
  3. Come ultimo tentativo, cercherà una traduzione inglese "generica" dell'output.
  4. Se nessuno dei precedenti è disponibile, si arrenderà e visualizzerà una chiave di traduzione.

Poiché le traduzioni in inglese potrebbero essere l'unica cosa che si frappone tra gli utenti del forum e le antiestetiche chiavi di traduzione, consigliamo vivamente di includere un set completo di risorse in inglese con ogni estensione. (Dovrai anche includere risorse in inglese se desideri elencare la tua estensione su Flarum Marketplace.) A differenza delle estensioni in bundle di Flarum & mdash; che vengono tradotti utilizzando risorse aggiunte da pacchetti di lingue; un'estensione di terze parti deve fornire tutte le proprie traduzioni.

File Locali

Le risorse linguistiche di Flarum utilizzano l'estensione ed il formato file YAML. I file delle impostazioni locali per un'estensione di terze parti devono essere archiviati nella cartella locale dell'estensione. Ogni file locale deve essere denominato utilizzando l'estensione ISO 639-1 per la lingua che contiene. Ad esempio, un file contenente traduzioni francesi dovrebbe essere denominato "fr.yml".

tip

Se desideri fornire supporto per una lingua specifica, puoi aggiungere un trattino basso seguito da un codice regione ISO 3166-1 alpha-2; il nome del file per il francese parlato in Canada, ad esempio, sarebbe "fr_CA.yml". Ma dovresti assicurarti di includere un file locale contenente traduzioni "generiche" per la stessa lingua, così Flarum avrà qualcosa su cui ripiegare nel caso in cui un utente specifichi una lingua che non hai fornito.

Lo scheletro di estensione include anche il template locale/en.yml dove puoi inserire le traduzioni in inglese della tua estensione. Se si desidera aggiungere risorse per un'altra lingua o locale, è sufficiente duplicare il modello e assegnargli un nome file appropriato. Quindi apri il file e inizia ad aggiungere le tue traduzioni!

Aggiungere chiavi

Ogni traduzione nel file locale deve essere preceduta da una chiave, che utilizzerai come identificatore per quella traduzione. La chiave ID dovrebbe essere in snake_case e seguito da due punti e uno spazio, come mostrato di seguito:

sample_key: Questa è una traduzione di esempio.

Puoi anche utilizzare le chiavi per dare spazi ai nomi per le tue traduzioni.. Per i principianti, la prima riga del file locale dovrebbe consistere in una singola chiave che raccoglie tutte le traduzioni per la tua estensione in un unico spazio. Questa chiave dovrebbe corrispondere esattamente al nome della cartella in cui risiede l'estensione kebab-case.

È possibile utilizzare chiavi aggiuntive per dividere lo spazio dei nomi dell'estensione in gruppi. Ciò è utile quando si desidera organizzare le traduzioni in base a dove vengono visualizzate nell'interfaccia utente, ad esempio. Queste chiavi di spaziatura dei nomi intermedie dovrebbero sempre essere in snake_case.

Ogni chiave di spaziatura dei nomi dovrebbe anche essere seguita da due punti. Le chiavi devono essere nidificate secondo il formato struttura YAML, aggiungendo due spazi di rientro per ogni livello nella gerarchia. Metti tutto insieme ed il file locale tutorial per iniziare dovrebbe assomigliare a questo:

acme-hello-world:                # NameSpacing per l'estensione; senza indentazione.
alert: # Namespacing per gli alerts; indentazione di 2 spazi.
hello_text: "Hello, world!" # Identificatore/traduzione; indentazione di 4 spazi.

Una volta che hai queste informazioni a posto, puoi formare la chiave di traduzione completa che utilizzerai per accedere a una traduzione elencandone le chiavi in ordine dallo spazio dei nomi dell'estensione a un identificatore, con i punti come delimitatori. Ad esempio, la chiave di traduzione completa per "Hello, world!" sarebbe:

'acme-hello-world.alert.hello_text'

Questo è davvero tutto ciò che devi sapere sui meccanismi di creazione delle chiavi. Tieni presente, tuttavia, che esiste un formato standard che gli sviluppatori devono seguire quando creano le risorse linguistiche per Flarum. Le regole per il namespacing delle traduzioni e assegnare un nome ad chiavi ID possono essere trovati nell'appencice A.

Aggiungere traduzioni

Gli esempi nella sezione precedente ti hanno già fornito le basi:digiti una chiave ID seguito da due punti e uno spazio quindi digiti la traduzione. Facile! Ora vorremmo solo aggiungere alcuni dettagli che ti aiuteranno a gestire traduzioni più lunghe e complesse.

Virgolette

Avrai notato che solo una delle due traduzioni di esempio nella sezione precedente era racchiusa tra virgolette. Generalmente non è necessario delimitare le traduzioni in questo modo. Tuttavia, dovresti utilizzare virgolette doppie per racchiudere qualsiasi traduzione che includa uno o più dei seguenti caratteri:

`  !  @  #  %  &  *  -  =  [  ]  {  }  |  :  ,  <  >  ?

Poiché Flarum utilizza parentesi graffe e parentesi angolari per indicare i le variabili ed i tag HTML, rispettivamente, è ovvio che qualsiasi traduzione che includa tali variabili dovrà essere racchiusa tra virgolette doppie.

Inoltre, dovresti usare virgolette singole per racchiudere qualsiasi traduzione che includa una o più virgolette doppie (") o backslash (\). Questa regola ha la precedenza! Quindi, se una traduzione dovesse includere sia le virgolette doppie che uno o più caratteri dalla lista sopra come questo esempio, in cui una variabile è compensata da virgolette andrebbe racchiuso tra virgolette singole .

Blocchi letterali

Quando è necessario che una traduzione appaia come più di una singola riga di testo, la traduzione deve essere aggiunta come un blocco letterale . Inserisci una barra verticale (|) dove normalmente inizieresti la traduzione, quindi aggiungi la traduzione sotto il tasto ID, facendo rientrare ogni riga di altri due spazi:

literal_block_text: |
Queste righe verranno visualizzate come mostrato qui, interruzioni di riga e tutto il resto.

Anche il rientro extra viene mantenuto: questa riga sarà rientrata di 4 spazi!

Le virgolette non sono necessarie, anche quando il blocco contiene caratteri speciali.

Il blocco letterale termina con l'ultima riga da rientrare di almeno due spazi in più rispetto alla chiave ID. Le virgolette non sono necessarie perché il blocco è effettivamente delimitato da questi due spazi extra di rientro.

Le principali risorse linguistiche di Flarum utilizzano blocchi letterali principalmente per il contenuto del corpo dell'email.

Riferimenti chiave

Non è raro utilizzare la stessa porzione di testo in più di una posizione o contesto. Supponiamo che tu voglia che la tua estensione visualizzi la frase "Modifica elementi" in due posizioni nell'interfaccia utente:

  • Come un pulsante su cui gli utenti possono fare clic quando desiderano modificare alcune cose
  • Come il titolo di una finestra di dialogo visualizzata quando gli utenti fanno clic su quel pulsante

Il tuo istinto potrebbe essere quello di aggiungere un'unica traduzione chiamiamola "edit_stuff" e usiamo quella chiave ID due volte nel tuo codice. Questo approccio è efficiente, ma manca di flessibilità: in alcune lingue, potrebbe non essere possibile utilizzare la stessa frase sia per il pulsante che per il titolo della finestra di dialogo! Un modo migliore sarebbe definire due chiavi da utilizzare nel codice, quindi impostarle entrambe per fare riferimento alla stessa traduzione, in questo modo:

edit_stuff_button: => edit_stuff    # Utilizzato nel codice che crea il pulsante.
edit_stuff_title: => edit_stuff # Utilizzato nel codice che crea la finestra di dialogo.

edit_stuff: Edit Stuff # Non utilizzato nel codice.

È possibile impostare una chiave in modo che faccia riferimento ad un'altra sostituendo la sua traduzione con un segno di uguale (=), un segno di maggiore (>), e uno spazio, seguito dalla chiave di traduzione completa a cui fare riferimento. Quando l'estensione è installata, il compilatore di Flarum risolverà questi riferimenti per creare un set completo di traduzioni da utilizzare.

C'è altro da dire sulla referenziazione per prima cosa, abbiamo completamente ignorato il problema dello spazio dei nomi nell'esempio sopra! E ti starai chiedendo perché abbiamo suggerito di creare tre chiavi quando due sarebbero sufficienti. Per una spiegazione, vedere le regole per la riutilizzazione di traduzioni nell'appendice A.

Utilizzare il traduttore

Dopo aver aggiunto una traduzione al file delle impostazioni locali, con spazi dei nomi e chiavi di identificazione appropriati, è possibile utilizzare l'estensione app.translator.trans() per fare riferimento a tale traduzione nel codice. Per esempio il file js/forum/src/index.js Tutorial per iniziare potrebbe finire per assomigliare a questo:

app.initializers.add('acme-hello-world', function() {
alert(app.translator.trans('acme-hello-world.alert.hello_text'));
});

Questo mostra il metodo di traduzione di base, senza campanelli o fischietti allegati. Di seguito troverai esempi di traduzioni più complesse che coinvolgono variabili e tag HTML. (Tieni presente che abbiamo omesso lo spazio dei nomi nei seguenti esempi per mantenerli semplici; se guardi il codice effettivo, troverai che le traduzioni hanno una spaziatura dei nomi appropriata in base al formato standard.)

Includere Variabili

Puoi includere variabili nelle traduzioni. As an example, let's look at the code that creates the first item in Flarum's search results dropdown. Questo pulsante cita la query di ricerca inserita dall'utente e altre informazioni che vengono passate al traduttore insieme alla chiave di traduzione, come parametro aggiuntivo:

{LinkButton.component({
icon: 'search',
children: app.translator.trans('all_discussions_button', {query}),
href: app.route('index', {q: query})
})}

Una variabile corrispondente nella traduzione consente al traduttore di sapere dove inserire la variabile:

all_discussions_button: 'Cerca in tutte le discussioni "{query}"'

Poiché le parentesi graffe vengono utilizzate per indicare le variabili, la traduzione nel suo insieme deve essere racchiusa in Virgolette. Normalmente, vengono utilizzate le virgolette doppie; ma poiché questa particolare traduzione utilizza le virgolette doppie per impostare la query di ricerca, la regola delle virgolette singole ha la precedenza.

Aggiungere tag HTML

L'estrazione delle traduzioni dall'HTML può rappresentare una sfida unica: come gestisci gli elementi HTML che influenzano solo una parte della frase? Fortunatamente, Flarum ti offre un modo per aggiungere tag alle tue traduzioni.

Si inizia aggiungendo una chiave ai parametri di ogni elemento che si desidera venga gestito dal traduttore. The following snippet — from the Edit Group modal of the admin interface — shows a translation key accompanied by a parameters object with one item.

<div className="helpText">
{app.translator.trans('icon_text', {
a: <a href="https://fortawesome.github.io/Font-Awesome/icons/" tabindex="-1"/>
})}
</div>

Nota che ogni parametro è definito utilizzando un singolo tag HTML, con una barra aggiunta prima della parentesi angolare di chiusura. È quindi possibile utilizzare tag di apertura e chiusura in stile HTML nel file delle impostazioni locali per specificare quale parte della traduzione è interessata da ciascun elemento. Ancora una volta, sono richieste virgolette doppie. Puoi vedere che non tutti i tag vengono passati come argomenti, solo quelli che hanno attributi.

icon_text: "Immetti il nome di qualsiasi icona <a>FontAwesome</a>, <em>senza</em> il prefisso <code>fa-</code> "

Ovviamente puoi dare a un parametro il nome che preferisci; puoi utilizzare <fred> e </fred> per racchiudere il testo del tuo link se ti può far piacere! Tuttavia, ti consigliamo di rimanere il più vicino possibile ai tag HTML effettivi rappresentati, in modo che i tuoi localizzatori saranno in grado di capire cosa sta succedendo.

I localizzatori possono riordinare gli elementi secondo necessità e persino scegliere di omettere i tag se lo desiderano. Ma non possono aggiungere tag propri: il traduttore ignorerà semplicemente qualsiasi tag in stile HTML che non corrisponde a un parametro definito correttamente nel codice.

Gestione della pluralizzazione

A volte, potrebbe essere necessario fornire versioni alternative di una traduzione per consentire la pluralizzazione di una parola o frase. Flarum utilizza la sintassi ICU MessageFormat per supportare la selezione di traduzioni basate su variabili. Il caso di uso più frequente è la pluralizzazione e la genderizzazione.

const remaining = this.minPrimary - primaryCount;
return app.translator.transChoice(
'choose_primary_placeholder',
remaining,
{ count: remaining }
);

Questo esempio è tratto da Scegli tag modali dell'omonima estensione, dove indica all'utente quanti altri tag primari possono essere selezionati. Ecco la traduzione in inglese del codice sopra:

choose_primary_placeholder: "Choose a primary tag|Choose {count} primary tags"

In questo caso, chiamiamo la variabile di pluralizzazione count. Non è fondamentale, ma raccomandiamo vivamente di utilizzare count per coerenza.

Ovviamente l'inglese ha solo due varianti: singolare o plurale. Dovrai fornire varianti aggiuntive quando crei traduzioni per una lingua che ha più di una forma plurale.

In addition to =0/=1/=2/... and other, the following plural keywords are supported: zero, one, two, few, and many.

See the Symfony Translation docs for more complex examples.

Avere a che fare con i generi

Support for grammatical gender will be added in a future version of Flarum. Detailed instructions will be provided here once that functionality becomes available.

Traduzione lato server

Translation is generally handled by Flarum's front-end client. However, you can use translations in your PHP code if you need to.

First, you'll need to get an instance of the Flarum\Locale\Translator class. You'll usually do this by typehinting this class in the constructor of your class so a translator instance is injected by the IoC Container. If dependency injection is not available, you can use resolve(Translator::class). Don't forget a use Flarum\Locale\Translator; statement at the top of your PHP file!

Then, the API is similar to the JavaScript Translator class. You can use $translator->trans like you'd use app.translator.trans in JavaScript. You can learn more about the Translator's methods in Symfony's Translator documentation, which Flarum's Translator extends.

Registrazione delle impostazioni locali

There's one last thing you need to do before Flarum can use your translations. You need to register them. Fortunately, Flarum makes this pretty easy. Add the following to your extend.php:

new Extend\Locales(__DIR__ . '/locale'),

Appendice A: formato chiave standard

The following guidelines were created for use in the Flarum core and bundled extensions. Their purpose is to ensure that translation keys are organized and named in a consistent fashion, so Flarum's localizers will be able to create and maintain high-quality language packs with a minimum of difficulty.

Developers who wish to contribute to the development of Flarum are expected to follow these guidelines. Third-party developers may also wish to follow them, so experienced Flarum localizers who undertake the translation of third-party extensions will find themselves working in familiar surroundings.

Namespacing delle Traduzioni

All translations are to be organized in categories, using namespacing keys arranged in up to three levels. Each level provides localizers with an important bit of information about where the translation is used:

➡ La chiave di primo livello indica quale componente utilizza la traduzione .

The namespacing for translation keys used in official Flarum components, including bundled extensions, should match the name of the language pack locale file for the component in question. The namespaces for Flarum's non-extension components are fixed as shown below:

core:        # Traduzioni usate dal core di Flarum
validation: # Traduzioni usate dal validatore di Laravel

Translation keys used in an extension including any third-party extension need to be namespaced using the extension's name in vendor-package format where the flarum- and flarum-ext- prefixes are stripped from the package (e.g, flarum-tags for the Tags extension and foo-bar for a foo/flarum-ext-bar extension).

There should be only one first-level prefix in any locale file; it should be the first line in the locale file.

➡ La chiave di secondo livello indica quale interfaccia utilizza la traduzione .

Since Flarum doesn't have all that many interfaces, we've come up with a short list of second-level keys for you to choose from. We've included the more frequently used ones in the locale file template created with the extension skeleton. Below you will find the complete list, with explanations:

admin:       # Traduzioni utilizzate dall'interfaccia di amministrazione.
forum: # Traduzioni utilizzate dall'interfaccia utente del forum.
lib: # Traduzioni utilizzate da uno dei precedenti.
views: # Traduzioni utilizzate al di fuori del normale client JS.
api: # Traduzioni utilizzate nei messaggi emessi dall'API.
email: # Traduzioni utilizzate nelle email inviate da Flarum.

The first four keys correspond roughly to the directories containing the code where the translations in that namespace will be used. (Most of your keys will probably go in admin or forum.) The remaining two keys are a bit different: the api namespace is for translations used in messages output by the API, while the email namespace contains the resources for all emails sent by the forum.

ref:         # Traduzioni referenziate da più di una chiave.
group: # Traduzioni utilizzate come gruppi predefiniti.

These two keys don't correspond to interfaces; they're for translations that require special handling. We'll explain how to use the ref namespace when we talk about reusing translations. The group namespace holds the default group names, which are translated by the server rather than at the front end.

➡ La chiave di terzo livello indica quale parte dell'interfaccia utente utilizza la traduzione .

The keys in this level are not so rigidly defined. Their main purpose is to chop the UI up into manageable chunks, so localizers can find the translations and see for themselves how they are used by the software. (Third-level keys aren't used in the ref and group namespaces, which don't need chopping.)

If you're modifying an existing location to add a new setting to the Settings page, for example you should copy our namespacing so experienced Flarum localizers will know at a glance exactly where the new translations are displayed. See English translations in flarum/core and bundled extensions for examples.

If your extension adds a new location such as a new dialog box you should feel free to create a new third-level key to namespace the translations that go there. Take a couple minutes to familiarize yourself with the namespacing in the locale files linked above, then create a new key that fits in with that scheme.

As a general rule, third-level keys should be short no more than one or two words and expressed in snake_case. They should be descriptive of the locations where the translations are used.

Denominazione delle chiavi di identificazione

Like the third-level namespacing keys, identifier keys should be expressed in snake_case. ID keys should be arranged in alphabetical order within each namespace, so they'll be easy for developers to find. (There is one exception to this rule! ID keys in the email namespace should be listed just as they appear in your mail client: subject first, then body.)

The typical ID key consists of two parts a root and a suffix each of which may be omitted in certain circumstances. Just as the namespacing keys tell localizers where the translation is used, each part of the ID key provides a further bit of information about the translation:

➡ Il suffisso indica come viene utilizzata la traduzione .

We'll start with the suffix because it's the most important part of the key name. It tells localizers what sort of object they should look for when trying to find the translation in the interface. For example, the suffixes in the following list are used for GUI objects more or less related to user operations:

_button:        # Utilizzato per i pulsanti (comprese le voci del menu a discesa).
_link: # Utilizzato per i collegamenti che non vengono visualizzati graficamente come pulsanti.
_heading: # Utilizzato per le intestazioni in tabelle ed elenchi.
_label: # Utilizzato per i nomi dei campi dati, le impostazioni delle caselle di controllo, ecc.
_placeholder: # Utilizzato per il testo predefinito visualizzato nei campi.

These suffixes are used for informative or descriptive text elements:

_confirmation:  # Utilizzato per i messaggi visualizzati per confermare un'operazione.
_message: # Utilizzato per i messaggi che mostrano il risultato di un'operazione.
_text: # Utilizzato per qualsiasi testo che non sia un messaggio, un titolo o una descrizione comando.
_title: # Utilizzato per il testo visualizzato come titolo di una pagina o modale.
_tooltip: # Utilizzato per il testo visualizzato quando l'utente passa con il mouse su qualcosa.

And there are two suffixes that are used only in the email namespace:

_body:          # Utilizzato per il contenuto del messaggio di posta elettronica.
_subject: # Utilizzato per la riga dell'oggetto del messaggio di posta elettronica.

The above is a complete listing of the suffixes available for use in locale files. You should take care to use them consistently, as doing so will make life easier for localizers. If you feel something is missing from the list, please file an issue with the developers; we'll consider adding a new suffix if the situation warrants it.

Suffixes should be omitted from ID keys for reused translations in the ref: namespace. This is because you can't be sure these translations will always be used in the same context. Adding a new context would mean changing the key name everywhere it's referenced so it's best to keep these translations generic.

➡ La radice indica cosa dice la traduzione .

In other words, it should be a brief summation of the translation's content. If the translation is a very short phrase no more than a few words long you may want to use it verbatim (in snake_case, of course). If it's very long, on the other hand, you should try to boil it down to as few words as possible.

In some cases, the summary may be replaced by a description of the object's function. This is commonly seen in buttons. The button that submits a form should be identified as a submit_button regardless of whether the translation says "OK" or "Save Changes". In a similar vein, the button that dismisses a dialog or message box is always a dismiss_button, even if it actually reads "OK" or "Cancel".

The root may also be omitted in certain cases usually when the suffix alone is sufficient to identify the translation. For example, it's unlikely that a page or dialog box will have more than one title and like as not, the content of the title is already given in the third-level namespacing! So the suffix can stand alone.

Suffixes are also sufficient to identify the subject and body components of an email message since each email will have only one subject line and one body. Note that the leading underscore is omitted in such cases: you would use just title, subject, or body as the ID key.

Riutilizzo delle traduzioni

Flarum's unique key references fulfill the same role as YAML anchors, but they're better in one respect: you can even reference keys in a different file! For this reason, you need to use the full translation key when referencing. Here's a more realistic example of how referencing works, complete with namespacing:

core:

forum:
header:
log_in_link: => core.ref.log_in

log_in:
submit_button: => core.ref.log_in
title: => core.ref.log_in

ref:
log_in: Log In

As you can see, we want to reuse a single translation in three different contexts (including two locations): (1) as a link displayed in the site header, (2) as a button displayed in the Log In modal, and (3) as the title of that modal. So all three of these keys have been set to reference the same full translation key.

The reused translation is identified by a key that omits the suffix as specified above and is placed in the ref namespace. The latter measure is needed to avoid conflicts that can occur if a reused translation is given the same name as a second-level namespacing key. (The email keys are a case in point.)

The ref namespace also makes it easy to track translation reuse. Imagine what would happen if you set the scalars for the button and title to reference core.forum.header.log_in_link instead:

core:

forum:
header:
log_in_link: => Log In

log_in:
submit_button: => core.forum.header.log_in_link # Never reference keys
title: => core.forum.header.log_in_link # that aren't in "ref"!

It would very easy to change the translation for the header link without realizing that you're also changing things in the Log In modal to say nothing of any extensions that might also be referencing that key! This sort of thing will be less likely to occur if you keep your reused translations in the ref namespace.

For this reason, any key references in the core resources must point to keys in the core.ref namespace. Key references in the resources for bundled extensions may point to either of two locations:

  • Le traduzioni specifiche dell'estensione dovrebbero andare in ref dei file locali dell'estensione.

  • Le traduzioni utilizzate sia dall'estensione che dal core dovrebbero essere inserite in core.ref.

Third-party extensions are welcome to reference keys in the core.ref namespace, but please be aware that we cannot add translations to this namespace based on reuse in third-party extensions. A third-party dev who wants to reuse a translation from a namespace other than core.ref will need to add a properly keyed duplicate translation to the extension's locale file.

No extension should ever reference a key from another extension, as doing so will result in a dependency.

One final caution: translation keys in the ref namespace should never be inserted directly in code. This is because localizers may end up creating a translation to replace every reference to a reused translation key in which case they would be within their rights to remove that key from the locale file. If such a key were being used in the code, it would end up without a matching resource to translate it!

Aggiunta di commenti

Comments (and empty lines) should be added to locale files so localizers will find them easier to navigate.

We've included some block comments in the locale file template included with the extension skeleton. They are there to remind developers of some basic concepts: translation keys should not be used in more than one place; keys for reused translations should never be inserted directly in code; and so forth.

You should add comment lines above every second- or third-level namespacing key, to give localizers a more complete description of the location covered by that namespace. When copying existing keys, be sure to copy the comment as well (and modify it if necessary). If you add a new third-level key, remember to preface it with a comment to explain the location being added.

You may also wish to add inline comments after a specific translation to provide localizers with further information about that translation (such as the fact that a translation can be pluralized if necessary).

Appendice B: Codifica per il mondo

In this appendix, we'd like to offer a few tips that may help you to avoid some of the more common pitfalls in the internationalization process. Abstracting language from code is easily one of the more humdrum tasks a programmer has to deal with, but if you don't give due attention to the subtleties involved, you're likely to end up creating your localizers an unnecessary headache or two.

Of course, it's not just about making life easier for localizers. Because when they get headaches, they will come to you for help often months (or even years) after you've put the project behind you and moved on to something else! It's the sort of situation where an ounce or two of prevention may indeed be worth several pounds of cure further down the road for everybody involved.

It's probably impossible to avoid localization issues completely; there are just too many variables. But by following a few simple guidelines, you should be able to head off many issues before they happen.

Elimina tutto il testo codificato!

This probably goes without saying. After all, if you're going to go to the trouble of extracting translations, you might as well finish the job, right? Well, yes, but that's easier said than done. It's really quite unusual to find a program that doesn't have at least a few bits of hardcoded text floating around somewhere.

Even tiny bits of text can cause problems for localizers. A comma here, a colon there perhaps a pair of brackets inserted to make the page more legible: such things can and do cause issues for localizers. After all, not all languages use the same glyphs for these things! Just one hardcoded space can be a problem for someone trying to translate the interface into a language that doesn't use spaces to separate words.

Generally speaking, any displayed text that isn't supplied by a variable or the result of a calculation must be included in the locale files. That's easily said, but actually doing it takes a bit of perseverance.

Evita sintassi codificata

Hardcoded text isn't the only way that code can create problems for localizers. Hardcoded syntax issues occur when the code forces words into a specific order that just won't work in other languages. They are generally the result of using two translations where just one would be more appropriate.

For an example, let's look at the line of text that's printed near the bottom of the Log In modal:

Non hai un account? Registrati

We originally coded this line as two translations, which were separated by a hardcoded space:

core:

forum:
header:
log_in_link: => Log In

log_in:
submit_button: => core.forum.header.log_in_link # Non fare mai riferimento alle chiavi
title: => core.forum.header.log_in_link # che non sono in "ref"!

There were good reasons for doing it this way. For one thing, it made it easy to turn the second half into a link. And since the second translation is reused elsewhere, keeping it separate seemed like a no-brainer.

But there were problems with this approach. The hardcoded space seemed likely to pose issues for some localizers, as mentioned above. And splitting this text into two strings would make it impossible to render the line as a single sentence with the link embedded in the middle:

Se non hai ancora un account, puoi [registrarti] (#)!

Since it seemed possible that a localizer might need this sort of flexibility, we opted to abstract the line as a single translation, using HTML-style tags to enclose the link text:

sign_up_text: "Non hai un account? <a>Registrati</a>"

This puts the (formerly hardcoded) space in the translation, so localizers who don't need it can remove it. And the tags can be positioned freely within the translation, making this approach much more flexible.

The moral of this story is: when you've got two adjacent chunks of text which seem related to each other grammatically or even semantically you should think about finding a way to incorporate them both in a single translation. Your localizers may have cause to thank you!

We might also conclude that the presence of little bits of hardcoded text such as the hardcoded space in this example may be a sort of code smell indicating the presence of a deeper issue. This isn't always the case, but it's a possibility that's worth taking into consideration.

Tieni gli occhi aperti sui plurali!

They are surprisingly easy to overlook. Of course, the need for pluralization support is fairly obvious here:

A Toby piace questo. A te piace questo. A Toby e Franz piace questo.

And the situation is complicated by the presence of the second-person pronoun, since it always takes the plural form in English, even when we're talking about one person. That's why the app.translator call is so complicated in the code that outputs the above sentences for the Likes extension.

Now look at this similar set of sentences, output by similar code in the Mentions extension:

Toby ha risposto a questo. Hai risposto a questo. Toby e Franz hanno risposto a questo.

In English, the simple past tense is not affected by pluralization. Since the verb phrase is always the same, it would be fairly easy to ignore the plurals and use the app.translator.trans() method to produce the single necessary translation. Of course, that simply wouldn't work for the French localizer, who needs to inflect the verb differently in each of the above three sentences.

This is the sort of situation where the humdrum chore of language abstraction requires a bit of extra care and attention. Remember to ask yourself whether each noun (or pronoun) can be pluralized. If it can, make sure to pass an appropriate variable to the translator. Of course, you don't need to provide any variant translations in the English resources

mentioned_by_text: "{users} ha risposto."       # Può essere pluralizzato...
mentioned_by_self_text: "{users} hanno risposto." # Può essere pluralizzato...

but it would be a very good idea to add a comment after the translations in question, to alert localizers to the fact that the code will support the addition of such variants, should they be necessary.

Riutilizza le traduzioni, non le chiavi!

If the namespacing keys combine to form a complete specification of where a translation is used, and the ID key specifies exactly how the translation is used and what it says, then it stands to reason that every full translation key must be unique. In other words: you should never use the same key more than once!

Although this may sound inefficient, there's a good reason for doing things this way: it's the easiest way to ensure that localizers will have the flexibility they need. If you reuse keys in your code, you'll eventually hit a snag. Your localizers will be unable to find a single expression that fits every context where you've used some key or other and then they'll start bugging you to fix your code.

Fortunately, you can avoid many such issues if you simply take care to namespace translations correctly, name your ID keys appropriately, and always reuse translations instead of keys. Though it may seem like a bother, in the long run, the standard format will make localization much easier for everyone.