DEV Community

Daniel Kantor
Daniel Kantor

Posted on

Generate screenshots for your translation keys

Screenshots are a useful tool for your translators, because they give context for your translation keys. Seeing text in it's proper context will make it much easier to create the correct translation.

This guide assumes that you know how to use Cypress, and have already set it up in your project. I do not recommend installing Cypress just to create screenshots for your translation keys.

Providing the tkey data attribute

In order for this solution to work, you'll need to provide the tkey data attribute for all translation keys. This is required so that the screenshots can receive the correct filename.

There are different ways to achieve this, and the implementation depends on the framework that you use.

In the case of my Svelte code in LibreLingo, I created a component which I use to wrap my translation keys.

<script>
  import { format } from "svelte-i18n"

  export let key
</script>

<span data-tkey={key}>
  {$format(key)}
</span>

This way I never have to specify this manually. It's implicit for every translation key.

Creating the screenshots

Creating screenshots with Cypress is easy:

cy.screenshot(fileName)

But, we need to create a separate file for each translation key, and with the correct filename:

cy.get('[data-tkey]').each($el => {
  const tkey = $el.data('tkey')
  console.log(`📸 Creating screenshots for ${tkey}}`)
  cy.screenshot(`__tkey-${tkey}`)
})

I am already using Cypress for visual regression testing, so I just put this code where I already create screenshots. There are other options if you don't use visual regression testing. You can consider running this code on the window:load event.

After running my Cypress tests, I already see the screenshots:

Alt Text

The problem is that a page can contain various translation keys. With this method, each translation key will have an identical screenshot, if they are on the same page. This is not ideal, because it can be hard to spot the specific translation key.

Outlining the translation on the screenshots

A nice way to guide the attention of the translator is to mark the relevant part of the screenshot.

I chose to draw a red rectangle around the relevant DOM node. Fortunately, it's very easy to find out the position and size of a DOM node relative to the viewport:

$el[0].getBoundingClientRect()

Using that, I can create a function that highlights a specific DOM element on the page:

const createRectangle = ({ left, top, width, height }) => {
  const rectangle = document.createElement("div");
  rectangle.setAttribute(
    "style",
    `position: fixed;
     left: ${left - 5}px;
     top: ${top - 5}px;
     width: ${width + 15}px;
     height: ${height + 15}px;
     border: 3px dashed red;
     z-index: 1000000;`
  );

  return rectangle;
};

const createElementHighlighter = (element) => {
  return createRectangle(element.getBoundingClientRect());
};

I can use that function to highlight each element before their screenshot is taken:

cy.get("[data-tkey]").each(($el) => {
  const tkey = $el.data("tkey");
  const highlighter = createElementHighlighter($el[0]);

  cy.window().then((win) => {
    win.document.body.appendChild(highlighter);
  });

  console.log(`📸 Creating screenshots for ${tkey}}`);
  cy.screenshot(`__tkey-${tkey}`);

  cy.window().then((win) => {
    win.document.body.removeChild(highlighter);
  });
});

If I run my tests now, I can see that the elements are correctly marked 🎉. Examples:

Alt Text

Alt Text

Drawbacks

This approach has several limitations and drawbacks. To name a few:

  • I wouldn't recommend checking these files into git, because they can change very often. Instead, it's better to upload them into your translation platform directly.
  • It's not useful to create screenshots this way if you don't already have Cypress tests covering the specific area of your app
  • It will slow down your Cypress tests slightly, although this can be mitigated if you only create the screenshots when an environment variable is set

Top comments (0)