Skip to content

RFC: Add State Module to options.config to enable multilingual routes #55

@cloudmark

Description

@cloudmark

We want to support multilingual urls and hence we want to defer the url to state binding to be done at runtime rather than being performed statically. Imagine we have a sitemap service which retrieves the urls per states e.g.:

{
    'en': [
      {'module': 'app.home', 'path': ''},
      {'module': 'app.about', 'path': '/about'},
    ],
    'sv': [
      {'module': 'app.home', 'path': ''},
      {'module': 'app.about', 'path': '/om'}
    ]
  }

we want to wire the state app.home and app.about to /en and /en/about when the language is en and '/sv' and '/sv/om' when the language is '/sv'.

Looking at UIRouter.forRoot or UIRouter.forChild there is a options.config which could allow us to enable this behaviour which is called from the applyModuleConfig method:

function applyModuleConfig(uiRouter, injector, options) {
    if (options === void 0) { options = {}; }
    if (isFunction(options.config)) {
        options.config(uiRouter, injector);
    }
    var states = options.states || [];
    states.forEach(function (state) { return uiRouter.stateRegistry.register(state); });
}

What is stopping us from using this hook is the fact that options.config only takes uiRouter and injector as arguments.

Adding options (module) as a third parameter will allow us to achieve deferred route configuration.

export function applyModuleConfig(uiRouter: UIRouter, injector: Injector, options: StatesModule = {}) {
  if (isFunction(options.config)) {
    options.config(uiRouter, injector, options);
  }

  let states = options.states || [];
  states.forEach(state => uiRouter.stateRegistry.register(state));
}

Example

As an example of how this would work have a look at the ui-router-multilingual project

To run the project:

npm install
npm start.deving

Open the browser and goto http://localhost:5555/en and hover on the links HOME and ABOUT.

  • HOME should point to /en/
  • ABOUT should point to /en/about

Open the browser and goto http://localhost:5555/sv and hover on the links HOME and ABOUT.

  • HOME should point to /sv/
  • ABOUT should point to /sv/om

Opening directly the link http://localhost:5555/ will default to english.

To configure multilingual modules we would setup the forChild and forRoot we would add the uiRouterConfigureSitemap config function e.g.

@NgModule({
  imports: [CommonModule,
    UIRouterModule.forChild({
      states:CHILD_STATES,
      config: uiRouterConfigureSitemap
    })],
  declarations: [AboutComponent],
  exports: [AboutComponent]
})
export class AboutModule {
}

The config function is simple:

export function uiRouterConfigureSitemap(router: UIRouter, injector: Injector, module: StatesModule) {
  let states: ExtNg2StateDeclaration[] = <ExtNg2StateDeclaration[]>module.states;

  // Process the states;
  let filteredStates: ExtNg2StateDeclaration[] = _.filter(states, (s) => {
    return s.future && !s._complete
  });

  _.map(filteredStates, (s) => {
    let sitemapObj:any = _.find(getSitemap(), (sitemap:any) => sitemap.module == s.name);
    console.log(`Retrieved ${s.name} from sitemap ${sitemapObj.path}`);
    // Set the url from the sitemap object
    s.url = sitemapObj.path;
    s._complete = true;
  });
  router.urlService.config.strictMode(false);
}

Note that ui-router-ng2 is committed. node_modules/ui-router-ng2 includes the changes proposed in the Pull Request.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions