frintjs/frint

Proposal: frint-intl

Open

#385 opened on Dec 11, 2017

View on GitHub
 (5 comments) (0 reactions) (0 assignees)JavaScript (746 stars) (37 forks)batch import
help wantedproposal

Description

(Intended to be done outside of this repository)

Very much a work in progress, and needs to be refined further as more feedback keeps coming in.

Todo

  • Figure out culture
  • CLI usage

Background

To unify l10n/i18n usage in FrintJS Apps, a common API can be considered, instead of having different variations spread across multiple Child Apps.

Generic requirements

  • API to translate/localize labels (text blocks identified by keys) programmatically (just JS)
  • React components for embedding labels
  • Tool for finding unused/redundant labels in code base (that we can safely remove)

Proposed packages

The requirements can be handled by these proposed packages below.

The data structure for labels is expected to be like this:

import { createModel, createCollection, Types } from 'frint-data';

const Label = createModel({
  schema: {
    // unique ID
    name: Types.string, 

    // ICU Message Syntax
    value: Types.string, 
  },
});

const Labels = createCollection({
  model: Label,
});

Read more about ICU Message Syntax here: http://userguide.icu-project.org/formatparse/messages

frint-intl

Exports:

  • IntlService

Expected interface (nothing finalized of course):

class IntlService {
  constructor(options) {
    // options.data: Labels
  }

  format(key, ...formatWithData) {
    return String;
  }
}

frint-intl-react

React components for embedding at JSX level:

import React from 'react';
import { Format } from 'frint-intl-react';

function MyComponent(props) {
  const formatData = {
    brand: 'CTNL',
  };

  return (
    <div>
      <Format name="homepage.title" data={formatData} />
    </div>
  );
}

Or, format a custom ICU syntax message at component-level:

<Format message="ICU formatted text here..." />

frint-intl-cli

This will expose a $ frint intl subcommand in CLI, via which we can find out about unused labels in our code base:

$ frint intl find-unused-labels ./**/*.js --source allLabels.json

It will first load all the label names as available in allLabels.json file, and then execute a search in all JS files matching the pattern ./**/*.js. If there are any labels usage found that do no exist in allLabels.json, it will print line with file name and line number in console.

Usage

To set up your App:

import { createApp } from 'frint';
import { IntlService } from 'frint-intl';

const App = createApp({
  name: 'MyRootApp',
  providers: [
    {
      name: 'intl',
      useFactory() {
        return new IntlService({
          data: [
            { 
              name: 'homepage.title',
              value: 'Welcome to {{brand}}!',
            },
          ],
        });
      },
    },
  ],
});

In your component, now you can do:

import { Format } from 'frint-intl-react';

function () {
  return (
    <Format 
      name="homepage.title" 
      data={{brand: 'Foo'}} 
    />;
  );
}

Contributor guide