Skip to content

Internationalization Supporting in @fundamental ngx platform

Platon Rov edited this page Apr 12, 2021 · 3 revisions

Current Angular i18n support is mostly made for application layer. We have identified several approaches which enable us to support internationalization even on the library level. When creating new component please follow these guidelines.

Exposing library's static strings and default labels

Use with caution

  • Do not provide i18n markers in platform library unless there is an unavoidable use case. (For example, textarea’s counter has a counter message to show exceeded characters like 10 characters remaining which is tightly bound to platform library's implementation logic)

  • Even if you have such an unavoidable use-case, before taking this approach always consult this with others as we want this to be really last option.

Steps

In the case where some texts are being provided in the library itself, do the following:

  • Identify if the element to be marked with i18n is used as a default label (For example, radio buttons, checkboxes, select components can have a No Selection label other than the actual options; this label can be a default string provided in the lib or can come from the user).

  • If a default label is coming from the lib when user does not provide any custom label, i18n marker will be added in the lib(more in How It Works).

    The list of components currently identified(needs to be revisited) under this special case are:

    · Textarea
    · Datepicker(solution already in core)
    · File uploader
    · Upload collection
    · Pagination
    · Data table
    
  • If the label is coming from the user, then application user can prefix the i18n attribute with the input label and provide the label as a string binding like so:

<fdp-select 
    i18n-noSelectionLabel 
    noSelectionLabel="None Selected">
</fdp-select>

How it works

  • For static strings coming from the library, or for default strings like default labels for some components, such as:
    @Input()
    noSelectionLabel: string = 'None';

we provide the i18n marker in the usual way:

<fd-option
        i18n="@@noSelection"
        *ngIf="hasNoSelection"
        [disabled]="false"
        [value]="null"
        (selectedChange)="onSelection($event)">
        {{ noSelectionLabel }}
</fd-option>

Do notice that the strings being translated are static and are assumed to not change. This is the basis for creating a schematic.

  • When the i18n marker is added as shown above, we run the xi18n extraction tool that Angular provides as a command ng xi18n and these extracted files will be generated.

    The translations for these strings will be provided after getting it from the localization teams.

  • We then use schematics to automatically add these translated strings to the application bundle files so application developer does not need to worry about it.

    For the application developer, when he/she runs ng add @ngx/platform(or ng update) command, these translations will be automatically placed in the corresponding language files of the application’s own translation files.

Declarative approach

If not already following a declarative approach, modify design for existing components such that they can handle values being given both in code as an array of objects(or gets fetched through db/server), and as individual items through template, such as fdp-radio-group and individual fdp-radio-buttons. In the latter case, i18n support is provided by using markers in the normal fashion. In the former case, translated strings are expected from the backend db/server and therefore, no markers are provided.

Individual items:

i18n markers can be placed by application developers like shown below:

<fdp-radio-group
            [id]="'radio1'"
            [name]="'radio1'"
            [value]="'March'"
            [(ngModel)]="favoriteMonth">
            <fdp-radio-button i18n="@@jan" [value]="'January'" [disabled]="true">
                {{ 'January' }}
            </fdp-radio-button>
            <fdp-radio-button i18n="@@feb" [value]="'February'">
                {{ 'February' }}
            </fdp-radio-button>
            <fdp-radio-button i18n="@@march" [value]="'March'">
                {{ 'March' }}
            </fdp-radio-button>
            <fdp-radio-button i18n="@@april" [value]="'April'">
                {{ 'April' }}
            </fdp-radio-button>
</fdp-radio-group>

As a list(array of objects):

It is application team’s responsibility to pass translated values to the list. No i18n markers will be placed.

<fdp-radio-group
            [id]="'radio1'"
            [name]="'radio1'"
            [list]="seasons"
            [value]="'Summer'"
            formControlName="example1">
</fdp-radio-group>

Note: The decision on which components should take the declarative approach in terms of individual items vs an array of objects must happen on a per-component basis. For a component like List, we expect it to have any number of items, usually being populated from a backend db/server. In this case, we need to support both individual items and array of objects. But, for a component like Menu, we expect it to have a limited number of items which will be directly input from the user rather than coming from a backend. Here, providing support only for individual items is sufficient.

Components requiring design change(needs to be revisited):
· Shellbar
· Process Flow
· Select
· Combobox
· Multicombobox
· Datepicker
· Icon tabs
· List

Usage in Forms and associated components

For Forms, we can follow the approach currently present in platform library where we use i18Strings in fdp-form-group as an attribute and bind it to the associated ng-template's #i18n template reference and have the #i18n template reference contain the error messages in their respective <span>s where application users can give angular's i18n markers:

<fdp-form-group [i18Strings]="i18n">...Form group contents... </fdp-form-group>
<ng-template #i18n let-errros>
        <span i18n="@@required" *ngIf="errros && errros.required">
            Value is required
        </span>
        <span i18n="@@maxLen" *ngIf="errros && errros.maxlength">
            You reached maximum allowed length. Required is {{errros.maxlength.requiredLength}}
          current is
          {{errros.maxlength.actualLength}}
        </span>
</ng-template>

i18n markers

This is the default Angular solution, where we use i18n attribute to mark translatable content. Usually you use this solution if the component has internally too many labels to translate. This is usually done at the application level followed by the ng xi18n extraction command that extracts all i18n marked strings to files for translation.

Update as of 8th March, 2021:

Please note that for Angular10, running ng xi18n might throw some errors when run without the --ivy flag. And when run with the --ivy flag, ng xi18n will only process i18n markers at the application level, and not at the library level- angular-cli issue link.

To resolve this for the time being, run the command suggested in the link to extract the translation markers- node_modules/.bin/localize-extract -s "node_modules/**/*.js" -f xlf -o messages.xlf. Do note this does not merge with existing content, and instead overwrites it; so use this command with caution.


Select & Plural

Due to SAP needs using select & plural features of i18n is prohibited! When you need to implement such behavior create the construction like below and describe every possible select case, but keep things always in the plural (to do not produce large amount of code).

<!-- Suitable for 2 selects, use [ngSwitch] if there are more -->

<ng-container *ngIf="condition; else #elseTemplate" i18n="...">
    If condition is true...
</ng-container>

<ng-template #elseTemplate" i18n="...">
    If condition is false...
</ng-template>

Notes

From Sushma:

1).On behalf of bar is not part of fundamental-ngx so we can remove from this list.

  • Have removed obo and supplier chain from the list.

2). As discussed Menu the only declarative approach because of not holding 100 no.of items the same as the Action bar,Icon tabs.

  • I have not mentioned that Menu is the only one because I have not really gone over the tech spec/design of every component we will implement and in the future there might be a case where some other component also does not need to take both approaches like Menu. I think developers implementing components can still think about this aspect once they begin developing to confirm if they need both approaches according to their usecase.

3).For Forms validation can we have sample code attached which Frank presented it will help to understand the point? Same as how we have for declarative and imperative approaches here.

  • Have changed this. Please take a look. Have updated the example Frank showed and my understanding of its usage.

4).Can we have related title, Our blog is providing guidance for developers and users what exactly is happing. Ex: i18n Guidelines etc.(We can check with Manju, Manav, Frank on this.)

  • Discussed with Manju that i18n support is a decent title. We can discuss on this further if this is not good enough.

Rest looks good.

Manju

  1. Steps, 2nd point,
  • Is is 'label' or text/string value? If 'label' is the standard term, its fine.
  • text area does not have label. It only has counter message.
  • table, for now its good. I doubt if it has any lables. It may have tooltips, but that could be part of toolbar, filter bar.

There are two things: one is static string like textarea message or other strings we find in lib. Label is a subset of these static strings. For example, noSelectionLabel which is also a static string but used as per context where applicable, such as in radio button, select etc. Label word is specifically used for these components and I hope developers understand from the context of their tech design.

  1. How it works, bullet point 2, is the command 'ngx i18n' or 'ng xi8n' ?

The command to run the extraction tool is ng xi18n.

  1. For design reconsideration, following components as well could be included and let the component owners comeback and give their comments if its not otherwise: a) Support only individual items
  • Menu button
  • Split menu button
  • Menu
  • Check box group
  • Radio button group
  • Action list item
  • Segmented buttons
  • Toolbar (for list of action buttons)
  • Icon tabs
  • Panel (accordion variant)
  • Process flow(not sure if labels are static or values come from backend)

As I am working on the tech spec sections now, I have marked these component list points as (needs to be revisited). Support for individual items is sufficient for menu, icon tabs(which in turn uses overflow menu), so I don't think it needs to be counted in this list. RBG is supporting both individual items and array of objects. In this way, the other components also have to be revisited thoroughly. Since the list is not explicitly part of the PR, we can revise the document after the PR is pushed through as well, right?

b) Support for array

  • Combo box
  • Multi combobox
  • Menu button
  • Split menu button
  • Radio button group
  • Action item list
  • Segmented buttons
  • Toolbar
  • Icon tabs
  • Panel

Same comment as above. Also, does this list talk about components NOT supporting array, or the ones supporting it. Because from tech spec, I see combo box is supporting array(as well as individual items through ng-template), so I am confused what this list is pointing to.

Clone this wiki locally