How the DevRel/Asia 2020 website works

Aug 12, 2020

I’d like to introduce the architecture of the DevRel/Asia 2020 website. The basic architecture of the website follows that of DevRelCon Tokyo, which I am organizing. But with major changes in terms of multilingual support.

The concept is as follows

  • Serverless
  • Static
  • Multiple languages support
  • Easy maintenance


First, let’s write about serverless. DevRel/Asia 2020 is built on a combination of the following services.

Out website is deployed on GitHub Pages. And we are used Jekyll a static website engine. Jekyll can use JSON and YAML as a data file. So for example, we prepare JSON data for the organizer and update it. the website will also be updated automatically.

We use Google Sheets as the source of this data, which mainly manages the following data.

  • Organiser Information
  • Translation Information
  • Sponsor Information
  • etc.

In order to get the data on Google Sheets, we developed an API to output the data in JSON in Google Apps Script. We periodically hit this API to update the files on Jekyll, and by exposing Google Apps Script as a web API, we can get the data as follows.

wget -O _data/organizers.json

GitHub Action is used to periodically update data as a cron every minute (actually it seems to be every 8 minutes) when it is pushed to master. Here’s a partial configuration of GitHub Action.

    runs-on: ubuntu-latest
    - name: Build the site in the jekyll/builder container
      uses: actions/checkout@v2
        persist-credentials: false
        fetch-depth: 0
    - name: Create local changes
      run: |
        wget -O ${{ github.workspace }}/_data/organizers.json ${{ secrets.URL }}?name=organizers
        wget -O ${{ github.workspace }}/_data/translates.json ${{ secrets.URL }}?name=translates

About CFP

The CFP has a dedicated form. Originally, we used to use PaperCall, but there were some problems, such as not knowing which language to use because it does not support multiple languages, and not being able to select the language speaker want to use when they speak. There is a way to describe such explanation on PaperCall, but it is not practical since there are 6 languages (English, Japanese, Korean, Chinese, Indonesian and Vietnamese). So, we prepared the CFP form independently and decided to support multiple languages.

I will write later on how to support multiple languages. When someone submit a CFP form, the data is sent to Nifcloud mobile backend. There are several reasons for this.

  • If the person call Google Apps Script, they can’t send from mainland China (Google’s service will be blocked).
  • Turning Google Apps Script into a REST API with POST is a bit of a hassle (I dealt with it later…)

Nifcloud mobile backend allows person to restrict ACLs (Access Control Law) at the time of data registration. So it’s easy to register CFPs, but not to view or delete them. And the data registered in Nifcloud mobile backend will be reflected in Google Spreadsheet by Google Apps Script time-based triggers.

When the data is reflected, we send an email to CFP contributors, telling them to confirm their CFP registration. We use Customers Mail Cloud for sending email. We also notify the organizer channel in Slack that the CFP has been received.

Voting CFP

One of the weak points of using PaperCall is that the free version only allows up to 5 people to participate in voting. Of course, we could have gone with a paid version. But in this case, we solved that problem by using our own form, which we created using Google Apps Script to develop our own voting form. Now all the organizers (there are over 30 organizers at DevRel/Asia 2020) can participate in the voting.

The voting form is built on Google Apps Script, so it’s easy to read the data and implement the voting results. Voting results are, of course, stored in a Google Sheets.

Contact by email

The conference is accompanied by a contact form. We have two entrances.

  • Using the embeded form
  • By email

The first thing we do is send a dedicated form inquiry, which sends data to Nifcloud mobile backend and runs a scripting function in it. It’s sending a message directly to the Slack channel.

By email, this is an email address ( registered in the Customers Mail Cloud, which calls doPost function in Google Apps Script by webhook. If the email is addressed to, all emails are delivered to the Slack channel via Google Apps Script. I didn’t use Nifcloud mobile backend because the Customers Mail Cloud webhook doesn’t support the signature generation required for Nifcloud mobile backend requesting. In other words, there is no way to invoke Nifcloud mobile backend scripting without a signature.

The email reply form is created in Google Forms. And the script for the form submission is used to send the email. We use Customers Mail Cloud for email submissions. The advantage of this is that we can keep a record of the results of the Google Form submissions and we can use as From. We can also always add to CC if we need to.

Update email

We use Mailchimp for email updates. We don’t have anything special to say about it. It’s easy to use and it’s a great service.

Posting social

We have the following social channels at DevRel/Asia 2020

Creating a message for each of these channels is hard, so we use Buffer. We use Buffer, which has an API that allows to batch submit messages to pre-registered social services.

So we’ve created a form for social submissions using Google Forms. The information you enter will be stored in a Google Sheets, and we have a script that periodically registers the content in the Google Sheets. We also included a script that periodically registers the contents of the Google Sheet to Buffer.

The big advantage of this architecture is that we don’t have to register each account to each social service - no more TweetDeck for Twitter, no more registering for Facebook or LinkedIn admins. The person in charge will be able to send messages to each service by filling out one form.

Another advantage is that since it’s a Google Sheets, we can create messages in bulk using formulas. For example, we can create messages in bulk to introduce organizer information, or we can create messages in bulk for potential speakers. If it’s a standard message, we can create a batch of messages at once. The delivery time can be easily manipulated using formulas (e.g., set it to 5 minutes after the previous post).

The combination of these services allows us to manage and operate the DevRel/Asia 2020 website in a serverless and free.


There is a CMS for managing conferences, but it can be a pain to use. There is WordPress plugin, but Google Sheets is much easier to operate. Managing servers is also a hard, and there are also some security risks.

For this reason, DevRel/Asia 2020 has been designed to be a static site, following in the footsteps of DevRelCon Tokyo, with free SSL hosting and stable operation with GitHub Pages.

Multiple languages support

The hardest part of the conference was going multilingual. At DevRelCon Tokyo, we only had to use two languages, English and Japanese. This time, as we mentioned earlier, there are 6 languages. First, we prepared a translation key.

Key English Japanese Korean Vietnamese Indonesian
intro2 About The Conference カンファレンスについて 컨퍼런스 소개 Về Hội Nghị Tentang Konferensi

Instead of translating from English to another language in this way, We’re using keys to translate each one. The problem is that not all translations are complete, and some are missing. The problem is that if a translation is not completed in time, it will be empty string. This means that if a translation is not available, we need to show the English language, and if a translation is available, we need to show the local language.

Since it was difficult to do that in Jekyll, I decided to use Ruby to handle it beforehand. This is done in GitHub Actions. If the keys are translated, they are given priority, if not, the English strings are applied to the keys. As a result, the process on the Jekyll side is simple.

For all displays, we write the following process

{% assign messages = %}
{% include translate.html %}

It would have been nice to be able to write something like below, but Jekyll doesn’t seem to allow us to define variables in included files when using include. So I use assign every time.

{% include translate.html messages = %}

The translation is rendered in parallel as follows. And by default, all .lang is hidden.

<span class="lang en">{{ messages.english }}</span>
<span class="lang ja">{{ messages.japan }}</span>
<span class="lang ko">{{ messages.korea }}</span>
<span class="lang zh">{{ messages.hongkong }}</span>
<span class="lang id">{{ messages.indonesia }}</span>
<span class="lang vi">{{ messages.vietnam }}</span>

And using JavaScript to recognize the language of the web browser when the website is displayed and reflect it in the display. The language recognition process uses a library called blang.

if ( {
} else if ( {
// The following is omitted

In addition, although we don’t see this often in Japan, in some cases, the basic language is English and the local language is set after the second language. In this case, English takes precedence over other languages, and even if the local language is supported, it will not be used. To solve this problem, our system retrieves the languages set in the web browser and notifies the visitor whether to use the local language if it is available.

const langs = navigator.languages;
if (langs.includes('ko')) {
  $('#language_change').attr('title', '여기에서 표시 언어를 영어에서 한국어로 변경할 수 있습니다.');
if (langs.includes('vi')) {
  $('#language_change').attr('title', 'Bạn có thể thay đổi ngôn ngữ hiển thị tại đây');

This method is generally fine, but there are a few issues

  • Only English is available for OGP (Open Graph Protocol)
  • Can’t apply multilingual processing to select tag options
  • Can’t apply multilingual processing to the input placeholders
  • The other languages are not well hidden in the Markdown display

There are some problems that haven’t been solved, but if we’re using Markdown, for example, we can solve them by using JavaScript to render Markdown.

Easy maintenance

Being a static site and using a Google Sheets makes it much less maintainable. If it’s in a table format, we’ve all had experience editing it. It’s a lot easier than creating a dedicated admin screen, and doing all the complicated processes there.

Scattered information is the most problematic in this kind of much people work. There are few places to look, and it’s recommended to be fixed. In this case, I only use Google Drive and Slack. All of our emails come to Slack, all of our meeting minutes are stored on Google Drive, our CFP votes and social posts are completed on Google Forms.


I’ve introduced back stage at DevRel/Asia 2020. Operating serverless frees us from managing servers and allows us to focus on running the conference. With data management and presentation separated, it’s also easier to isolate problems as they arise.

I hope you all find it helpful when you’re running your own conference or community website!

Newsletter ニュースレター 뉴스레터 Berita Bản tin

Please register your email address so you won't miss any update on DevRel/Asia 2020! We never send spam emails. メールアドレスを登録してください。DevRel/Asia 2020に関するニュースをお届けします!(スパムメールは送りません) 이메일 주소를 등록하시면, DevRel/Asia 2020 소식을 전해드립니다. Silahkan daftar alamat email Anda agar Anda tidak ketinggalan menerima kabar terbaru dari DevRel/Asia 2020! Kami tidak pernah mengirim email spam. Vui lòng đăng ký địa chỉ email của bạn để bạn không bỏ lỡ bất kỳ cập nhật nào trên DevRel / Châu Á 2020! Chúng tôi không bao giờ gửi email spam.

Please follow us on social media. SNSのフォローをお願いします 소셜 미디어를 팔로우해주세요. Ikuti kami di media sosial. Hãy theo dõi chúng tôi trên phương tiện truyền thông xã hội.