Drupal - Build a Mobile App Game to Learn Words from Another Language

Category:

In this tutorial we'll explore how to make a simple mobile application game with DrupalGap for a Drupal 7 website. Our game will help us learn words in another langauge.

We'll use Drupal to manage our words and their translations. Since Drupal comes with a default content type called Article, we'll use that for our words.

1. Download and Install Drupal (in English)

2. Enable Required Core Modules (included in Drupal Core)

  • Locale
  • Content translation

3. Enable Required Contrib Modules

4. Add Language

  • Administration -> Configuration -> Regional and language
  • admin/config/regional/language

For my game, I want to learn Vietnamese words. However, choose whichever language you'd like to learn words for, then click the 'Add language' button.

  • Administration -> Configuration -> Regional and language -> Languages
  • admin/config/regional/language/add

5. Enable URL Detection and Selection

  • Administration -> Configuration -> Regional and language -> Languages -> Detection and Selection
  • admin/config/regional/language/configure

Under 'Content language detection', check the 'Enabled' checkbox next to the URL detection method:

Please note, the screen shot above does NOT have the checkbox checked, but you must CHECK the box, before hitting 'Save settings'.

6. Make Article Node Titles Translatable

  • Administration -> Structure -> Content types -> Article -> Manage Fields
  • admin/structure/types/manage/article/fields

Click the 'replace' link under the 'Operations' column for the 'Title' field. Then check the 'Replace title with a field instance' checkbox and click the 'Save settings' button.

Please note, the screen shot above does NOT have the checkbox checked, but you must CHECK the box, before hitting 'Save settings'.

7. Make Article Nodes Translatable

  • Administration -> Structure -> Content types -> Article
  • admin/structure/types/manage/article

Go to 'Publishing options' and select the 'Enabled, with field translation' radio button, then hit the 'Save content type' button.

8. Create Word to Translate

  • Content -> Add content
  • node/add/article

It seems natural that our first word to learn would be "Hello", so let's enter that into the Title field on the Create Article Node form:

We'll skip all the other fields for now (tags, body, image, language, etc), then go ahead and save your new node.

9. Translate Word

Click the 'Translate' tab when viewing your newly created node.

Click the 'add' link under the 'Operations' column to add a translation for your secondary language. Then add the translation for "Hello" in the title field, then click the 'Save' button.

For this example, the word "Hello" in Vietnamese is "Xin chào". Where did I get the translation? Good question. My wife is Vietnamese. Also, my daughter is 10 months old (at the time of writing this), so I need to get prepared for any multi lingual back talk :) If you don't have your own in-house translator, try Google Translate.

10. View Translated Word

To view the translated word, we navigate to the node, then insert the language code at the front of the path, for example:

Review step #5 to see the language detection and selection settings that make the above translated link possible.

11. Create a View to Return a Random Word (Article)

Our mobile application will need to be able to consume JSON data from our Drupal site. Let's create a new view.

  • admin/structure/views/add

On the 'Add new view' form, enter values like this:

  • View name: Random Word
  • Show 'Content' of type 'Article' sorted by 'Unsorted'
  • Check the 'Create a page' checkbox
  • Path: random-word
  • Display format: 'JSON data document'
  • Items to display: 1
  • Uncheck the 'Use a pager' checkbox

Then click the 'Continue & edit' button.

Sort Criteria

Add some 'Sort Criteria' to return a randomly selected word (article), even though we only have 1 right now. To do this, select 'Global' from the 'Filter' drop down menu, then check the box next to 'Global: Random' and then click the 'Apply (all displays)' button.

Fields

Add a Node ID field to your view. To do this, click the 'Add' button next to 'Fields', type 'nid' into the 'Search' text box, select 'Content: Nid' when it shows up in the search results list, then click the 'Apply (all displays)' button. On the next screen, change the label from 'Nid' to 'nid', then click the 'Apply (all displays)' button.

Add the translated title field to your view. To do this, click the 'Add' button next to 'Fields', type 'title' into the 'Search' text box, select 'Content: Title - Appears in node:article', then click the 'Apply (all displays)' button. On the next screen, change the label to 'title_translated', then click the 'Apply (all displays)' button.

Format (important step)

Click the 'Settings' link next to 'JSON data document' under 'Format', uncheck the 'Views API mode' checkbox and then click the 'Apply (all displays)' button.

Preview View Results in JSON

Now when we preview the results of our view, we should see something like this:

{
  "nodes" : [
    {
      "node" : {
        "title" : "Hello",
        "nid" : "1",
        "title_translated" : "Xin chào"
      }
    }
  ]
}

Save the View

Our view is ready to go, click the 'Save' button to save the view.

12. Complete the DrupalGap Hello World

Now we're ready to start building the mobile application. The easiest way to get started is to complete the Hello World for the DrupalGap mobile application development kit.

Please be patient with this step, if you've never set up a mobile application development environment, it will take some time to get started. But once you're done, you'll be ready to rock, harder than ever before.

For this example application, I installed my Drupal 7 website so it would be available here:

Once we are up and running, and have set the 'site_path' in our settings.js file, our mobile app should look something like this:

13. Create a Custom DrupalGap Module

Next up, we'll need a custom module in DrupalGap to build our game. We'll create a module called 'wordgame':

  • www/app/modules/custom/wordgame/wordgame.js

Then we'll tell our settings.js file about the custom module:

/* Custom Modules */
Drupal.modules.custom['wordgame'] = {};

Complete details on creating a custom module for DrupalGap

14. Create a Custom Page in the Mobile App to Play the Game

Just like Drupal, we will use hook_menu() in our DrupalGap module to create a custom page.

/**
 * Implements hook_menu().
 */
function wordgame_menu() {
  try {
    var items = {
      play: {
        title: 'Play Game',
        page_callback: 'wordgame_play'
      }
    };
    return items;
  }
  catch (error) { drupalgap_error(error); }
}

/**
 * Page call back function for play page.
 */
function wordgame_play() {
  try {
    return 'It is time to play the game!';
  }
  catch (error) { drupalgap_error(error); }
}

Now if we set our App's front page to our newly created page, we'll see the new page. To do this, set the 'front' variable in settings.js to the 'play' page. Here is what our page will look like when our App loads:

15. Build the Game

Our game will be pretty simple, it will grab the JSON for a random word (and its translation) from our Drupal website. Once we have the random word JSON object, we will display the translated word and provide a text field for the player to enter the English translation of the word. We'll provide buttons to let the player submit their answer, see the answer (if they don't know the answer), and to retrieve another word. Pretty basic, let's go!

var wordgame_answer = ''; // Holds the current answer.

/**
 * Implements hook_menu().
 */
function wordgame_menu() {
  var items = {
    play:{
      title:'Play Game',
      page_callback:'wordgame_play',
      pageshow:'wordgame_play_pageshow'
    }
  };
  return items;
}

/**
 * The page call back function for the play page.
 */
function wordgame_play() {
  var content = {
    /* Load word button */
    new_word:{
      theme:"button",
      text:"Load New Word",
      attributes:{
        onclick:"wordgame_load_new_word();"
      }
    },
    /* Word display container */
    word:{
      markup:'<div id="wordgame_word"></div>',
    },
    /* Player input form */
    player_input:{
      markup:drupalgap_get_form('wordgame_word_form')
    },
    /* Answer button */
    answer:{
      theme:'button',
      text:'View Answer',
      attributes:{
        onclick:"wordgame_view_answer();"
      }
    },
  };
  return content;
}

/**
 * The jQueryMobile pageshow call back function for the play page.
 */
function wordgame_play_pageshow() {
  wordgame_load_new_word();
}

/**
 * The player input form.
 */
function wordgame_word_form() {
  var form = {
    'id':'wordgame_word_form',
    'elements':{
      'translation':{
        'type':'textfield',
        'title':'Translation',
        'required':true,
      },
      'submit':{
        'type':'submit',
        'value':'Check My Answer',
      },
    },
  };
  return form;
}

/**
 * The player input form validation handler.
 */
function wordgame_word_form_validate(form, form_state) {
  // If the translation wasn't correct, set the form error.
  if (wordgame_answer != form_state.values.translation) {
    drupalgap_form_set_error('translation', 'Sorry, that is not correct!');
  }
}

/**
 * The player input form submission handler.
 */
function wordgame_word_form_submit(form, form_state) {
  // Their answer was correct, tell them about it, then load a new word.
  alert('Correct!');
  wordgame_load_new_word();
}

/**
 * Loads a new word from Drupal.
 */
function wordgame_load_new_word() {
  
  // Clear previous input.
  $('#edit-wordgame-word-form-translation').val('');
  
  // Grab a random word from the Drupal site translated view JSON page:
  //   http://language.tylerfrankenstein.com/vi/random-word
  //
  //   Note: the 'vi' is the language code for Vietnamese. Replace it
  //         with the language code for the language you would like to
  //        learn.
  drupalgap.views_datasource.call({
      path:'vi/random-word',
      success:function(data){
        if (data.nodes.length > 0) {
          // If there were any results, iterate over the collection.
          $.each(data.nodes, function(index, object){
              // Extract the node.
              var node = object.node;
              // Show the word to translate.
              $('div#wordgame_word').html(
                '<p>The word to translate is:</p>' + 
                '<p>' + node.title_translated + '</p>'
              );
              // Save the answer.
              wordgame_answer = node.title;
          });
        }
      }
  });
}

/**
 * Displays the current answer.
 */
function wordgame_view_answer() {
  if (wordgame_answer && wordgame_answer != '') {
    alert(wordgame_answer);
  }
}

Now when we run our game, it will look something like this:

Now if we enter the word "Hello" into the text field and click the "Check My Answer" button, we have conquered the game! If we don't know the answer, we can click 'View Answer' to see the translation.

16. Add New Word

We won't get very far into learning a new language, if we can't add more words. Luckily DrupalGap has built in support for users and entities. Let's login to our Drupal site, and then create a new word (Article).

Go to the login page by, you guessed it, clicking the Login button.

Add a region menu link in settings.js for authenticated users that will take them to the Article node form, for example:

/* Add Word Button */
{
  'title':'Word',
  'path':'node/add/article',
  "options":{"attributes":{"data-icon":"add", "class":"ui-btn-right"}},
  "roles":{
    "value":['authenticated user'],
    "mode":"include",
  }
}

See more complete details on adding region menu links with settings.js in DrupalGap

Once we add the menu button to our settings.js file, the game will look something like this:

Click the 'Add' button to go to the Article node form, add another English word, then click the 'Save' button.

17. Translate New Word

This was my first time experimenting with a multi lingual Drupal site. As the lead developer for DrupalGap, I've wanted to implement multi lingual features into DrupalGap for some time now, but haven't yet been presented the opportunity. I wanted to figure out a fun way to learn Vietnamese, and DrupalGap needs mutli lingual features, so I decided to write this demonstration game. At this point in our example game, I now see a limitation of DrupalGap. We don't yet have the feature of being able to translate nodes from within DrupalGap.

Unfortuntately for now, we'll have to translate the new word from the Admin UI back in our Drupal site. The translation of Goodbye in Vietname is, "tạm biệt". After translating the word, we should now be able to play the game with the new word.

18. Conclusion

I had fun building this little demonstration game, and hope it will keep me motivated to learn another language. I hope this example inspires you to give DrupalGap a try and see what types of fun mobile applications you can build for your Drupal site. If you'd like to contribute to DrupalGap, your code is certainly welcome. Please share your experience. Thanks for stopping by!

 

Comments

Tyler, this is awesome, thanks for posting this and introducing DrupalGap, never knew this existed!  Can the theme of the iphone/android app be 100% customizable so it looks like a native app and not a generic DrupalGap app?

Awakash, thanks for the kind words! I'm glad DrupalGap sounds interesting to you, I hope you'll be able to successfully build an app or ten for your Drupal sites. DrupalGap does support customizable themes (http://drupalgap.org/node/84). It would be possible to have a separate theme for each platform, just create two themes and then choose which one to use in the settings.js file for each platform. jQueryMobile is used for all themeing, so as far as making it look like a native app, that is up to the power/limitations of jQM. Good luck, and happy coding!

Thanks for the great DrupalGap plug in and tutorials. I had a rough start, but narrowed it down to incompatible versions of phonegap (3.0) and drupalgap (1.02).

I think it's awesome you are learning  Vietnamese. I have to teach my kids someday. 

Thank you Phil! You are correct, PhoneGap 3.0 may not be compatable yet with DrupalGap. I need to spend some time in the next few days testing out PhoneGap 3.0 and adjusting DrupalGap as necessary (they just released PhoneGap 3.0). Right now, I recommend using PhoneGap 2.9.0.

FYI, DrupalGap 1.02 is VERY old, I wouldn't recommend using it at all. The 7.x-1.4-alpha is the recommended version (7.x-1.5-alpha will be out in the next few days). Unfortunately, Drupal 6 isn't supported anymore.

Have we met before at DrupalCamp MI?

Yes we did meet at DrupalCamp MI. I enjoyed your presentation.

I am new to phonegap and was runing through the getting started guide which had me create the phonegap directory via the cli. I thought I was using 2.9, but didn't realize I had downloaded 3.0 since it came out that night.

You wouldn't happen to know how to specify using phone gap 2.9 when installing phonegap using the cli?

Is the Drupal Gap 7.x-1.5-alpha stable enough to use on a production app? I know it's an alpha. 

Lastly, where is the best place to get support? I'm having an issue rendering nodes with custom fields including video.

Thanks again for all your work on Drupal Gap. I hope to be able to help with the project when I come up to speed. 

Hey Phill,

When creating a PhoneGap project with 2.9.0, I just download 2.9.0 to my desktop, change directory into the phonegap-2.9.0/lib/android/bin, then run the ./create command. I think that counts as the CLI, but I haven't explicitly looked at their documentation for that portion yet. For example, run a command like this to get started (the destination directory must NOT exist):

./create ~/Desktop/phonegap-code/MyProject com.mybusiness.myproject MyProject

I think 7.x-1.5 alpha is stable enough for product. There are a few out there running version prior to that. It really depends on how complex your app wants to be and what is currently available.

For support, check out www.drupalgap.org/support for more info. Thanks for the kind words, good luck and happy coding!

Thanks for the quick response. 

My first app is not complex, so I should be good. Have a wonderful day.

Sorry for the off topic,

But you always answer my question in the past, and nobody answered this question on other forums, so i ask you if you can help me with this,

Firstly i use drupal 7.2 and services 3.5, i need to develop an application for work in Java that use xml rpc service from drupal,

It worked well in my localhost, but when i tried in the e-commerce drupal site the XML response from the server was not good, it added a tag   front in the xml like this :

Content-Type: text/xml

<front><?xml version="1.0"?>

<methodResponse>
  <params>
  <param>
    <value><struct>
  <member><name>sessid</name><value><string>Ac-2wF6wauhAi8nAneEOV-CCG_4iPRrJONmxqqa8zVM</string></value></member>
  <member><name>session_name</name><value><string>SESS8402317dc35203e47385dd8c23cb8b04</string></value></member>

when i use Burp suite and remove the front tag from the response of the server it worked well, so could you help me to find why drupal web service in the e-commerce site added this tag,

Cordially

and thank you so much!

Sorry jeks, I'm not sure what is happing with the front tag. I'd recommend updating your Drupal site from 7.2 (that is way behind the latest release). Then I would start with a fresh Drupal install, get my Services returning what I need (without the front tag prepended), then start enabling modules/features one-by-one to find out which one(s) is causing problems.

Thank you for the answer!

I removed one by one the modules, and i found that the module php filter is the one who's causing problems, the site is an  e-commerce wich im working for as internship, so i cant begin the project from nothing,

php filter module is used to integrate php code inside page, I enabled this module on my drupal in localhost and webservice still working, so there is php code in compagnies drupal site that is not working well,
and as the problem is only present in the user.login services i think the problem is maybe in some php code added by the previous developer ?

do you know how to find the method used by the service user.login ?

Thanks a lot !!

The User Login service resource uses POST. More info: http://tylerfrankenstein.com/code/drupal-services-examples

Hi Tyler,

Many thanks for the tutorial, i liked it very much.

It seems to have worked out well in general, though smth went wrong with the 'gameplay', maybe because i created the content_type "Word" (not Article), and maybe smth was confused, or smth wrong with my Views. I'll work on this. And by the way, it all worked on platform version 1.0.0.

But what I wanted to ask is how can I export the application? I mean how I can download the app as a .apk file to load on my Android device?

Many thanks again

Ulukman

 

Hi Ulukman,

To export your application as an APK file you'll need to open your project in Eclipse, run it in an emulator (or on your device). Then just right click on the project name in the left sidebar, and click Export. From there, select Android Application, and that'll take you through the wizard which will output the APK file.

FYI, the forms API in DrupalGap has changed slightly since I published this article, check out the forms page to see what is different: http://www.drupalgap.org/node/155

Hi Tyler,

Thanks for the answer and your tip. Can I pls ask couple of more questions?

1. In the tutorial above one thing is not working with my app. On the Step 11, section Fields, your 3rd field to be displayed comes from 'Content: Title - Appears in node:article', and it's returning you "Xin Chao", so the translation. However, my Views is not working that way, because that field returms me just the Title of article, not translation. Can you pls advise?

2. Regarding the export - I'm just a beginner and Eclipse seems to me difficult at the moment. But I've found https://build.phonegap.com/apps which says can easily build ready-to-use apps from projects I guess like you're making. Didn't you test that, what do you think? Or are you recommending to learn Eclipse (Android Studio) anyway? 

3. Can you pls hint, are these updated Forms API affecting the app above? On what step?

Many thanks again and good luck with your further tutorials!

Ulukman

Hi Ulukman,

1. Unfortunately my language site doesn't seem to be working anymore, I'm not sure why. So I can't get in and look at the view. If memory serves me correctly, I believe there were two title fields to choose from. One for the default language, and one for the secondary language. Hopefully you'll see two title fields to choose from.

2. I've heard about PhoneGap Build, but I haven't tried it yet. It sounds like it can be used as an alternative to Eclipse and it will just automatically export the build file(s) for you.

3. The updated Forms API (only necessary if you are using 7.x-1.x-alpha of DrupalGap, 7.x-1.5-alpha uses the older Forms API). The only step affected would be #15 (the form creation, validation and submission functions). The DG Forms API has an example of the new and old Forms API: http://drupalgap.org/node/155

I hope this helps!

Hi,thanks for the tutorial,i want to ask about user registration.Are there any tutorial how to create user registration from android using services 3.5?Thanks a lot.

Do a POST to /my_services_endpoint/user/register.json?name=bob&mail=bob@bob.com

You'll need to URL encode the e-mail address value.

DrupalGap has this built in, so you won't have to code anything ;)

About the translation part, this is what I use for drupal: https://poeditor.com/. A crowd translation platform that has a simple interface and also a drupal plugin that makes import easier. Localization is an important aspect and doing it properly brings a considerable boost.

This module looks great but having installed it on a staged version of a site I'm working on, I can't find the configuration options or content fields anywhere. The only mention I see of the module is under available tokens.

Hi Mark, there actually isn't any configuration options for DrupalGap. Essentially you just enable it, then you're ready to go with http://www.drupalgap.org/get-started