Cosmic JS Blog Stay tuned for community news, company announcements and updates from the Cosmic JS team.

How to Build a Multi-Language Static Website Without AJAX

by Flynn Buckingham on September 5, 2017

A couple of weeks ago I wrote an article about building a static website with Gulp, and why it’s so fantastic, as well as a couple of things I learned on the way.

But one of the things I failed to touch on was how to manage dynamic content with static websites. In a dynamic website, pulling locale data is often taxed with multiple AJAX requests, as well as the time it takes to process the data being pulled from the remote server.

But what if I told you there is a faster, and more optimized way to bundle the language data for your small web-application? And what if, I also told you that you can use a remote Content Management System (CMS), that can manage your website’s content?

Enter Cosmic JS

Do you want to know — what…. it…. is?

Cosmic JS is an API-first CMS system made to help bridge the gap between developers and editors. Unlike WordPress or Drupal, the Cosmic JS API lives independently from your code. This allows it to be implemented in a numerous amount of ways to accomplish an awesome amount of things.

There are several benefits to this (which you can read in detail about here), but the one I will be focusing right now will be the flexibility it can give us when approaching unique challenges.

One of these challenges that we can overcome is trying to manage content on a static web-application. Because Cosmic JS at it’s heart uses JSON data to deliver content to your website, we can take advantage of this to filter and embed the content we need.

Let me show you how it’s done.

Before we begin…

The Cosmic JS homepage (as of late 2017)

If you intend on modifying the app content you’ll have to create a Cosmic JS account. They offer free plans that you can use, as well as a 2 week trial to test it out without any restrictions.

Regardless, you’ll need to have a working development environment with Node.js and npm installed. We need it in order to run the Gulp build tooling as well as the development server. Once you have both Node.js and npm installed, we can begin working on the demo application.

Installing the demo

The demo GitHub project is located at cosmicjs/static-multi-language-app. Either clone the repository with git clone or download the project manually using the download button on the repository page.

Once the project is downloaded (and extracted if you downloaded an archive), cd into the project directory and then download the project dependencies with the command npm install. Once that is done, you should now be able to build the project.

Before we go through some the project details, build the developmentversion with the command gulp dbuild. The built application should then be available inside the build/ directory.

Running the App

How the default application should look (set to es-MX)

At this point, you’d probably want to run the application locally. To do so, make sure the project is built and start the development server with gulp server. Your default browser should open with the web app, located by accessing localhost:8080on your web browser.

App structure

The default app structure

The main structure of the application is split into two segments (like many web applications). There is the build/ section, which contains the built project files, which also acts as the additional web root for our development server. And the src/ section, which contains the source code for the project.

Key files in the root project directory include the config.js file, which contains the configuration for both the Cosmic JS API fetcher script fetch.js, as well as the Gulp build-file gulpfile.js. 

The file fetch-utils.jscontains a helper function for filtering through specific objects.

The fetcher-utils is fairly powerful, and I’m considering porting a more robust version to it’s own mini npm module. Follow me on Twitter or GitHub if you’d like updates about my open source projects.

There is also a if you’d like more detailed explanations and examples of how to take advantage of the API provided in the app.

Setting up for additional content

Here is a code snippet from the configuration file config.js:
// The config.js file
module.exports = {
    // Cosmic JS specific configuration...
    lang: {
        defaultLocale: 'en-US'
    fetch: {
        file: 'src/cosmic-data.json',
        cache: false,
        NodeWhiteList: ['locale', 'slug', 'content'],
        NodeAllowedTags: ['a', 'b', 'i', 'only-the-tags-you-want']

The default language loaded by the application is specified in the lang.defaultLocale key, and is en-US by default. This means that it will attempt to load the language locale en-US when the application first loads unless other-wise specified.

Dashboard > Nodes — This is what it should look like.

If you activated the demo on the Cosmic JS website, you should already have a bucket populated with Nodes, which are the default type that the application uses. Each Node contains a specific inline string that gets parsed by fetch.js to be embedded in your application.

Creating a new Node with the Cosmic API is fairly simple. To create a new Node, simply click the button on the top right + Add Node, and it should bring up a fairly simple UI that resembles something like this:

The UI for the Node creation interface.

When creating a new Node (for multiple languages) it is best to first select a locale with the Select Locale drop-down. This ensures that your data gets loaded with the correct locale when the app loads.

To name the Node, simply type a name into the Node Title field. A Slugfield (which will be mentioned again later) should auto-populate as you are creating the Title of the Node. Note that you cannot create a new Node with the same Slug unless the locale is different. This is to prevent accidental duplicate values within your app.

Once that’s done, enter in the content you’d like your Node to represent. This should be consistent between locales of your app.

A sample node.

When done, make sure to publish the Node by clicking the Publish button located at the top right of the page.

That’s it. You’ve created a new Node with the locale specified. For consistency, make sure to repeat this for each locale, so you have a set Node value for the locale specified.

So, now that you have all the locales set for a particular slug, you can start including the newly available data into your static web application.

To bundle the newly created Node, make sure you have an active internet connection. If you do, then run gulp dbuild or gulp build to fetch and embed the data into the bundle.js file located in build/assets/bundle.js

Adding static content to the markup

I created two main ways of adding content to your static website. The first is a static method, which involves adding a custom data-cosmic-node attribute to your application. The string value of the attribute should be equivalent to the slug name generated by the Cosmic JS API.

Navigate to the src/html/main.html and replace the default markup of :

<div class="app-container">
    <div class="cosmic-app">
        <h2 data-cosmic-node="button-press-prompt"></h2>
            <button id="add-button" class="cosmic-app-button">
                <span data-cosmic-node="add-button"></span>
            <button id="sub-button" class="cosmic-app-button">
                <span data-cosmic-node="sub-button"></span>
        <h2 class="cosmic-app-current-count">
            <span data-cosmic-node="current-count"></span>
            <span id="current-count"></span>
        <h3 id="count-message"></h3>

With this:

<div class="app-container">
    <h2 data-cosmic-node="this-is-a-sample-element"></h2>

Now simply rebuild the application with gulp dbuild. You should now get something that looks like this:

This is what the updated app should look like.

Assuming you made a Node for the locales appropriate for your app, you should see the contents of the element update whenever you switch locales. This is done through a element caching technique that searches the DOM for elements with the attribute data-cosmic-node, and will attempt to each one with the matching language value (if it exists).

Adding dynamic content to your app

Obviously, a static implementation alone is not enough for a useful web app, and being somewhat seasoned in this area I knew exactly what needed to be done.

I created a minimal language API for the application located at src/js/lang.js. It is not only responsible for caching and updating elements when the language changes, but it also provides methods that allows developers to manually get stored language strings, as well as execute custom events whenever the language locale successfully changes.

The documentation as well as a working implementation can be found within the demo itself (at src/js/main.js), in addition to the file.

But in case you’d rather me explain it here, this is the simple rundown of methods that will help you manage locale state in the application.


The method CosmicLangauge.getStringmethod does exactly what it sounds like. It attempts to fetch a specific value of a Node from the stored content. If found, it will return the filtered HTML content for the currently selected locale.

Here is an example of the method at work at work inside of a closure:

So, you can potentially loop this method, conditionally rendering different Node values depending on the conditions set forth by your logic. But as you may have figured, what would happen in the event that the locale changes throughout the app?


As the name probably suggests, this is an event handler. Whenever a locale change event is invoked (via the loadFromLocale method), an additional array of event handlers are also fired. These are bound with the aforementioned addUpdateEvent.

A simple example of the event handler in action.

While simple in practice, you’ll most likely need this if you plan on setting any sort of dynamic multi-language content within your web app. 

The example on the official repository shows a slightly more advanced means of managing the content of an Element based on state. I’d recommenced that you go check it out to get a better feel of how to implement the event.

In closing…

I could go on about the multiple ways to implement the mini language API I made. But the best way to learn is to simply throw yourself at it, and learn it at your own pace. Go ahead and try it out!

Personally, I really enjoyed writing the language API. It felt cool to accomplish something new, and provide a means to help other developers build their own applications.

You may also like

After many weeks of development we are excited to announce a couple of big updates.  We have completely rebuilt both our REST API docs and NPM module.

We're happy to announce that you now have the ability to publish your Objects at a later date and time.

This is blog number one on the new Cosmic JS blog page.  Hopefully this will help me find the best way to help developers and publishers use this platform easier and more efficiently.

Hello World!   We are officially in private beta mode.  Lots of work has been done up until this point to make Cosmic JS the best cloud-hosted content platform.  Sign up for an account and please send us some feedback.  Here is a copy of my blog post on the release:

Cosmic JS is a cloud-hosted content platform that makes it easy to manage content for websites and applications.

I built Cosmic JS because I saw a problem with scaling content across platforms and devices.  After years of building applications using installed content management systems, I became tired of rebuilding APIs to handle content distribution from a website to microsites, landing pages and applications.  I decided to build one API to handle all content outlets for easier and faster distribution, and Cosmic JS was born.

Cosmic JS allows for easy content management and distribution by giving you the power to store content as JSON objects in an API that can be delivered anywhere.

Cosmic JS is API-first, meaning your content can be distributed across all devices and platforms from your website, to microsites and landing pages, to native mobile applications which allows for faster development cycles.   And when you use Cosmic JS to serve data and files, application servers can be kept light-weight which saves on server costs.

Get started

Click here to sign up for a Cosmic JS account, it’s completely free to sign up.

Cosmic JS is currently in private beta but you will be notified when your account has been activated.

Start building

Click here to check out the available clients for JavaScript and PHP on GitHub.

Currently there are available clients for JavaScript and PHP to help you get started building scalable, content-ready applications.

View examples

Click here to view code for websites built using Cosmic JS.

I’ll post some tutorials on this blog soon to show you how easy it is to use Cosmic JS to manage content for your next project, so stay tuned.  If you have any questions, please post them below, or reach out to me on twitter or email me.

Tony Spiro

Click here to go to Cosmic JS
Click here to go to Cosmic JS on GitHub

It's now easier to get started using Cosmic JS as your content platform.  After signing in, click "Add new bucket" and you will see that you now have the option to install a starter bucket.  

After you click "Install", your starter bucket will be imported to a new bucket and your app zip file will be downloaded to your machine.  At that point you can extract the files and configure your new app to connect to your new Cosmic JS bucket.  

This is meant to help familiarize you with how to set up your bucket to best manage content for your websites and apps.  Sign in and enjoy!


In this installment of the Cosmic JS Developer Spotlight Series, we sat down with Sumit Kharche, a Full Stack Software Developer residing in Pune, India. Submit is an active member of the Cosmic JS Community, having recently built the new React Static Blog, which is available in the Cosmic JS Apps Marketplace. With more community projects on the way, we're excited to interview one of our own for this Spotlight. 😎 Follow Sumit on Twitter, LinkedIn and GitHub, and enjoy the conversation.