GithubHelp home page GithubHelp logo

fusionjs / fusion-plugin-i18n Goto Github PK

View Code? Open in Web Editor NEW
2.0 7.0 17.0 729 KB

Migrated to https://github.com/fusionjs/fusionjs

License: MIT License

JavaScript 97.36% Shell 2.15% Dockerfile 0.49%
fusion fusionjs

fusion-plugin-i18n's Introduction

fusion-plugin-i18n

Build status

Adds I18n (Internationalization) string support to a Fusion.js app.

This plugin looks for translations in the ./translations folder by default. Translations for each language are expected to be in a JSON file with a locale as a filename. For example, for U.S. English, translations should be in ./translations/en-US.json. Language tags are dictated by your browser, and likely follow the RFC 5646 specification.

If you're using React, you should use fusion-plugin-i18n-react instead of this package.


Table of contents


Installation

yarn add fusion-plugin-i18n

Usage

Simple middleware

The plugin provides a programmatic interface which exposes translate. See Service API for more details.

// src/some-middleware-plugin.js
import {createPlugin} from 'fusion-core';

export default createPlugin({
  deps: {I18n: I18nToken},
  middleware: ({I18n}) => {
    return (ctx, next) => {
      if (__NODE__ && ctx.path === '/some-path') {
        const i18n = I18n.from(ctx);
        ctx.body = {
          message: i18n.translate('test', {name: 'world'}), // hello world
        };
      }
      return next();
    };
  },
});

The default loader expects translation files to live in ./translations/{locale}.

./translations/en-US.json

{
  "HomeHeader": "Welcome!",
  "Greeting": "Hello, ${name}"
}

./translations/pt-BR.json

{
  "HomeHeader": "Bem-vindo!",
  "Greeting": "Olá, ${name}"
}

Setup

// src/main.js
import App from 'fusion-core';
import I18n, {
  I18nToken,
  I18nLoaderToken,
  createI18nLoader,
} from 'fusion-plugin-i18n';
import {FetchToken} from 'fusion-tokens';
import fetch from 'unfetch';

export default () => {
  const app = new App(<div />);

  app.register(I18nToken, I18n);
  __NODE__
    ? app.register(I18nLoaderToken, createI18nLoader())
    : app.register(FetchToken, fetch);

  return app;
};

API

Registration API

I18n
import I18n from 'fusion-plugin-i18n-react';

The i18n plugin. Typically, it should be registered to I18nToken. Provides the i18n service

I18nToken
import {I18nToken} from 'fusion-plugin-i18n-react';

The canonical token for the I18n plugin. Typically, it should be registered with the I18n plugin.

Dependencies

I18nLoaderToken
import {I18nLoaderToken} from 'fusion-plugin-i18n';

A function that provides translations. Optional. Server-side only.

Type
type I18nLoader = {
  from: (ctx: Context) => {locale: string | Locale, translations: {[string]: string},
};
  • loader.from: (ctx) => ({locale, translations}) -
    • ctx: FusionContext - Required. A FusionJS context object.
    • locale: Locale - A Locale
    • translations: {[string]: string} - A object that maps translation keys to translated values for the given locale
Default value

If no loader is provided, the default loader will read translations from ./translations/{locale}.json. See src/loader.js for more details.

HydrationStateToken
import {HydrationStateToken} from 'fusion-plugin-i18n';

Sets the hydrated state in the client, and can be useful for testing purposes. Optional. Browser only.

Type
type HydrationState = {
  chunks: Array<string | number>,
  translations: {[string]: string},
};
Default value

If no hydration state is provided, this will be an empty object ({}) and have no effect.

FetchToken
import {FetchToken} from 'fusion-tokens';

A fetch implementation. Browser-only.

Type
type Fetch = (url: string, options: Object) => Promise<Response>;
  • url: string - Required. Path or URL to the resource you wish to fetch.
  • options: Object - Optional. You may optionally pass an init options object as the second argument. See Request for more details.
  • [return]: Promise<Request> - Return value from fetch. See [Response](A function that loads appropriate translations and locale information given an HTTP request context) for more details.
Default value

If no fetch implementation is provided, window.fetch is used.

Service API

const translation: string = i18n.translate(
  key: string,
  interpolations: {[string]: string}
);
  • key: string - A translation key. When using createI18nLoader, it refers to a object key in a translation json file.
  • interpolations: object - A object that maps an interpolation key to a value. For example, given a translation file {"foo": "${bar} world"}, the code i18n.translate('foo', {bar: 'hello'}) returns "hello world".
  • translation: string - A translation, or key if a matching translation could not be found.

Other examples

Custom translations loader example

// src/main.js
import App from 'fusion-core';
import I18n, {I18nToken, I18nLoaderToken} from 'fusion-plugin-i18n';
import {FetchToken} from 'fusion-tokens';
import fetch from 'unfetch';
import I18nLoader from './translations';

export default () => {
  const app = new App(<div></div>);

  app.register(I18nToken, I18n);
  __NODE__
    ? app.register(I18nLoaderToken, I18nLoader);
    : app.register(FetchToken, fetch);

  // ....

  return app;
}

// src/translation-loader.js
import {Locale} from 'locale';

const translationData = {
  'en_US': {
    test: "hello ${name}"
  }
}

export default (ctx) => {
  // locale could be determined in different ways,
  // e.g. from ctx.headers['accept-language'] or from a /en_US/ URL
  const locale = new Locale('en_US');
  const translations = translationData[locale];
  return {locale, translations};
}

Custom locale resolver

If you want to use the default loader, but want to provide a custom locale resolver, you can pass it into createI18nLoader

// src/main.js
import App from 'fusion-core';
import I18n, {createI18nLoader, I18nToken, I18nLoaderToken} from 'fusion-plugin-i18n';
import {FetchToken} from 'fusion-tokens';
import fetch from 'unfetch';

// use custom locale header instead of default
const myLocaleResolver = (ctx) => ctx.headers['my-locale-header'];

export default () => {
  const app = new App(<div></div>);

  app.register(I18nToken, I18n);
  __NODE__
    ? app.register(I18nLoaderToken, createI18nLoader(myLocaleResolver));
    : app.register(FetchToken, fetch);

  // ....

  return app;
}

fusion-plugin-i18n's People

Contributors

renovate[bot] avatar alexmsmithca avatar kevingrandon avatar ganemone avatar lhorie avatar rtsao avatar nadiia avatar uberopensourcebot avatar ksheedlo avatar rajeshsegu avatar angus-c avatar ratson avatar chrisrauh avatar kahwee avatar marceloadsj avatar renovate-bot avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar James Cloos avatar  avatar Derek Ju avatar  avatar Derek Ju avatar

fusion-plugin-i18n's Issues

Middleware should add html lang attribute

Type of issue

Feature Request

Description

We should probably have the i18n plugin add the lang attribute to the opening html tag, as it is recommended for accessibility. We can do this using ctx.template.htmlAttrs

Add Token dependencies to readme

Problem/Rationale

Documentation regarding Fusion API is out of date given recent changes to leverage new Dependency Injection architecture.

Solution/Change/Deliverable

Update documentation

Loader isn't loading non en-us translations

Type of issue

Bug

Description

Loader is trying to load en_au.json but the file is en-au.json

Current behavior

Translations aren't loaded

Expected behavior

Translations should be loaded

Steps to reproduce

  1. Use a non en-us locale

Your environment

  • fusion-plugin-i18n version: 1.0.2

  • Node.js version (node --version): 8.9.4

  • npm version (npm --version): 5.6.0

  • Operating System: OS X

Don't interpolate if interpolation value is not present.

Currently, a call to translate() will attempt to interpolate variables even if no interpolation values are provided returning a string interpolated with "undefined".

This result is unexpected and it would be preferable to return a string with the variables in it. Such string is useful when you want to interpolate the values somewhere else in the application.

For example:

translations: {interpolated: 'hi ${adjective} ${noun}'},

translate('interpolated', {adjective: 'big', noun: 'world'}) 
// 'hi big world'

translate('interpolated', {noun: 'world'}) 
// 'hi ${adjective} world'

translate('interpolated')
// 'hi ${adjective} ${noun}'

Client-side locale switching

Currently there's no mechanism for client-side locale switching, which means a page refresh is required to change locales.

Perhaps there should be an API for doing this client-side.

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Error type: Preset name not found within published preset config (monorepo:angularmaterial). Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.

Error in newer versions of Flow

I believe this occurs for 0.80 and greater. I'm using 0.82.

Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ node_modules/fusion-plugin-i18n/src/types.js:22:12

Cannot use function type as a type because function type is a value. To get the type of a value use typeof.

     19│ export type I18nDepsType = {
     20│   fetch?: typeof FetchToken.optional,
     21│   hydrationState?: typeof HydrationStateToken.optional,
     22│   loader?: I18nLoaderToken.optional,
     23│ };
     24│
     25│ export type I18nServiceType = {

Export the string interpolation function

Feature request

Export the string interpolation function for applications to use the same logic when interpolating strings externally.

We recently updated the interpolation logic to be able to pass interpolation variables through in order to interpolate externally. This is useful for interpolating dynamic values into translation strings. Because this use case happens mixed with internally interpolated translation strings, being able to use the exact same logic in both places would help guarantee consistency of outcomes.

Related, if the plugin architecture or performance considerations allow, it would be easier to maintain the code and internal consistency if we extract the translation function from browser and node implementation into its own file and re-use that.

Would like to hear any concerns, specially on the architectural or performance constraints to extract the translation function. Based on those, I am happy to contribute the update.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.