npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@lefapps/translations

v4.0.2

Published

React package for translations and cms

Downloads

9

Readme

Translations (@lefapps)

This package should be accompanied by @lefapps/translations-server to get the fulle experience.

Setup

Install from npm:

npm i @lefapps/translations

Import in your app:

import { Translator } from '@lefapps/translations'

Define a translator configuration:

const languages = ['nl', 'fr', 'en'] // you are free to decide how they look
const defaultLanguage = languages[0]
const translatorConfig = {
  languages,
  language:
    typeof navigator !== 'undefined'
      ? (navigator.language || navigator.userLanguage).split('-')[0] || defaultLanguage
      : defaultLanguage,
  canEdit: () => true // must be a function
}

Wrap your app code:

const App = () => {
  return (
    <Translator {...translatorConfig}>
      // App code
    </Translator>
  )
}

Note: changing the language can be done by changing the language prop in the config.

Use the Translate Component:

import { Translate } from '@lefapps/translations'

const Content = page => {
  return <Translate _id={page} />
}

Access the raw translation string:

import { useRawTranslation } from '@lefapps/translations'

const Logo = ({ src }) => {
  const { translation } = useRawTranslation('menu/logo/alt')
  return <h1><img src={src} alt={translation} /></h1>
}

Include the languageSwitcher:

import { PickLanguage } from '@lefapps/translations'

const Header = () => {
  return (
    <header>
      <h1>My Brand</h1>
      <nav>
        <ul />
        <PickLanguage />
      </nav>
    </header>
  )
}

Translate

Use the Translate component to fetch translations using a specific identifier.

Props

| Prop | Type | Required? | Default | Description | | --------- | ------------------- | --------- | --------- | --------------------------------------------------------------------- | | _id | String | ✓ | "" | Identifier of the translation (see guidelines) | | md | Bool | | false | Formatted using MarkDown (html rendered using the markdown-it plugin) | | tag | StringComponent | | span | HTML tag to wrap the translation | | className | String | | "" | Optional classnames for | | params | Object | | {} | Replace text: {{key}} gets replaced by its value | | autoHide | Bool | | false | Hide the component when the translation is empty | | onInit | Func | | null | Callback when the component is initialised (before loading) | | onLoad | Func | | null | Callback when the translation data is finished loading | | children | StringNodes | | null | Initial value while loading | | language | String | | [current] | Force a different language to be loaded |

Guidelines

We recommend to define your identifiers with the following schema:

header
header/menu
header/menu/about
header/menu/about/team
header/menu/about/contact
etc...

This way you can easily group and organise them in your storage/database.

Attributes

The following HTML attributes are automatically applied on the element:

.translation: always present
.translation__loading: present while fetching
.translation__md: present when markdown formatting is applied
.translation__error: present when an error occurred while loading
[data-translation]: the identifier

*The component is automatically subtly styled while loading.

useRawTranslation

Use the useRawTranslation hook to fetch translations as a string instead of React Component.

Notes

  1. To keep your code organised, only use useRawTranslation when necessary(e.g. for alt or title attributes — these do not accept React Components).
  2. The returned translation is the raw string. If the value contains MarkDown, you should take care of encoding it in your app.

Arguments

Accepts one argument, the identifier: useRawTranslation(_id).

Returns

| Key | Type | Description | | ----------- | ------ | --------------------------------------------------------------- | | loading | Bool | True while the translation is being fetched | | error | Object | Populated with Apollo Error if something goes wrong | | translation | String | Translation for the identifier in the currently active language | | _id | String | Identifier of the translation | | md | Bool | Whether the returned string contains MarkDown | | params | Array | Available keys |

PickLanguage

Use this component to change language. it is automatically hidden when only one language is provided.

Props

| Prop | Type | Required? | Default | Description | | --------- | --------------- | --------- | ------- | ---------------------------------------- | | children | StringNodes | | null | Content to show as label of the dropdown | | showTitle | Bool | | false | Show the current language |

Attributes

The following HTML attributes are automatically applied on the element:

"#language-picker": always present

No default styling is applied on this component.

The languages shown in the picker are Translate components with the following identifier: translator/{{language}}. Transalte them to your linking!

Internals

If you want to access certain dynamic fields from the translator, e.g. the current language, use the useTranslator hook.

import { useTranslator } from '@lefapps/translations'

const Page = () => {
  const { languages, setLanguage } = useTranslator()

  return (
    <ul>
      {languages.map(lang => {
        return <li key={lang} onClick={() => setLanguage(lang)}>
          {lang}
        </li>
      })}
    </ul>
  )
}

The same can be achieved with the HOC withTranslator:

import { withTranslator } from '@lefapps/translations'

const SetEnglish = withTranslator(({ language }) => {
  return (
    <p>
      This is the current language: {language}
      <br/>
      <button onClick={() => setLanguage('en')}>
        Set current language to EN
      </button>
    </p>
  )
})

Props

These values can be retrieved from the hook/hoc:

| Prop | Type | Description | | ----------- | ------------ | ------------------------------- | | language | String | Currently selected language | | languages | [String] | All available languages | | setLanguage | Function(ln) | Change current language to ln |

Data Fetching

The transltions are fetched over the wire using GraphQl queries and mutations. When your app is using graphql already, you can easily integrate the queries. Use the companion package @lefapps/translations-server to implement the backend correctly.

Editing

When the canEdit config returns a non-falsy value, the translated text shows an editor to edit the translation in place after double clicking it. Note: this is merely a client-side optimisation, you should always authenticate and validate incoming requests server-side.

Otherwise you can build your own backend list to edit each translation. An example:

import React, { useState } from 'react'
import { useQuery } from '@apollo/react-hooks'
import { queries, Editor } from '@lefapps/translations'

const Translation = ({ _id }) => {
  const [isOpen, setOpen] = useState(false)
  const onClick = () => setOpen(!isOpen)

  const actions = { onClick }
  const name = _id.split('/')

  return (
    <li key={_id}>
      <h3 {...actions}>{name}</h3>
      <Editor _id={_id} toggle={toggle} isOpen={isOpen} alert={alert} />
    </li>
  )
}

const Translations = () => {
  const { data } = useQuery(queries.TRANSLATION_LIST)
  return (
    <section>
      <h1>Translations</h1>
      <ul>
        {data.translations.map(Translation)}
      </ul>
    </section>
  )
}