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

tachyon-intl

v32.0.0

Published

Wrapper around twitch-intl that consumes tachyon-intl-server data

Downloads

4

Readme

Tachyon-Intl

Internationalization helpers using twitch-intl that works well with tachyon-intl-server.

Setup

Add twitch-intl-cli To Your Project

  1. If you have not yet had your Smartling project onboarded to Loom, reach out on Slack in the #loom channel.

  2. In the package's package.json file add the necessary intl commands and dependencies, replacing $LOOM_PROJECT with your Loom project id:

    {
      "files": ["messages/"],
      "scripts": {
        "intl:download": "twitch-intl download --midway -S \"!(node_modules)/**/!(*.test).ts?(x)\" --project-id $LOOM_PROJECT --outdir ./messages",
        "intl:submit": "twitch-intl upload --midway -S \"!(node_modules)/**/!(*.test).ts?(x)\" --project-id $LOOM_PROJECT --prompt --exclude-uploaded --submit --jira-ticket",
        "intl:test": "yarn intl:test:ci --midway",
        "intl:test:ci": "twitch-intl submission-check -S \"!(node_modules)/**/!(*.test).ts?(x)\" --project-id $LOOM_PROJECT"
      },
      "dependencies": {
        "tachyon-intl": "^17.0.0"
      },
      "devDependencies": {
        "twitch-intl-cli": "^4.4.0"
      }
    }
  3. Create a messages directory in the root of the project.

  4. Submit strings following the submission process.

  5. Run yarn intl:download to populate messages for all locales.

Install The Root Context

Your app can either load intl data on its own and pass them into TachyonIntlRoot (this is what Tachyon apps do):

import type { FC } from 'react';
import { IntlData, TachyonIntlRoot } from 'tachyon-intl';

export const renderApp: FC = () => {
  // Implement getIntlData reading it in the way that makes the most sense
  // for your application
  const intlData: IntlData = getIntlData();

  return <TachyonIntlRoot data={intlData}>{/* App JSX */}</TachyonIntlRoot>;
};

If your app already uses TwitchIntl and needs to inter-op with tachyon-intl, you can pass in the intl instance (this is what Twilight does):

import type { FC } from 'react';
import { TachyonIntlRoot } from 'tachyon-intl';

export const renderApp: FC = () => {
  // Wherever your intl comes from
  const intl = createTwitchIntl();

  return <TachyonIntlRoot intl={intl}>{/* App JSX */}</TachyonIntlRoot>;
};

Submitting Strings

Tachyon-Intl uses twitch-intl-cli to manage string submission. Submit strings for the "tachyon" (if developing in Tachyon) Loom project (corresponding to the "Mobile Web" Smartling project) following the string submission process.

Downloading Strings

yarn intl:download

Formatting App Strings For Internationalization

Reference this internationalization guide for an exhaustive list of localization use cases such as dealing with numbers, dates, times, durations, and link rendering in sentences.

Hook Use

  1. Call useIntl() in your functional component.
  2. Destructure the necessary format helper(s) to a local variable named formatMessage (or one of the other names) off of the return of useIntl().
  3. Read the documentation for using these helpers.

IMPORTANT: Do not skip step #2. If you attempt to consume formatMessage directly off of intl, twitch-intl-cli will not function correctly. The internationalization relies on the names matching exactly and being their own function names.

import type { FC } from 'react';
import { useIntl } from 'tachyon-intl';

interface WelcomeBannerProps {}

export const WelcomeBanner: FC<WelcomeBannerProps> = (props) => {
  // Always assign to a local variable before consuming
  const { formatMessage, formatNumber, formatNumberShort } = useIntl();

  return (
    <div>
      {formatMessage('Welcome to your home screen!', 'WelcomeBanner')}
      {/* ... */}
    </div>
  );
};

HOC Use

  1. Wrap a component with the withIntl HOC and extend IntlProps in the component's prop interface.
  2. Assign the necessary format helper(s) to a local variable named formatMessage (or one of the other names) off of props.intl.
  3. Read the documentation for using these helpers.

IMPORTANT: Do not skip step #2. If you attempt to consume formatMessage directly off of props.intl, twitch-intl-cli will not function correctly. The internationalization relies on the names matching exactly and being their own function names.

import { Component } from 'react';
import { IntlProps, withIntl } from 'tachyon-intl';

interface WelcomeBannerProps extends IntlProps {}

class WelcomeBannerBase extends Component<WelcomeBannerProps> {
  public override render(): JSX.Element {
    // Always assign to a local variable before consuming
    const { formatMessage, formatNumber, formatNumberShort } = this.props.intl;

    return (
      <div>
        {formatMessage('Welcome to your home screen!', 'WelcomeBanner')}
        {/* ... */}
      </div>
    );
  }
}

export const WelcomeBanner = withIntl(WelcomeBannerBase);

Getting The User's Selected Locale

You can also get the user's preferred, among those we support, locale and language:

import type { FC } from 'react';
import { useIntl } from 'tachyon-intl';

const LocaleDependentComponent: FC = () => {
  const { getActiveLocale, getLanguageCode } = useIntl();
  // ...
};

Gating Features Based On User Locale

The <LocaleGate> allows gating features behind a list of country codes. By default it operates in allowlist mode but it can also operate as a blocklist.

Operating as an Allowlist

import type { FC } from 'react';
import { LocaleGate, CountryCode } from 'tachyon-intl';

const ComponentThatShouldOnlyRenderContentInBrazilAndMexico: FC = () => {
  return (
    <LocaleGate countries={[CountryCode.Brazil, CountryCode.Mexico]}>
      {/*Brazil & Mexico only content here*/}
    </LocaleGate>
  );
};

By default <LocaleGate> will fall back to rendering null. You can optionally pass a fallback.

Operating as a Allowlist with Fallback

import type { FC } from 'react';
import { LocaleGate, CountryCode } from 'tachyon-intl';

const FallBackComponent: FC = () => {
  return (
    <div>
      This is only available in Brazil & Mexico and you sadly aren't there.
    </div>
  );
};

const ComponentThatShouldOnlyRenderContentInBrazilAndMexico: FC = () => {
  return (
    <LocaleGate
      countries={[CountryCode.Brazil, CountryCode.Mexico]}
      fallback={FallBackComponent} // you can also write this as () => <FallbackComponent />
    >
      {/* Brazil & Mexico only content here */}
    </LocaleGate>
  );
};

Operating as a Blocklist

import type { FC } from 'react';
import { LocaleGate, CountryCode } from 'tachyon-intl';

const ComponentThatShouldOnlyRenderContentInBrazilAndMexico: FC = () => {
  return (
    <LocaleGate blocklist countries={[CountryCode.Brazil, CountryCode.Mexico]}>
      {/* Globally accessible content EXCEPT for Brazil & Mexico */}
    </LocaleGate>
  );
};

Warnings

  • It's very easy to run into surprising issues by rendering content on the server that you assumed would happen on the client. Particularly, the formatDate and formatTime methods will probably not behave as you expect when running in a Server Side Rendered application. For mitigation and more details see dates.
  • When using <LocaleGate> be aware that this uses the user's device locale as a trigger. The locale is in the user's control on their device (they can change it by changing their device country & language setting), so do not use this for sensitive features!

Common Issues

You are required to have a valid mwinit cookie to run intl:download and intl:submit commands. If you aren't you'll see something like:

Downloading latest translated messages...
There was an error downloading the messages.
Error getting strings for project tachyon. Midway/ApiGateway response: 403 Forbidden
Have you run mwinit recently?
Done, with errors. Using --debug may help diagnose issues.