Jump to content

Translating administration – language question for all users


Adam Kiss
 Share

Recommended Posts

Welcome to the forums Diogo! Thank you for your post and offer to help with Portuguese translation. I think we will be able to take you up on your offer this summer, so hope to talk to you more about this soon. That's a good point about European vs Brazilian Portuguese. It sounds like we will eventually need both as separate translations, so we will keep an eye out for this. My impression is that the majority of PW users are in Europe at present. If that's true, European-based languages will no doubt get covered before others.

Link to comment
Share on other sites

  • 1 month later...

Hi there. I recently checked out Processwire and like it alot.

I also wanted to come here and see what is planned for the support of multilanguage. Nice to see it's already considered.

Also would like to offer my help for this. I could translate to german if needed.

I think the most efficient way would be to have some sort of tanslation files (php, xml) that would make add other langauges easy.

Thanks for creating this awesome product! Keep up the good work.

Link to comment
Share on other sites

Soma, welcome to forums! There is currently 2.1 in underway, plus some other PW stuff we're working on, but once we release the 2.1 (by the end of the summer, august maybe?) we're going to focus on multilinguality, both of content and of administration, so that's when we'll contact all the people that posted in this topic, and we'll try to release at least a few languages (for administration) together with 2.2 (I see this one released maybe by the end of the year or later)

Link to comment
Share on other sites

  • 5 weeks later...

Hello everybody!

First i want to say how much i am impressed about PW - i have spent the last few days trying out a lot of CMS (like i do several times a year) and PW looks very promising.

I like its "full featured simplicity" - lots of possibilities which are hidden in a simple tree menu. And the fact that everything is a custom field in this system - the feature for which i was looking for since a long time.

Thank you for that great CMS, Ryan!

It would be great if you could find a good possibility for the localization of the backend as soon as possible - if you need somebody for the german translation - just tell me.

I am really looking forward to use this system in the future and hope that the PW community will grow and help PW getting better and better!

Kind regards,

Christian

Link to comment
Share on other sites

Christian– Welcome to the forums and thanks for your post. Glad that you like PW so far. Once 2.1 full release is done, multi language support is next on the to-do list here, and it's the main drive of version 2.2. We certainly welcome any help with translation and testing–thank you for your offer.

Link to comment
Share on other sites

Hello Ryan - that sounds fantastic!  I have actually two current projects which i would like to realize with PW - no other CMS fits the requirements as good as PW does. I hope that i can convince the clients that an english backend will do the job for the moment too - PWs backend is so straightforward and simple that i think that even somebody who knows only few words in english could work with it...

And maybe I can try to find the important impressions in the sourcecode and change it there for know - if you could give me a hint where i have to search would be great.  ;)

Kind regards,

Christian

Link to comment
Share on other sites

I don't recommend changing words directly in the source code, just because that will make it difficult for you to perform upgrades... you'd have to redo your work on every upgrade. A better temporary solution is to build a module that hooks into Page::render, and then just perform a search/replace on all the words you want to translate in the admin. This is relatively easy to do, and I'll be happy to get you started with it if it's of interest. The actual search/replace works like this:

<?php

$translate = array(
    'Milk' => 'Leche', 
    'Beer' => 'Cerveza', 
    'Bread' => 'Pan'
    ); 

$out = str_replace(array_keys($translate), array_values($translate), $out); 
Link to comment
Share on other sites

Hello Ryan,

thanks for your answer!

that will make it difficult for you to perform upgrades... you'd have to redo your work on every upgrade

Yes, i knew this and it would be great if you could get me started with replacing words with search/replace in PW. How could we do this?

Seems that localization of PW in general will be something more complicated because a lot of expressions are used by the system with Jquery, or am i false?

Kind regards,

Christian

Link to comment
Share on other sites

Here is a starting point for you. You'd want to paste this into a file called LanguageTranslator.module and place in your /site/modules/ directory. Then go to the modules tab in the admin, and click "check for new modules" and the click "install" for the Language Translator module.

<?php
class LanguageTranslator extends WireData implements Module {

       public static function getModuleInfo() {
               return array(
                       'title' => 'Language Translator',
                       'summary' => 'Example of translating languages',
                       'version' => 100,
                       'permanent' => false,
                       'autoload' => true,
                       'singular' => true,
                       );
       }

       public function init() {
               $this->addHookAfter('Page::render', $this, 'render');
       }

       public function render(HookEvent $event) {

               $page = $event->object;
               $out = $event->return;

               // only operate on admin pages
               if($page->template != 'admin') return;

	$translate = array(
		// place your translations here, in this format (case sensitive)
		'Milk' => 'Leche', 
		'Beer' => 'Cerveza', 
		'Bread' => 'Pan'
		); 

	$out = str_replace(array_keys($translate), array_values($translate), $out); 

               $event->return = $out;
       }
}

You are right about some words being in jQuery, but there aren't a lot so I don't expect it'll be an issue. At first, we'll be focusing on the pages list and editor for language translation. The other parts of the CMS (Modules, Fields, Templates, Access) are superuser-only functions, and thus more applicable to developers than clients.

Link to comment
Share on other sites

Thank you very much for this! I will check how i can work with it.

You are right about some words being in jQuery, but there aren't a lot so I don't expect it'll be an issue.

When i changed the very first words in the core last night ("edit", "new", "view", "move") in ProcessPageList.module i recognized that if i change "move" to another word it will not work anymore - so i guessed that "Move" is used in another place, probably a javascript.

---

The module works like a breeze ;-) - it's much more than a starting point - thanks for that again!

As expected the problem which i described before resists - "Move" is used somewhere else - when i translate it moving pages will not work anymore - but hopefully this arrives only i a few cases like you said.

---

Guess there will be a few things that have to be changed:

"Edit" seems to work - although i get the following errors in the console :

ProcessPageBearbeiten.css and ProcessPageBearbeiten.js not found

"Bearbeiten" => "Edit" :-) - lets look further into it...

[Edit by Adam]: Glued three of your posts together. Welcome to the forums and please, use modify function if you want to say more than you said in your original post :)

Link to comment
Share on other sites

The 'Move' and 'Edit' issue are likely the same thing. Because those terms appear elsewhere in other contexts where it shouldn't be changed, you have to adjust your string to ensure you are only targeting the right version. For instance, with 'Move' and 'Edit', you may want to change them to be '>Move<', and '>Edit<' so that you are only replacing those strings when they appear in a markup tag. You may need to take this approach with most terms. Make them as specific as possible just to ensure you are only replacing the things you want, and nothing that you don't.

Link to comment
Share on other sites

For instance, with 'Move' and 'Edit', you may want to change them to be '>Move<', and '>Edit<'

Yes, i did it like that and in most cases there where no problems, i had to make specific terms and it worked fine.

In the case of "Move", "Edit" and "New" it was strange: it did not work - is this maybe because the HTML is generated by a javscript?

I tried:

		'>View<' => '>Anschauen<',
		'>Move<' => '>Bewegen<',

but nothing changed then...

Then i had a view at str_replace and couldnt find a solution - i thought it was a problem with the "><"... But when i tested changing some other HTML code with the modul it worked fine.

No idea why it doenst work in those cases - just maybe the javascript thingy.

Link to comment
Share on other sites

You are right it is generated by javascript, I wasn't thinking about that. But it's delivered to Javascript by ProcessWire in JSON format, and that JSON should still pass through Page::render. So in this case, if you set your replacements like "Edit" and "Move" – including the double quotes, I bet that will work. Let me know?

Link to comment
Share on other sites

Just in case you need it more specific, here's an example of the JSON output (pulled from Firebug). I underlined the Edit, Move, View, and New, so that you can more easily see what's around it.

{"page":{"id":2,"label":"Admin","status":1039,"numChildren":6,"path":"\/processwire\/","actions":[{"name":"Edit","url":"\/celist\/processwire\/page\/edit\/?id=2"},{"name":"View","url":"http:\/\/localhost:8888\/celist\/processwire\/"},{"name":"New","url":"\/celist\/processwire\/page\/add\/?parent_id=2"},{"name":"Move","url":"#"}],"addClass":"PageListAccessOff","type":"System"},"children":[{"id":3,"label":"Pages","status":21,"numChildren":8,"path":"\/processwire\/page\/","actions":[{"name":"Edit","url":"\/celist\/processwire\/page\/edit\/?id=3"},{"name":"View","url":"http:\/\/localhost:8888\/celist\/processwire\/page\/"},{"name":"New","url":"\/celist\/processwire\/page\/add\/?parent_id=3"},{"name":"Move","url":"#"}]},{"id":22,"label":"Setup","status":21,"numChildren":3,"path":"\/processwire\/setup\/","actions":

... and so on...pretty isn't it? :)

In your case, you may want to target strings like: "name":"Edit"

Link to comment
Share on other sites

Back again...

So i it and this code works:

'"name":"Edit"' => '"name":"Bearbeiten"',

works fine - just the menuitems are changed and the links to the files which include "Edit" in the filename stay intact.

In case of "Move" its dfferent - i huess i have to work out how the class, which is necessary for the move action, can be added...

---

Right now i saw that you have changed your previous post and suggested exact the same codefragment which i took - but as i said: for "Move" i have to add the class somehow.

Not so easy with JSON - i have no experience with that - but really great that you find time to help me. Thanks a lot!

---

So almost everything which is important for the moment is translated now - just a few notices "success-messages and error-messages" have to be edited.

If there is a possibility to solve that "Move" problem would be nice - if not, i have to teach my clients what means "Move" ;-) - but i did not expect that there would be just a quick workaround so i am very happy right now!

---

Ok, so i sorted this out:

Even if i use the JSON code fragments in the LanguageTranslator.module, there are still some classes added which use the new word which was generated with str_replace.

<li class="PageListActionBearbeiten">   (prev. PageListActionEdit)

<li class="PageListActionAnschauen">   (prev. PageListActionView)

<li class="PageListActionNeu">    (prev. PageListActionNew)

<li class="PageListActionBewegen">     (prev. PageListActionMove)

In case of "Edit", "View" and "New" this class seems just to be added but is not used later for styling or with jQuery, in case of "Move" it is used in ProcessPageList.js:

$("a.PageListPage", $ul).click(clickChild); 
$(".PageListActionMove a", $ul).click(clickMove); 
$(".PageListActionSelect a", $ul).click(clickSelect); 
$(".PageListTriggerOpen a.PageListPage", $ul).click();

So for this moment i just have to change this one little thing in the core ("PageListActionMove" to "PageListActionBewegen") - not too much work to change this again after an update, i guess. Although of course i would like to avoid changing something in the core - but to manage that thing with the "Move" trigger i guess there is no way to avoid this...

If this can be solved via hook - please tell me.

So for the moment i have something like a localized PW which i can use for my clients' sites - and i am looking forward to see how PW will get a localization in future releases - will be littly tricky i guess, because one have to take care about JSON. But i am sure you will do a great job!

[Edited by Adam] I glued four of your posts together

Link to comment
Share on other sites

I see what you mean about those class names.  I had forgotten those class names were generated dynamically from the text labels. We will need to change that for future localization, so I went ahead and changed it now. If you grab the latest commit, it now keeps the label used for generating the class name in a separate field in the JSON so that you can safely change the 'name' one on the fly.

Link to comment
Share on other sites

Yes, works fantastic! Great!

I dont know if the same "problem" appears in the "Edit page" "Wire Tabs" - i couldnt get the JSON output for that part with Firebug and so i couldnt change those expressions in the same way with:

'"name":"Content"' => '"name":"Inhalt"',

If you could provide me the JSON output i will try and let you know if there has to be changed something too.

---

I had a deeper look and now i am not sure if this part is generated with JSON but the Wire Tabs seem to be generated via jQuery after "Page::render" - so str_replace does not hook into the code... not sure if i am right.

---

For now i have found a - not very elegant - way to solve this problem - I have changed the path and id again with str_replace to the original expressions:

'ProcessPageEditUnterseiten' => 'ProcessPageEditChildren'

So if its not important for future translation you dont have to dig into the code - for me it works fine for the moment.

Link to comment
Share on other sites

Those tabs are being generated by javascript from the existing markup. The tab label appears in the 'title' attribute of markup like this:

<li class='InputfieldWrapper ui-widget' id='ProcessPageEditContent' title='Content'>

As a result, I would maybe suggest a search:

id='ProcessPageEditContent' title='Content'

Replace with:

id='ProcessPageEditContent' title='Inhalt' 
Link to comment
Share on other sites

Yes, that works fine - if one add the backslashes, just in one case it didn't:

'id=\'ProcessPageEditChildren\' title=\'Children\'' => 'id=\'ProcessPageEditChildren\' title=\'Unterseiten\'',

I guess it has something to do with the fact that - i dont't know why - the title "Children" is wrapped in <em></em>. I have tried to add this to the code above but i couldn't get it work.

Link to comment
Share on other sites

That em is to add emphasis to the children tab as a way to say "this page has children". The stylesheet gives a faint underline to provide that emphasis. So the search/replace would probably need to look for both versions... Emphasized and not emphasized (or use a regexp with preg_replace).

Link to comment
Share on other sites

  • 4 weeks later...

Thanks, Ryan! It's really cool how easy things can be done in PW!

I decided to translate backend as you described here. Everything works fine, but how do I translate the default text in the search field? I tried to search using the string from the page source, but had no luck.

Link to comment
Share on other sites

The 'Search' label is actually in this file:

/wire/modules/Process/ProcessPageSearch/ProcessPageSearch.js

this line, near the bottom of the file:

var label = 'Search';

I'll be starting up the support for multi-language here very soon, so hard-coded labels like this will be a thing of a past in the near future.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...