Skip to content

Support for localisation/internationalisation (i18n) #1

@n0rdlicht

Description

@n0rdlicht

When authoring snapshots for bilingual regions (e.g. certain cities in Switzerland, Canada, South Africa etc.) it would be helpful to add support for multiple locale versions for any localisable content like titles and descriptions, legend entries etc. Even map content could have localised resources for different languages/regions.

Technical background

Matching localisations to application settings/user preferences should be based on the IETF propsed language tags, combining language codes defined by ISO 639-1 alpha-2 and region codes defined by ISO 3166-1 alpha-2 into a string separated by a hyphen. E.g. it-CH for Italian speaking regions Switzerland or fr-CA for french speaking regions in Canada or de for generic German version.

The relevant parts of a snapshot.view here are:

  • datapackage.view.spec.title
  • datapackage.view.spec.description
  • datapackage.view.spec.attribution
  • datapackage.view.spec.legend.label
  • datapackage.sources
  • datapackage.title
  • datapackage.description
  • datapackage.keywords
  • locale specific datapackage.resources

Option 1: Create fully distinct snapshot.view objects

One for each supported locale by adding a view.spec.locale key.

This will work with existing setups, since the first view can be considered the "fallback" and hence work as is. Conversely old snapshots will not break since no changes are needed, new versions can implement a check if locale keys are present and if yes matched to application settings.

This only works inside snapshot.views. Where implementations are using standard Data Package functionality (namely sources and resources) other options need to be used, making this approach heterogeneous at best and confusing for new users.

Example

...
"views": [
    {
        "name": "mapview",
        "specType": "gemeindescanSnapshot",
        "spec": {
            "locale": "en",
            "title": "Example Title EN",
            "description": "Example Description EN",
            "attribution": "Example Attribution EN",
            "bounds": ["geo:47.45236318,9.37245474", "geo:47.46902238,9.40338365"],
            "legend": [{
                "label": "Example Legend EN",
                "size": 1,
                "shape": "square",
                "primary": true,
                "fillColor": "#3eadc6",
                "fillOpacity": 0.35,
                "strokeColor": "#3eadc6",
                "strokeWidth": 2.0,
                "strokeOpacity": 1.0
            }]
        },
        "resources": ["res-1", "res-2", "res-3-en", "res-4-en", "mapbox-background-en"]
    },
    {
        "name": "mapview",
        "specType": "gemeindescanSnapshot",
        "spec": {
            "locale": "de",
            "title": "Beispiel Titel DE",
            "description": "Beispiel Beschreibung DE",
            "attribution": "Beispiel Attribution DE",
            "bounds": ["geo:47.45236318,9.37245474", "geo:47.46902238,9.40338365"],
            "legend": [{
                "label": "Beispiel Legende DE",
                "size": 1,
                "shape": "square",
                "primary": true,
                "fillColor": "#3eadc6",
                "fillOpacity": 0.35,
                "strokeColor": "#3eadc6",
                "strokeWidth": 2.0,
                "strokeOpacity": 1.0
            }]
        },
        "resources": ["res-1", "res-2", "res-3-de", "res-4-de", "mapbox-background-de"]
    },
    {
        "name": "mapview",
        "specType": "gemeindescanSnapshot",
        "spec": {
            "locale": "fr",
            "title": "Example de titre FR",
            "description": "Beispiel description FR",
            "attribution": "Beispiel d'attribution FR",
            "bounds": ["geo:47.45236318,9.37245474", "geo:47.46902238,9.40338365"],
            "legend": [{
                "label": "Beispiel de légende FR",
                "size": 1,
                "shape": "square",
                "primary": true,
                "fillColor": "#3eadc6",
                "fillOpacity": 0.35,
                "strokeColor": "#3eadc6",
                "strokeWidth": 2.0,
                "strokeOpacity": 1.0
            }]
        },
        "resources": ["res-1", "res-2", "res-3-fr", "res-4-fr", "mapbox-background-fr"]
    }
],
"sources": [{
    "defaultLocale": "en",
    "url": "https://www.openstreetmap.org/copyright",
    "title": "Map: Mapbox, \u00a9 OpenStreetMap",
    "i18n": [
        {
            "locale": "de",
            "url": "https://www.openstreetmap.org/copyright",
            "title": "Karte: Mapbox, \u00a9 OpenStreetMap"
        },
        {
            "locale": "ch",
            "url": "https://www.openstreetmap.org/copyright",
            "title": "Carte: Mapbox, \u00a9 OpenStreetMap"
        }
    ]
}],
...

Option 2: Inline localisation for relevant keys with an optional i18n dictionary

In this option a single snapshot.view, snapshot.sources etc. object would be kept, however each key that needs localisation can now have an additional entry inside an i18n object specifying localised versions replacing default strings where needed. If no localised string is provided the original (fallback) one is used.

Implementations without i18n support can simply ignore the additional i18n entries. Conversely when authoring a snapshot adding localisation is also optional since only the fallback entries would be used if no localised strings are available.

To replace default strings with localised ones the relevant structures and entries are reproduced inside an i18n dictionary.

The fallback language after matching locale keys can either be by convention (view with index 0) or an extra key, e.g. view.defaultLocale.

Example

...
"i18n": {
    "de-CH": {
        "view": [{
            "spec": {
                "title": "Beispiel Titel DE",
                "description": "Beispiel Beschreibung DE",
                "attribution": "Beispiel Attribution DE",
                "legend": [
                    {
                        "label": "Beispiel Legende DE"
                    }
                ]
            },
            "resources": ["res-1", "res-2", "res-3-de", "res-4-de", "mapbox-background-de"]
        }],
        "sources": [
            {
                "title": "Karte: Mapbox, \u00a9 OpenStreetMap"
            }
        ]
    },
    "fr-CH": {
        "view": [{
            "spec": {
                "title": "Example de titre FR",
                "description": "Example description FR",
                "attribution": "Example d'attribution FR",
                "legend": [
                    {
                        "label": "Example de légende FR"
                    }
                ]
            },
            "resources": ["res-1", "res-2", "res-3-fr", "res-4-fr", "mapbox-background-fr"]
        }],
        "sources": [
            {
                "title": "Carte: Mapbox, \u00a9 OpenStreetMap"
            }
        ]
    }
}
"views": [
    {
        "name": "mapview",
        "specType": "gemeindescanSnapshot",
        "defaultLocale": "en",
        "spec": {
            "title": "Example Title EN",
            "description": "Example Description EN",
            "attribution": "Example Attribution EN",
            "bounds": ["geo:47.45236318,9.37245474", "geo:47.46902238,9.40338365"],
            "legend": [{
                "label": "Example Legend EN",
                "size": 1,
                "shape": "square",
                "primary": true,
                "fillColor": "#3eadc6",
                "fillOpacity": 0.35,
                "strokeColor": "#3eadc6",
                "strokeWidth": 2.0,
                "strokeOpacity": 1.0
            }]
        },
        "resources": ["res-1", "res-2", "res-3-en", "res-4-en", "mapbox-background-en"]
    },
],
"sources": [{
    "url": "https://www.openstreetmap.org/copyright",
    "title": "Map: Mapbox, \u00a9 OpenStreetMap"
}]
...

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions