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:
by website content
example: homepage.php, page1.php, page2.php...
by logical domain:
example: auth.php, validation.php, pagination.php...
by html:
example: buttons.php, popup_messages.php, form_data.php...
by straight traslation:
example: simple_words.php, phrases.php... and than contain content like 'password-to-short' => 'your password is to long'
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.
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.
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.
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.
Related
As I've started building a project, there will be quite a few entries in the .po translation file. I use Poedit to build these.
My question is, what is the best practice for entries within this file? I was thinking, instead of referencing entries such as:
echo _('This is an entry.');
I was thinking of organizing them like:
echo _('error_pwd');
echo _('error_user_taken');
Which, once ran through the translation file, would output something like:
Password incorrect. Please try again.
Username is already taken. Please try another.
So, all my translations can be organized by type, such as error_, msg_, status_, tip_, etc.
Has anyone seen it done this way, or have any suggestions on a more organized method?
In fact it doesn't matter!
It's just up to you.
However, I advise you do not split translations in sections.
No there's any benefit in doing so. Actually, the most projects use the one file approach for all msgid entries.
Like django, see.
Of course, If you still want split translation by sections, might you want take a look on Domains:
From PHP doc:
This function (textdomain()) sets the domain to search within when calls are made to
gettext(), usually the named after an application.
Also, as earlier said, the advantage when using msgid as a real phrase ou word (instead underline or dotted notation key) is that it stays as default message if no there's a translation for entry.
And here goes some helpful links:
Django Porject - i18n, Definition
PHP textdomain function
What is bindtextdomain, textdomain in gettext?
How to determine which catalog to be used
This is a standard approach for other framework, e.g. Symfony/Laravel:
trans('error.validation');
But it has a downfall, if you forget to translate one phrase on your site it will appear like the keyword 'error.validation'
I looked into the "text" table in the SQL database and found the fields for the page contents rather complicated. Was trying to use WhatLinksHere but got myself into a bigger mess.
I believe there must be a simple method that I can use, judging from the ReplaceText extension, as well as the Search php files. But those files do really look cryptic to me, since they referenced some other files. I wonder if anyone can help me out on this.
(P/S: I looked into the "pagelinks" table and saw only pl_from. Wonder why there is no pl_to?)
Template transclusions are recorded in the templatelinks table, not in pagelinks.
The format of both tables is the same: the tl_from field contains the page ID of the linking / transcluding page, while the fields tl_namespace and tl_title contain the namespace and normalized (DB key form, i.e. underscores for spaces) title of the target page being transcluded.
For templatelinks, the target namespace will usually be 10 (Template), but this need not always be the case: pages in any namespace can be transcluded using the syntax {{Namespace:Title}} (or just {{:Title}} for pages in the main namespace).
The reason for this asymmetry is that, while the transcluding page must, necessarily, exist, there's no guarantee that the template being transcluded does. Thus, the target page might not have a page ID, and so we need to refer to it using its title (and namespace).
I'm trying to rewrite asp.net mvc application to codeigniter.
Basically codeigniter follow mvc pattern so it's pretty much ok. Now I'm stuck at localization.
I do not want to change url, in order that /Company/About remains the same in english and german. Inside view I had in asp.net Views/Index.cshtml as default for german and Views/Index.en.US.cshtml for english localized page.
I will describe scenario which works perfect on my asp website.
User clicks on country flag
Based on 1. step value cookie is populated with country value
Helper load desired thred into current thread
Views are localized
How can I apply this approach to codeigniter, or similar at least?
Thanks
I think it will be not a good idea to have separate files for each language. You can do it easily using some other techniques, which are easy to implement.
While working on one of my CI project, i need to make it to support multiple languages. As i worked in other multilingual systems like Prestashop, so i borrowed ideas from there and implemented it in my CI project.
I have implemented it as followed:
1) I am storing words in language files. Each language has its single file named as language ISO code, like for english its name is en.php In this language file, words are stored as file_name_md5(of the word) in array like below for Hello World in view file hello.php .
$_lang = array(
'hello_b10a8db164e0754105b7a99be72e3fe5' => 'hallo Welt',
...
...
...
)
The key of the $_lang associative array is the world appended with file name, to be translated, and the value is the translation.
Storing words and fetching the words into / from these language files, are handled by the Translation library I created.
2) All my static text in views files are written in english. I created helper function for it called "l" , small L . Lets say i want Hello world to in my view (say hello.php) and should be translated into multiple languages. So in my view i write it like
<?=$this->l('Hello World...', 'hello')?>
3) Now the l helper function perform small operation on the arguments passed to it. It takes md5 of the world and append it with the file name as you can see above. Then it calls a member function of my Translation library, which looks into the $_lang array to find that match. If it finds the match, it returns the translation. If no translation is found for that word, then the l helper function returns the original text back.
4) I have created my own controller library from which all my controllers are extended. To preserve CI features, my parent controllers are extended from default CI controller. In my parent controller, i load the language files according to the user language. This way the $_lang array is available for the Translation library to look into for the words.
5) In my admin side, i have created a translation system, which reads all my View files for a specific pattern like the below one
<?=$this->l('Hello World...', 'hello')?>
The code generate a form in which a text field is created for each word. The text field name is the same as the $_lang array keys, like filename_md5_of_word . The text field label is the original word in this case "Hello World...". And the translation has to be written to the text field.
On saving, the translations are stored in to specific language file for that particular language selected for translation.
Using this method, you will be able to add as many languages as you like in future, without creating view files for each language, so it is flexible.
I hope i have explained enough so you can take the idea of how easily you can implement translation system, and avoid separate view files for each language.
If you have any questions, feel free to contact me here.
Thank you
I have a site; I need to develop to support multiple languages, for example en, tr, ar, sp, etc.
But the problem is , what is the best way to do it with Codeigniter?
I have a controller ( SITE ). I have a lot of functions LIKE ( hotel , city , page , blog )
I want to before this method add a segment ( language ). This is old links
http://example.com/hotel/mariot
http://example.com/hotel/hilton
http://example.com/city/london
http://example.com/city/paris
...
..
and I want the links to be like this
http://example.com/en/hotel/mariot
http://example.com/ar/hotel/mariot
http://example.com/sp/hotel/mariot
http://example.com/tr/hotel/mariot
http://example.com/en/city/london
http://example.com/ar/city/paris
....
..
sometimes thinking every language have a controller but it is possible...
What is the best way to change all links to support the languages?
I'm sorry If my question is not clear, this is my English.
The right way, is using routes.php look for it inside (application/config/routes.php)
You can use regex expressions for your specific problem.
here is the manual: http://ellislab.com/codeigniter/user-guide/general/routing.html
if you want your links to be like this
http://example.com/en/something
then you might need to have subdomain or folder in your project called en. but yet this is not the perfect solution.
what you have to do is to make your text output assigned into variables which takes their values from an xml file. like if you have some text called "your room number is: 0" and this value is hard coded HTML then you should put it in en.xml file under some tag and get it from the xml file which is requested by the user according to the required lang.
you might can do the previous solution in all languages but you have to consider that Arabic language is RTL language so just consider that in your css. But generally you can use xml files to control the languages.
hope that is what you needed.
i need to translate my site in multiple languages. i was thinking to use a database called language and put the translation there.
database : translation
tables: language
column: id, english, french, german, italian, spanish
or i was thinking about a php solution like:
english.php
french.php
german.php
italian.php
spanish.php
so you simply include the file you need.
now, i can see pros and cons for both, what i want to know is what is consider the standard in the industry to do something like this?
You can use gettext, this function is proposed for this feature, not a "standard" but fast enough.
The second options in the use of a PHP file with a big array (really big, for each string), this is the most common solution.
To the database content (the big problem here, don't forget), if all your content must have the translation, one column for each language, otherwise use a flag of language for each line on database.
There is no industry standard. I have seen (and implemented) solutions using flat files, XML, PHP code, a database, and gettext files to store the localized strings. It's a matter of what is more suitable for you.
My go-to method for PHP is simply files containing arrays of strings, for example
en.php
return array (
'How are you?' => 'How are you?',
'Goodbye' => 'Goodbye',
);
de.php
return array (
'How are you?' => 'Wie gehts?',
'Goodbye' => 'Auf wiedersehen',
);
This can be integrated into an application with reasonable granularity (there can be many such files, e.g. one for each component) and control (you can easily fall back to any other language if you don't find a string) and it is also very convenient to modify without need for special tools.
My favorite PHP framework (Yii) and a giant open source project I have worked on (Moodle) also use this approach.
Noone of the two solutions seems great to me. You should think in the long run when you think a solution.
What if you choose to translate your website in other languages different from those you thought as russian or chinese? In the first case you have to add more and more columns, in the second you've to create more and more file. Another cons is what if you translate a page in italian and spanish but not yet in french?
I think that a good thing is to have a database based solution and a main language. Now you can do something like this:
Create a table 'page' (id, title, ...) where you'll store the page in the main language and where you'll have the info of the translated page too
Create a table 'translation' (idsource, idtranslation, language)
Everytime check the available translations and give those to the users
In database localization you have four main strategies. Each has particular advantages and disadvantages. For the long term I would definitely recommend cloning. You can see the four methods at the link below:
http://www.sisulizer.com/localization/software/server-desktop-database.shtml
There are two main ideas you want to be sure to be implementing. The first, be sure you are integrating some form of translation memory. Your language vendor should be instructing you on how to do this and probably doing it for you.
The second, for each additional language you target, your data will get at least 2x more complex. Keep this in mind as you move forward. Not only your data, but your file sets, management, etc.
Hope that helps. Let me know if you have further questions.
Russell