Photo by Leonardo Toshiro Okubo on Unsplash
Profile picture for user eirik
Skrevet av
Eirik S. Morland
Publisert
31. august 2020

Utrulling av oversettelser i Drupal

En av mange flotte ting med Drupal 8 (og Drupal 9) er støtten for flerspråklighet. Du kan oversette hva som helst, så det å lage en side som er "helnorsk" er noe Drupal støtter ut av boksen.

Hvis du laster ned Drupal så kan du få stort sett hele grensesnittet oversatt til norsk med et par klikk, siden oversetting er en dugnadsjobb. I praksis betyr dette at de fleste tekstene som både vi og våre brukere ser i løpet av en arbeidshverdag allerede er oversatt. Enten av oss, eller noen andre i fellesskapet. Her vil jeg spesielt trekke fram svenryen, som nesten på egen hånd har gått gjennom alle tekstene i Drupal 8 kjernen.

I dag skal vi snakke om en annen interessant problemstilling, og om hvordan vi løser den med Drupal. Nemlig hvordan vi kan rulle ut ny funksjonalitet som inneholder oversettelser.

I Ny Media utvikler vi skreddersydde løsninger for våre kunder. Med det sørger vi for at både jobben og forretningsmodellen blir enklere og mer lønnsom. For å oppnå dette ender vi ofte opp med å skrive kode som er enten tilpasset en spesifikk kunde, eller funksjonalitet som vi selv kan bruke på flere prosjekter.

Oversetting av Drupal er en dugnadsjobb. Men helt nye tekststrenger som vi nettopp har laget i kode som vi selv har skrevet er ikke noe vi kan regne med at fellesskapet skal oversette for oss. Så da må vi gjøre det selv. Utfordringen her ligger i hvordan vi kan få tekststrengene oversatt på produksjonssiden, når tekstene bare fins på dette spesifikke prosjektet. La oss se på et par teoretiske løsninger, og deretter på løsningen vi bruker. Tilfeldigvis er denne løsningen den vi selv synes er best, og den vil vi nå dele med dere!

La oss si at vi utvikler en løsning der vi skal vise fram noe informasjon om opphavsrett på alle sider, og at dette må være oversatt. La oss si at vi kaller denne nye modulen for "copyright_info". Og la oss si at koden i denne modulen ser noe sånn ut:

/**
* Implements hook_preprocess_HOOK().
*/
function copyright_info_preprocess_page(&$variables) {
 $variables["page"]["content"][] = [
   '#markup' => t('Thank you for visiting this site, and we hope you like the content. However it is copyrighted so please do not steal it.'),
 ];
}

På hver side vil nå hele grensesnitter være oversatt til norsk. Bortsett fra den helt nye delen som omhandler opphavsrett, siden vi akkurat laget dette selv.

Screenshot from translated frontpage. Note the untranslated custom string.
Skjermbilde fra en oversatt forside. Legg merke til den uoversatte egendefinerte teksten.

Alternativ 1: Oversette "for hånd" når man har rullet ut den nye funksjonaliteten

Dette er den enkleste og mest åpenbare måten å gjøre det på. Etter du har rullet ut den nye funksjonaliteten går du inn i adminstrasjonsgrensesnittet for oversettelser på siden din. Dette finner du under Administrasjon -> Konfigurasjon -> Regionalt og språk -> Oversett brukergrensesnittet eller på adressen admin/config/regional/translate. So da søker vi opp tekststrengen(e) vi akkurat har laget, og så kan vi oversette dem, en etter en.

String translation

Denne løsningen er både transparent og enkel. Og det har sine fordeler:

  • Krever ingen byggesteg på produksjonssiden for å importere oversettelser.
  • Krever ingen ekstra moduler man må skru på.

På den andre siden har det noen ulemper:

  • Det er tidkrevende, spesielt om man har mer enn en tekststreng som må oversettes
  • Det er fort gjort å gjøre feil (feil ved kopier/lim-inn eller skrivefeil)
  • Man ender opp med å ha en produksjonsside som er midlertidig uoversatt mens man manuelt redigerer oversettelsene

I eksempler ovenfor kan dette være en OK løsning, siden vi bare har den ene tekststrengen. Men med en gang man får flere enn én tekststreng man skal oversette så vil man virkelig ikke gjøre dette for hånd. I tillegg, om dette er en side med høy traffikk, så vil man ikke at siden midlertidig skal framstå som uoversatt mens du arbeider manuelt.

Alternativ 2: Eksportere oversettelser på en test/staging side, og importere på produksjonssiden

En annen løsning som er tilgjengelig ut av boksen er å eksportere alle oversatte tekststrenger du har på en side, for så å importere den på en annen side (for eksempel produksjonssiden).

Export strings from development or staging site
Først kan du eksportere og laste ned tekststrengene på en side der de nye tekststrengene er oversatt (f.eks lokalt eller på en staging side)
Import on live site
Deretter laster du opp, og importer, tekststrengene på produksjonssiden.

Dette er også ganske enkelt, så det har liknende fordeler:

  • Det trengs ingen byggesteg for å importere oversettelser
  • Det trengs ingen ekstra moduler
  • Det støtter importering av store mengder tekst

Det har riktignok også noen ulemper:

  • Fremdeles er det manuelt arbeid, og det kan gjøre at nettsiden din midlertidig framstår uten oversettelser
  • Krever at man manuelt importerer tekster. Altså kan man ikke gjøre automatisk utrulling.
  • Man har ikke versjonskontrollert oversettelsene sine

Alternativ 3: Importere oversettelesr som en del av byggeprosessen.

Som du sikkert har skjønt så er dette alternativet jeg ønsker å framheve i denne bloggposten, og det er alternativet vi bruker i Ny Media. For å oppnå dette bruker vi en Drupal modul som heter  Custom translation deployments. Dette er en modul vi utviklet som en del av et prosjekt for en av våre flerspråklige kunder, som så endte opp med å bli vårt standard oppsett for å rulle ut oversettelser på våre prosjekt.

Modulen gir deg to måter man kan enkelt rulle ut oversettelser. Vi skal se på den enkleste her, og så kort nevne den litt mer avanserte måten.

Første steg i å rulle ut oversettelser er å sørge for at oversettelsene er lagt til i ditt versjonskontrollsystem. En standard Drupal installasjon setter mappen for oversettelser til å være sites/default/files/translations. Dette er typisk en mappe man ignorer i versjonskontrollsystemet. Så vi starter med å endre dette til å være et sted vi kan sjekke inn i versjonskontrollen. For eksempel ../translations. For å endre dette går vi til siden for "Filsystem" som du finner under Administrasjon -> Konfigurasjon -> Media, eller på stien admin/config/media/file-system.

File settings
Siden dette prosjektet har sin rot et nivå over Drupal installasjonen, plasserer vi oversettelsene i en mappe i rota av prosjektet.

Her i Norge er vi som oftest interessert i norske oversettelesr for våre norske kunder. Modulen Custom translation deployments har et predefinert filmønster definert. Med det mener jeg at hvis vi plasserer en fil som heter project_specifc-custom.LANGUAGE.po (eller i vårt tilfelle med norsk som språk: project_specifc-custom.nb.po) i mappa vi nettopp definerte og opprettet. La oss prøve dette!

Først, la os sørge for at fila ligger der den skal:

$ ls ../translations
project_specific-custom.nb.po

Nå kan man enten bruke grensesnittet (under Administrasjon -> Rapporter -> Tilgjengelige oppdateringer for oversettelser - admin/reports/translations), eller man kan gjøre dette med drush.

Den andre hendige tingen man kan gjøre er nå å legge til import av oversettelser i byggescriptet ditt. Kanskje har du noen form for Continuous Deployment verktøy for dette, eller kanskje du kjører byggesteg manuelt på serveren din. Uansett hvor du befinner deg i spekteret så kan du alltids gjøre noe sånn som dette:

$ drush sdel locale.translation_last_checked && drush locale-update && drush cr
>  [notice] Translation file not found: http://ftp.drupal.org/files/translations/8.x/project_specific/project_specific-custom.nb.po.
>  [notice] Checked nb translation for project_specific.
>  [notice] Imported nb translation for project_specific.
>  [notice] Translations imported: 1 added, 0 updated, 0 removed.
>  [notice] Message: En oversettelsesfil importert. /1/ oversettelser ble lagt til, /0/ 
> oversettelser ble oppdatert og /0/ oversettelser ble fjernet.

Dette er faktisk 3 kommandoer. Den første sørger for at Drush vet at det er på tide å oppdatere oversettelser. Den andre oppdaterer oversettelsene, og den tredje tømmer mellomlagre. Det tredje steget er viktig om du har oversettelser som brukes i JavaScript.

Men det er også mulig å importere disse oversettelsene fra grensesnittet. Det ser ut sånn ca som dette:

Interface for importing a local file

En annen ting man kan merke seg er at siden Drupal vil nå behandle "project_specific" som et prosjekt, så kan du faktisk også ha en fil for oversettelser på en server, og Drupal vil sjekke der etter oppdateringer til den. Som du ser fra output fra Drush kommandoen ovenfor så vil Drupal nå lete etter en slik fil med et spesifikt mønster. Dette mønsteret er definert som en del av hook implementasjonen for custom_translation_deployments. Så om du vil ha en oversettelsesfil for din organisasjon, så kan du ha en egenutviklet modul som implementerer denne hooken, og derfor også gjøre oversettelser tilgjengelig for nedlasting og oppdatering automatisk. Her er et eksempel på dette:

/**
 * Implements hook_custom_translation_deployments_files().
 */
function my_org_custom_translation_deployments_files() {
  $items = [];
  $items[] = [
    'name' => 'my_org',
    'project_type' => 'module',
    'core' => '8.x',
    // We set the version to something static, but not to "dev".
    'version' => 'custom',
    'server_pattern' => 'http://my_org.com/files/translations/%core/%project/%project-%version.%language.po',
    'status' => 1,
  ];
  return $items;
}

På denne måten kan vi både rulle ut oversettelser i en fil kalt my_org-custom.nb.po eller vi kan ha en fil tilgjengelig på  http://my_org.com/files/translations/8.x/my_org/my_org-custom.nb.po.

Som en bonus vil jeg også anbefale å endre innstillinger for oppdatering av oversettelser til å bare lete på det lokale filsystemet på produksjonsserveren. Og i tillegg kun lete etter oversettelser manuelt (siden vi nå gjør det manuelt som en del av byggestegene). På den måten vil Drupal aldri prøve å laste ned nye oversettelser på produksjonssiden din, som igjen kan lage konflikter med versjonskontrollerte oversettelser. Innstillingen for dette er på Administrasjon -> Konfigurasjon -> Regionalt og språk -> Oversett brukergrensesnittet -> Innstillinger for grensesnittsoversettelse, eller på stien  admin/config/regional/translate/settings.

Admin settings for translations

Du kan også gjøre dete som en del av innstillingene på produksjonssiden, og i stedet ha denne innstillingen aktivert for utviklingssider. For å gjøre dette i settings.php så legger du til noe som dette:

$config['locale.settings']['translation']['use_source'] = 'local';

Fleksibel utrulling av oversettelse

Uansett hvor avansert du har lagt opp til utrulling og oversetting så har Drupal en måte du kan håndtere dette på. Og når det ikke er tilstrekkelig med verktøy ut av boksen, så kan du bruke moduler som  Custom translation deployments for å hjelpe deg de siste stegene som trengs. Modulen har full testdekning og er brukt på mange produksjonssider. Den støtter også Drupal 9 ut av boksen!

Om du ser etter en partner for å utvikle din flerspråklige nettside, er det bare å ta kontakt med Ny Media.