Translation

This kit does not include any built-in translation utilities like gettext. Instead, we recommend creating different pages or embeds for each language you’re building and passing the translated content to common Svelte components.

Translating pages and embeds

Let’s say you want to translate your project.

If your content comes from a Google doc, you’ll add a new doc to google.json, in this case for German, de (πŸ‡©πŸ‡ͺ):

// google.json
{
  "docs": {
    "locales/en/content.json": "GOOGLE_EN_DOC_ID-123456789etc",
    "locales/de/content.json": "GOOGLE_DE_DOC_ID-123456789etc"
  },
}

Once you run yarn get-google, you will see the translated content in your locales folder:

locales/
  en/
    content.json
  de/
    content.json

… with different text values for each keyed piece of content like:

// en/content.json
{
  "greeting": "Hello!"
}

// de/content.json
{
  "greeting": "Guten Tag!"
}

To publish a page and embed in both English πŸ‡¬πŸ‡§ and German πŸ‡©πŸ‡ͺ, you might have a pages/ directory like:

pages/
  de/
    +page.svelte πŸ‡©πŸ‡ͺ
  embeds/
    en/
      page/
        +page.svelte πŸ‡¬πŸ‡§
    de/
      page/
        +page.svelte πŸ‡©πŸ‡ͺ
  +page.svelte πŸ‡¬πŸ‡§

Inside each +page.svelte, import the correct content for that page’s translation and pass it to a common component:

<!-- πŸ‡¬πŸ‡§ pages/+page.svelte -->
<script>
  import englishContent from '$locales/en/content.json';
  import App from '$lib/App.svelte';
</script>

<App content="{englishContent}" />
<!-- πŸ‡©πŸ‡ͺ pages/de/+page.svelte -->
<script>
  import germantContent from '$locales/de/content.json';
  import App from '$lib/App.svelte';
</script>

<App content="{germanContent}" />

Now the common component App.svelte can use the correct translated text passed to it:

<!-- src/lib/App.svelte -->
<script>
  // Can be πŸ‡¬πŸ‡§ or πŸ‡©πŸ‡ͺ
  export let content;
</script>

<h1>{content.greeting}</h1>

The same principle applies to your embeds:

<!-- πŸ‡¬πŸ‡§ Embed page: pages/embeds/en/page/+page.svelte -->
<script>
  import englishContent from '$locales/en/content.json';
  import App from '$lib/App.svelte';
</script>

<App content="{englishContent}" />


<!-- πŸ‡©πŸ‡ͺ Embed page: pages/embeds/de/page/+page.svelte -->
<script>
  import germanContent from '$locales/de/content.json';
  import App from '$lib/App.svelte';
</script>

<App content="{germanContent}" locale="{'de'}" />

Changing components in Svelte based on translation

You may also want to conditionally change content in a component based on the language of the page that’s using it.

One way is to pass a locale prop from each +page.svelte page – in a similar way to how you passed different values through the content prop – and use it to set values in your code.

Let’s try updating the byline in our App.svelte component.

First, declare the locale prop in App.svelte with a default value, likely en.

<!-- src/lib/App.svelte -->
<script>
  export let content;
  // πŸ‘‡πŸ‘‡πŸ‘‡
  export let locale = 'en';
</script>

Now use that prop to conditionally set some content, in our case translating our byline to Spanish.

<!-- src/lib/App.svelte -->
<Headline section="{content.Kicker}" hed="{content.Hed}" dek="{content.Dek}">
  <span slot="byline">
    <!-- πŸ‡¬πŸ‡§ locale -->
    {#if locale === 'en'}
      By {@html marked.parseInline(content.Byline)}
      <!-- πŸ‡ͺπŸ‡Έ locale -->
    {:else if locale === 'es'}
      Por {@html marked.parseInline(content.Byline)}
    {/if}
  </span>
</Headline>

Now be sure to pass the correct value to your App.svelte component from each +page.svelte that uses it (including embeds):

<!-- πŸ‡©πŸ‡ͺ pages/en/+page.svelte -->
<script>
  import englishContent from '$locales/de/content.json';
  import App from '$lib/App.svelte';
</script>

<App content="{germanContent}" locale="en" />

<!-- πŸ‡©πŸ‡ͺ pages/de/+page.svelte -->
<script>
  import germantContent from '$locales/de/content.json';
  import App from '$lib/App.svelte';
</script>

<App content="{germanContent}" locale="de" />

You can use that prop to set any other conditionals you need.

For example, let’s put the dateline in more Euro-friendly format using the javascript Date.toLocaleString method, passed the locale parameter for Spanish and a date formatter object:

<!-- src/lib/App.svelte -->
<script>
  export let content;
  export let locale = 'en';
</script>

<Headline section="{content.Kicker}" hed="{content.Hed}" dek="{content.Dek}">
  <span slot="byline">
    <!-- ... -->
  </span>
  <div slot="dateline">
    <!-- πŸ‡ͺπŸ‡Έ locale -->
    {#if locale === 'es'}
      Publicado <time datetime="{content.Published}">
        {new Date(content.Published).toLocaleString('es-ES', {
          year: 'numeric',
          month: 'long',
          day: 'numeric',
        })}
      </time>
      <!-- πŸ‡¬πŸ‡§ locale -->
    {:else}
      Published <time datetime="{content.Published}">
        {apdate(new Date(content.Published))}
      </time>
    {/if}
  </div>
</Headline>

Other options

For more complex translation handling, you can use something like svelte-i18n.

Translated pages and embeds in RNGS

Pages

The graphics kit will upload all pages to RNGS in a single archive. That means translated pages will share the same root URL as your English language page.

So with a pages/ directory like:

pages/
  de/
    +page.svelte πŸ‡©πŸ‡ͺ
  +page.svelte πŸ‡¬πŸ‡§

The German-language page will be at the same URL for the English page PLUS /de/.

For example, this is the URL for a recent English page: https://www.reuters.com/graphics/PERU-PROTEST/ROADBLOCK/zgpobnbwavd/

And this, for its Spanish translation + es: https://www.reuters.com/graphics/PERU-PROTEST/ROADBLOCK/zgpobnbwavd/es/

Embeds

Embeds, by contrast, are each uploaded as a separate archive, which means they’ll generally have unique URLs.