Home » Php » php – Structuring Website Translation files

php – Structuring Website Translation files

Posted by: admin July 12, 2020 Leave a comment

Questions:

I faced this problem several times while building websites.
I will explain the using PHP and Laravel as an example but this problem is a common amoung multiple platforms.
This was already addressed in a few questions (post1, post2,post3, post4 and some others) but the posts didn’t really get a good answer.

The question is: What is the best way of structuring translated content inside of language files?

I’m currently using Laravel (I’m not mentioning the version because both Laravel 4 and Laravel 5 have similar localisation functionalities, at least similar enough for the purpouses of this topic).

The localisation structures the content accross language files (en, es,de, fr…) inside which there can be multiple .php files that contain a return statement that returns a multi-level dictionary structure.

/lang
    /en
        messages.php
    /es
        messages.php

and the files contain something like this:

<?php    
return [

    'example1' => 'example message for value exaple-key',
    'example2' => [
        'sub-example' => 'example message for example1.sub.example',
    ],    
];

and calling of this is done by doing something like this:

//Laravel 5    
trans('messages.example1'); //outputs 'example message for value exaple-key'
trans('messages.example2.sub-example'); //outputs 'example message for example1.sub.example'

//Laravel 4   
Lang::get('messages.example1'); //outputs 'example message for value exaple-key'
Lang::get('messages.example2.sub-example'); //outputs 'example message for example1.sub.example'

A few methods of grouping come to mind:

  1. by website content

    example: homepage.php, page1.php, page2.php...

  2. by logical domain:

    example: auth.php, validation.php, pagination.php...

  3. by html:

    example: buttons.php, popup_messages.php, form_data.php...

  4. by straight traslation:

    example: simple_words.php, phrases.php... and than contain content like 'password-to-short' => 'your password is to long'

  5. Some hybrid/combination of the ones mentioned before

All of these have some obvious benefits and drawbacks and I won’t try to go int that but the 5th option is most likely the best solution but there’s still the problem of where to draw the line to get minimal duplication of phrases and content.

Annother problem is how to solve the problem of uppercase first characters in some cases and lowercase in other cases as well as punctuation characters at the ends.

I did reaserch regarding this problem but there are no definitive guidelines and/or good examples available to learn from.

All opinions are welcome.

How to&Answers:

I tend to group functionality in my Laravel apps into self-contained ‘components’. For example, I’ve been working on email campaign functionality for an application recently so put the service provider class, models, service classes in a folder at app/Email.

Bearing this in mind, I organise my translations in a similar fashion. So even though on this project we’re not translating strings, if we were I would create a resources/assets/lang/en/email.php file, and put translated strings for the email component in there.

So in another project, my directory structure might look like this:

  • /resources
    • /lang
      • /en
        • auth.php
        • email.php
        • events.php
        • news.php
        • pagination.php
        • passwords.php
        • validation.php

Hope this helps.

Answer:

In my experience there is no reason to have different groups other than trying to use your translations somewhere else. I usually put all my project messages in a group named app and for each of my shared libraries I use a separate group name (because I might use them in other projects).
An example of a a failure login message in my website would be

trans('app.username_and_password_do_not_match')

and if it’s in a third party library named Auth it would be

trans('auth.username_and_password_do_not_match')

And remember to write the full message as your message key instead of using short names (like app.login.fail). this way you don’t need to check the website content for every translation.

I didn’t fully understand your last problem so you might want to clarify it a bit.

Answer:

I would go with option #4, so you’d have something like this:

/lang/
    /en 
      messages.php
      words.php
    /fr
      message.php
      words.php
    /de
      messages.php
      words.php

This does a few things:

  • It segments out everything very clearly. You know which language to find where. And you know what’s in the file associated with the language.
  • The above makes maintenance easier in the future because you can find stuff.
  • It gives you files, by language, that can be translated separately.
  • It puts all the message in one clearly defined place.

One thing to note, is that if your app gets REALLY big and REALLY international, you may want to use ISO language codes instead. For example, european Portugese (pt_PT) and Brazilian Portugese are different and with a global audience you’d probably want to cover both.