We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 30023
    • 172 Posts
    I have developed a rough method, including some basic code, for including multiple languages in the CMS. Its currently part-module, part-plugin, and partly involves some changes to the core - and as such I may well submit it for inclusion in either the existing Evolution and/or this project http://forums.modx.com/thread/?thread=74766.

    It adds to, rather than changes, the existing db structure. This is a must, otherwise we break all old sites.

    The key feature is that I have used views - currently only tested in MySQL. If we want to include as an example, French translations, we have a modx_site_content_fr view i.e. which aside from the suffix to the name mimics the existing modx_site_content. Suffixes are all ISO639 two letter codes.

    To make this work invisibly to existing code, I have changed $modx->getFullTablename to take into account the session's language. If the language is, for example, set to French, then for the 'site_content' table it will return modx_site_content_fr instead of modx_site_content.

    Any existing code that bypasses $modx->getFullTablename will receive translations from the primary or default language as a fallback. However I anticipate that most existing code - core and extras - will work fully without any changes.

    Extra languages can be added in the back end via a module, which alters the db by adding extra columns to modx_site_content and modx_tmplvar_contentvalues. The extra columns have ISO639 suffixes e.g. pagetitle_fr. The primary or default language has no suffix for backwards compatability. This however is 'under the hood' and can be ignored by existing code.

    So far I have code for:

    a) A 'Create Language' module, which gives the facility to add or remove languages, and takes care of the db changes required.

    b) A 'Select Language' plugin for the manager, which changes the current language (in both back and front end).

    c) A new $modx->getFullTablename:

    // (TimGS)
    function getFullTableName($tbl, $lang = null) {
     	if (is_null($lang) && ($tbl == 'site_content' || $tbl == 'site_tmplvar_contentvalues')) {
    		$lang = $_SESSION['language'];
    	}
    	if ($lang == $modx->config['manager_lang_attribute']) { // Primary language -> uses standard text fields
    		$lang = null;
    	}
    	return $this->db->config['dbase'] . ".`" . $this->db->config['table_prefix'] . $tbl . ($lang ? '_' . $lang : '') . "`";
    }
    


    (d) Caching of documents requires three changes:

    (1) In document.parser.class.inc.php, change checkCache:

    function checkCache($id) {
            // $cacheFile= "assets/cache/docid_" . $id . ".pageCache.php";
            // Changed by TimGS for translations
            $cacheFile= "assets/cache/docid_" . $id . ($_SESSION['language'] ? '_'.$_SESSION['language'] : '') . ".pageCache.php";
    


    (2) In document.parser.class.inc.php, change postProcess:

        function postProcess() {
            // if the current document was generated, cache it!
            if ($this->documentGenerated == 1 && $this->documentObject['cacheable'] == 1 && $this->documentObject['type'] == 'document' && $this->documentObject['published'] == 1) {
                $basepath= $this->config["base_path"] . "assets/cache";
                // invoke OnBeforeSaveWebPageCache event
                $this->invokeEvent("OnBeforeSaveWebPageCache");
                // if ($fp= @ fopen($basepath . "/docid_" . $this->documentIdentifier . ".pageCache.php", "w")) {
                // Changed by TimGS for translations
                if ($fp= @ fopen($basepath . "/docid_" . $this->documentIdentifier . ($_SESSION['language'] ? '_'.$_SESSION['language'] : '') . ".pageCache.php", "w")) {
    


    (3) In document_data.static.php, line 327

    	$filename = $modx->config['base_path']."assets/cache/docid_".$id. ($_SESSION['language'] ? '_'.$_SESSION['language'] : '') . ".pageCache.php";
    


    I have not yet produced any frontend code to switch languages. However at this stage, for testing, if you are logged on to the backend you can use the select language plugin which changes the language for both back and front ends together.

    This system could be extended to include versioning, but this would need more manager alterations. We would have views such as modx_site_content-fr and modx_site_content-fr-draft.

    Please note that this is very much a work in progress. Do not use on any sites where you value the data! The module alters the db structure, and any bugs could have major consequences. Also note that it is as yet a rather crude UI, without even a confirm dialog box for deleting a language.

    Attached are:

    • A module for creating languages
    • A plugin for OnManagerPageInit to change languages
    • A sample partial db dump for a site with one page, three languages. It only includes the content and template tables so you will need to import it into an existing fresh install.

    File attachments updated 6 May 2012, 22.32 GMT. [ed. note: TimGS last edited this post 11 years, 11 months ago.]
      • 19369
      • 1,098 Posts
      Do you have a unique url for each language in this way? Do you use only one resource for multiple languages?
        • 30023
        • 172 Posts
        Good questions.

        re: resources

        Yes - one resource, multiple translations.

        Changing language, changes the text fields that are used (actually I need to do some more work for TVs - currently all TVs would have 'translations', not just the text TVs), so it looks to a manager user like another resource. However, it is just extra text fields on the same resource.

        Non-text fields e.g. template, menuindex, are not duplicated.

        You are best trying it out on a fresh install and importing my sample site content. That way all should be come clearer.

        re: URLs

        Yes and no (!)

        A session variable holds the current language, so currently a URL does not point to a specific language - it all depends on the session's language. The plus point being that if I give you a URL, then if you are already looking at the site, it will open in 'your' language for your session.

        However many would prefer a URL to go to a specific language. What I have considered and would suggest as an option selected via the Configuration, is that $modx->makeURL is modified so that the language is automatically appended to links e.g. /about-us?language=fr.

        A plugin for the frontend could listen for the language parameter in the URL and switch languages as appropriate.

        -- Tim.

        [ed. note: TimGS last edited this post 11 years, 11 months ago.]
          • 28439
          • 222 Posts
          Don't forget friendly URL's, the language should be part of the document name, for example www.example.com/home-it or www.example.com/home-de

          There is another thing to keep in mind, we need a variable to return the current language in the headers meta tag.

          And there is a need to handle untranslated documents in one language. This should be done through language chains. For example the language of the current visitor is Polish, the original language is Italian.
          The current page is not available in Polish, the page should be delivered in English, if English is not available, the original page in German should be delivered.

          In the manager it should be possible, to have a possibility to work as a translator.

          The idea itself is nice, Tim, and it shows a possible solution.
            Gone away and found a better place to stay
            • 19369
            • 1,098 Posts
            A session variable holds the current language, so currently a URL does not point to a specific language - it all depends on the session's language.

            Is google going to index the website correctly in all languages? I have seen websites without friendly URL indexing only the default one.

            You are best trying it out on a fresh install and importing my sample site content. That way all should be come clearer.

            Ok, I will do it.

            Quote from: Stefanie at May 05, 2012, 10:56 AM
            Don't forget friendly URL's, the language should be part of the document name, for example www.example.com/home-it or www.example.com/home-de

            +1

            Friendly URL should be flexible, usually I use this structure:
            www.example.com/it/home/
            www.example.com/de/home/
            www.example.com/fr/home/
            • Perhaps an examination of how YAMS handles these things would be useful.
                Studying MODX in the desert - http://sottwell.com
                Tips and Tricks from the MODX Forums and Slack Channels - http://modxcookbook.com
                Join the Slack Community - http://modx.org
                • 30023
                • 172 Posts
                A query string parameter is sufficient for Google. Try "violin jobs" and "stellenangebote violine". You should get the violin jobs page at musicalchairs.info in both cases, but in the appropriate language. The former does get 1st place versus the latter's 3rd, but to be fair the latter is only beaten by a German (.de) website.

                Note that the above site uses the query string parameter as a switch only. It does not append the parameter to all URLs - only those linked to by the flags in the top right corner.

                I can also see why someone would want a friendly URL for this.

                I do think it should be switchable though via a configuration option whether the language is to be included in the URL or not, and perhaps even switchable as to whether we have it in the query string or as a friendly URL.

                There is also another option which hasn't been mentioned where multiple languages are displayed on the same page. Currently I haven't got this implemented, but with further modifications to the parser we could have placeholders with language overrides e.g. [+pagetitle+] is the current language but [+pagetitle;es+] is always Spanish.

                I would like to support all of the above options as I can think of jobs I have done that correspond to each option - and I want a CMS that will give me the flexibility to easily do what is requested.

                To a certain extent most of this part of the discussion should be independent of my existing code. Frontend features just need to ensure that $_SESSION['language'] is set correctly.

                -- Tim.
                  • 30023
                  • 172 Posts
                  I have the following suggested configuration options relating to the above, with suggested defaults:

                  1) Include language in URLs? Yes/No (defaults to No as by default there is only one language)

                  2) Include language in URLs as parameter or friendly URL? (defaults to the latter but this only takes effect if FURLs are on anyway)

                  3) URL parameter name (default: language)

                  4) FURL format (default: XX/[+FURL+])

                  Obviously only one of 3 and 4 is ever relevant.

                  These options affect
                  $modx->makeURL
                  FURL decoding which should also set $_SESSION['language']
                    • 19369
                    • 1,098 Posts
                    I like your approach, I have installed the module and plugin and I see the links to switch from one language to another, that's good and really simple to use.

                    I will add some css/html to implement it correctly in the new manager theme.

                    How are you going to handle strings that needs to be translated inside templates/chunks/snippets?
                    What do you think about a placeholder, let's call it "language", and the id of the text after that, for example:
                    [+language:header_Text+]
                    [+language:footer_Text+]
                    


                    And then a module with a table to add/edit/translate each string.
                      • 30023
                      • 172 Posts
                      Quote from: microcipcip at May 05, 2012, 05:16 PM
                      I like your approach, I have installed the module and plugin and I see the links to switch from one language to another, that's good and really simple to use.

                      I will add some css/html to implement it correctly in the new manager theme.

                      Good - I'd rather hoped you'd do that. Do you envisage the code itself still being in the form of a module and plugin?

                      How are you going to handle strings that needs to be translated inside templates/chunks/snippets?

                      Snippets

                      Do you mean snippet-specific text e.g. a search snippet would have 'search results' ?

                      Many snippets have language parameters e.g. Ditto, so a call could be of the form [!Ditto? &language=`[:language:]` ... ... ... !] Note the new placeholder delimiters for [:language:] - as far as I can see such a language placeholder does not correspond to any existing placeholder type. This placeholder probably should be one of the first things replaced by parseDocumentSource().

                      Future extras could just access $_SESSION['language'] directly, or probably more sensibly via a new property e.g. $modx->language.

                      This way, If a prevnextjump snippet had a placeholder [+next+] then those placeholders can remain as they are, and the snippet justs replaces them with the correct text as according to the language.

                      Chunks and templates

                      If I have some non-content managed text, I'd prefer not to have to jump between template/chunk and a separate editing table. Ideally then, I'd like to have something like:

                      [:en|Good Day|fr|Bonjour|de|Guten Tag:]

                      This may get a bit unwieldy if you have lots of languages, in which case your suggestion becomes more practical. I'm inclined to suggest both are implemented, and subject to any other comments and suggestions may well do that as the next step.

                      -- Tim.