From 0a6399bf7f9ce5fb72e45593ce06e961849a1b0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Prod=27homme?= Date: Thu, 13 Jun 2024 14:31:44 +0200 Subject: [PATCH 01/14] Minimum code for i18n --- cms/config/sync/admin-role.strapi-author.json | 277 +++++++++++++----- cms/config/sync/admin-role.strapi-editor.json | 193 +++++++++++- ...ntent_types##api##data-info.data-info.json | 2 +- ...ntent_types##api##data-tool.data-tool.json | 8 +- ...iguration_content_types##api##mpa.mpa.json | 52 ++-- ...pi##static-indicator.static-indicator.json | 18 +- cms/config/sync/user-role.public.json | 135 --------- frontend/.gitignore | 4 + frontend/.vscode/settings.json | 3 + frontend/local.d.ts | 2 +- frontend/next.config.js | 4 + frontend/package.json | 1 + frontend/src/components/header.tsx | 2 +- .../components/static-pages/intro/index.tsx | 2 +- .../containers/about/questions-list/index.tsx | 2 +- .../src/containers/homepage/intro/index.tsx | 2 +- .../homepage/link-cards/link-card/index.tsx | 2 +- .../card-list/card-item/index.tsx | 6 +- .../containers/map/content/details/index.tsx | 2 +- .../tables/national-highseas/useColumns.tsx | 8 +- .../map/content/map/layers-toolbox/index.tsx | 2 +- .../map/layers-toolbox/legend/eez/index.tsx | 8 +- .../legend/establishment/index.tsx | 8 +- .../map/layers-toolbox/legend/index.tsx | 8 +- .../map/layers-toolbox/legend/item.tsx | 10 +- .../map/content/map/popup/eez/index.tsx | 3 +- .../map/content/map/popup/index.tsx | 2 +- .../map/popup/protected-area/index.tsx | 2 + frontend/src/containers/map/sidebar/index.tsx | 2 +- frontend/src/layouts/static-page.tsx | 2 +- frontend/src/pages/_app.tsx | 26 +- frontend/src/types/index.d.ts | 2 +- frontend/translations/en.json | 1 + frontend/yarn.lock | 107 +++++++ 34 files changed, 599 insertions(+), 309 deletions(-) create mode 100644 frontend/.vscode/settings.json create mode 100644 frontend/translations/en.json diff --git a/cms/config/sync/admin-role.strapi-author.json b/cms/config/sync/admin-role.strapi-author.json index 8c25e6f1..b57830c7 100644 --- a/cms/config/sync/admin-role.strapi-author.json +++ b/cms/config/sync/admin-role.strapi-author.json @@ -16,21 +16,18 @@ "registration" ] }, - "conditions": [] + "conditions": [ + "admin::is-creator" + ] }, { "action": "plugin::content-manager.explorer.delete", "actionParameters": {}, "subject": "api::contact-detail.contact-detail", "properties": {}, - "conditions": [] - }, - { - "action": "plugin::content-manager.explorer.publish", - "actionParameters": {}, - "subject": "api::contact-detail.contact-detail", - "properties": {}, - "conditions": [] + "conditions": [ + "admin::is-creator" + ] }, { "action": "plugin::content-manager.explorer.read", @@ -45,7 +42,9 @@ "registration" ] }, - "conditions": [] + "conditions": [ + "admin::is-creator" + ] }, { "action": "plugin::content-manager.explorer.update", @@ -60,7 +59,9 @@ "registration" ] }, - "conditions": [] + "conditions": [ + "admin::is-creator" + ] }, { "action": "plugin::content-manager.explorer.create", @@ -192,15 +193,6 @@ "admin::is-creator" ] }, - { - "action": "plugin::content-manager.explorer.publish", - "actionParameters": {}, - "subject": "api::data-tool-ecosystem.data-tool-ecosystem", - "properties": {}, - "conditions": [ - "admin::is-creator" - ] - }, { "action": "plugin::content-manager.explorer.read", "actionParameters": {}, @@ -251,15 +243,6 @@ "admin::is-creator" ] }, - { - "action": "plugin::content-manager.explorer.publish", - "actionParameters": {}, - "subject": "api::data-tool-language.data-tool-language", - "properties": {}, - "conditions": [ - "admin::is-creator" - ] - }, { "action": "plugin::content-manager.explorer.read", "actionParameters": {}, @@ -312,15 +295,6 @@ "admin::is-creator" ] }, - { - "action": "plugin::content-manager.explorer.publish", - "actionParameters": {}, - "subject": "api::data-tool-resource-type.data-tool-resource-type", - "properties": {}, - "conditions": [ - "admin::is-creator" - ] - }, { "action": "plugin::content-manager.explorer.read", "actionParameters": {}, @@ -357,6 +331,7 @@ "description", "site", "languages", + "data_tool_resource_types", "geography", "data_tool_ecosystems" ] @@ -374,15 +349,6 @@ "admin::is-creator" ] }, - { - "action": "plugin::content-manager.explorer.publish", - "actionParameters": {}, - "subject": "api::data-tool.data-tool", - "properties": {}, - "conditions": [ - "admin::is-creator" - ] - }, { "action": "plugin::content-manager.explorer.read", "actionParameters": {}, @@ -393,6 +359,7 @@ "description", "site", "languages", + "data_tool_resource_types", "geography", "data_tool_ecosystems" ] @@ -411,6 +378,7 @@ "description", "site", "languages", + "data_tool_resource_types", "geography", "data_tool_ecosystems" ] @@ -419,6 +387,57 @@ "admin::is-creator" ] }, + { + "action": "plugin::content-manager.explorer.create", + "actionParameters": {}, + "subject": "api::dataset.dataset", + "properties": { + "fields": [ + "name", + "layers" + ] + }, + "conditions": [ + "admin::is-creator" + ] + }, + { + "action": "plugin::content-manager.explorer.delete", + "actionParameters": {}, + "subject": "api::dataset.dataset", + "properties": {}, + "conditions": [ + "admin::is-creator" + ] + }, + { + "action": "plugin::content-manager.explorer.read", + "actionParameters": {}, + "subject": "api::dataset.dataset", + "properties": { + "fields": [ + "name", + "layers" + ] + }, + "conditions": [ + "admin::is-creator" + ] + }, + { + "action": "plugin::content-manager.explorer.update", + "actionParameters": {}, + "subject": "api::dataset.dataset", + "properties": { + "fields": [ + "name", + "layers" + ] + }, + "conditions": [ + "admin::is-creator" + ] + }, { "action": "plugin::content-manager.explorer.create", "actionParameters": {}, @@ -641,6 +660,90 @@ "admin::is-creator" ] }, + { + "action": "plugin::content-manager.explorer.create", + "actionParameters": {}, + "subject": "api::layer.layer", + "properties": { + "fields": [ + "title", + "type", + "config", + "params_config", + "legend_config", + "interaction_config", + "metadata.description", + "metadata.citation", + "metadata.source", + "metadata.resolution", + "metadata.content_date", + "metadata.license", + "dataset" + ] + }, + "conditions": [ + "admin::is-creator" + ] + }, + { + "action": "plugin::content-manager.explorer.delete", + "actionParameters": {}, + "subject": "api::layer.layer", + "properties": {}, + "conditions": [ + "admin::is-creator" + ] + }, + { + "action": "plugin::content-manager.explorer.read", + "actionParameters": {}, + "subject": "api::layer.layer", + "properties": { + "fields": [ + "title", + "type", + "config", + "params_config", + "legend_config", + "interaction_config", + "metadata.description", + "metadata.citation", + "metadata.source", + "metadata.resolution", + "metadata.content_date", + "metadata.license", + "dataset" + ] + }, + "conditions": [ + "admin::is-creator" + ] + }, + { + "action": "plugin::content-manager.explorer.update", + "actionParameters": {}, + "subject": "api::layer.layer", + "properties": { + "fields": [ + "title", + "type", + "config", + "params_config", + "legend_config", + "interaction_config", + "metadata.description", + "metadata.citation", + "metadata.source", + "metadata.resolution", + "metadata.content_date", + "metadata.license", + "dataset" + ] + }, + "conditions": [ + "admin::is-creator" + ] + }, { "action": "plugin::content-manager.explorer.create", "actionParameters": {}, @@ -652,7 +755,11 @@ "totalMarineArea", "type", "groups", - "members" + "members", + "fishing_protection_level_stats", + "mpaa_protection_level_stats", + "protection_coverage_stats", + "bounds" ] }, "conditions": [ @@ -679,7 +786,11 @@ "totalMarineArea", "type", "groups", - "members" + "members", + "fishing_protection_level_stats", + "mpaa_protection_level_stats", + "protection_coverage_stats", + "bounds" ] }, "conditions": [ @@ -697,7 +808,11 @@ "totalMarineArea", "type", "groups", - "members" + "members", + "fishing_protection_level_stats", + "mpaa_protection_level_stats", + "protection_coverage_stats", + "bounds" ] }, "conditions": [ @@ -714,7 +829,8 @@ "fishing_protection_level", "mpaa_protection_level", "location", - "area" + "area", + "mpaa_establishment_stage" ] }, "conditions": [ @@ -740,7 +856,8 @@ "fishing_protection_level", "mpaa_protection_level", "location", - "area" + "area", + "mpaa_establishment_stage" ] }, "conditions": [ @@ -757,7 +874,8 @@ "fishing_protection_level", "mpaa_protection_level", "location", - "area" + "area", + "mpaa_establishment_stage" ] }, "conditions": [ @@ -770,9 +888,12 @@ "subject": "api::mpa.mpa", "properties": { "fields": [ - "wdpaid", "name", - "area" + "area", + "year", + "protection_status", + "mpa_protection_coverage_stats", + "wdpaid" ] }, "conditions": [ @@ -794,9 +915,12 @@ "subject": "api::mpa.mpa", "properties": { "fields": [ - "wdpaid", "name", - "area" + "area", + "year", + "protection_status", + "mpa_protection_coverage_stats", + "wdpaid" ] }, "conditions": [ @@ -809,9 +933,12 @@ "subject": "api::mpa.mpa", "properties": { "fields": [ - "wdpaid", "name", - "area" + "area", + "year", + "protection_status", + "mpa_protection_coverage_stats", + "wdpaid" ] }, "conditions": [ @@ -886,7 +1013,8 @@ "fields": [ "slug", "name", - "info" + "info", + "mpa_protection_coverage_stats" ] }, "conditions": [ @@ -910,7 +1038,8 @@ "fields": [ "slug", "name", - "info" + "info", + "mpa_protection_coverage_stats" ] }, "conditions": [ @@ -925,7 +1054,8 @@ "fields": [ "slug", "name", - "info" + "info", + "mpa_protection_coverage_stats" ] }, "conditions": [ @@ -1169,21 +1299,18 @@ "description" ] }, - "conditions": [] + "conditions": [ + "admin::is-creator" + ] }, { "action": "plugin::content-manager.explorer.delete", "actionParameters": {}, "subject": "api::static-indicator.static-indicator", "properties": {}, - "conditions": [] - }, - { - "action": "plugin::content-manager.explorer.publish", - "actionParameters": {}, - "subject": "api::static-indicator.static-indicator", - "properties": {}, - "conditions": [] + "conditions": [ + "admin::is-creator" + ] }, { "action": "plugin::content-manager.explorer.read", @@ -1197,7 +1324,9 @@ "description" ] }, - "conditions": [] + "conditions": [ + "admin::is-creator" + ] }, { "action": "plugin::content-manager.explorer.update", @@ -1211,7 +1340,9 @@ "description" ] }, - "conditions": [] + "conditions": [ + "admin::is-creator" + ] }, { "action": "plugin::upload.assets.copy-link", diff --git a/cms/config/sync/admin-role.strapi-editor.json b/cms/config/sync/admin-role.strapi-editor.json index 08b7d809..3c181452 100644 --- a/cms/config/sync/admin-role.strapi-editor.json +++ b/cms/config/sync/admin-role.strapi-editor.json @@ -311,6 +311,7 @@ "description", "site", "languages", + "data_tool_resource_types", "geography", "data_tool_ecosystems" ] @@ -341,6 +342,7 @@ "description", "site", "languages", + "data_tool_resource_types", "geography", "data_tool_ecosystems" ] @@ -357,12 +359,63 @@ "description", "site", "languages", + "data_tool_resource_types", "geography", "data_tool_ecosystems" ] }, "conditions": [] }, + { + "action": "plugin::content-manager.explorer.create", + "actionParameters": {}, + "subject": "api::dataset.dataset", + "properties": { + "fields": [ + "name", + "layers" + ] + }, + "conditions": [] + }, + { + "action": "plugin::content-manager.explorer.delete", + "actionParameters": {}, + "subject": "api::dataset.dataset", + "properties": {}, + "conditions": [] + }, + { + "action": "plugin::content-manager.explorer.publish", + "actionParameters": {}, + "subject": "api::dataset.dataset", + "properties": {}, + "conditions": [] + }, + { + "action": "plugin::content-manager.explorer.read", + "actionParameters": {}, + "subject": "api::dataset.dataset", + "properties": { + "fields": [ + "name", + "layers" + ] + }, + "conditions": [] + }, + { + "action": "plugin::content-manager.explorer.update", + "actionParameters": {}, + "subject": "api::dataset.dataset", + "properties": { + "fields": [ + "name", + "layers" + ] + }, + "conditions": [] + }, { "action": "plugin::content-manager.explorer.create", "actionParameters": {}, @@ -553,6 +606,89 @@ }, "conditions": [] }, + { + "action": "plugin::content-manager.explorer.create", + "actionParameters": {}, + "subject": "api::layer.layer", + "properties": { + "fields": [ + "title", + "type", + "config", + "params_config", + "legend_config", + "interaction_config", + "metadata.description", + "metadata.citation", + "metadata.source", + "metadata.resolution", + "metadata.content_date", + "metadata.license", + "dataset" + ] + }, + "conditions": [] + }, + { + "action": "plugin::content-manager.explorer.delete", + "actionParameters": {}, + "subject": "api::layer.layer", + "properties": {}, + "conditions": [] + }, + { + "action": "plugin::content-manager.explorer.publish", + "actionParameters": {}, + "subject": "api::layer.layer", + "properties": {}, + "conditions": [] + }, + { + "action": "plugin::content-manager.explorer.read", + "actionParameters": {}, + "subject": "api::layer.layer", + "properties": { + "fields": [ + "title", + "type", + "config", + "params_config", + "legend_config", + "interaction_config", + "metadata.description", + "metadata.citation", + "metadata.source", + "metadata.resolution", + "metadata.content_date", + "metadata.license", + "dataset" + ] + }, + "conditions": [] + }, + { + "action": "plugin::content-manager.explorer.update", + "actionParameters": {}, + "subject": "api::layer.layer", + "properties": { + "fields": [ + "title", + "type", + "config", + "params_config", + "legend_config", + "interaction_config", + "metadata.description", + "metadata.citation", + "metadata.source", + "metadata.resolution", + "metadata.content_date", + "metadata.license", + "dataset" + ] + }, + "conditions": [] + }, { "action": "plugin::content-manager.explorer.create", "actionParameters": {}, @@ -564,7 +700,11 @@ "totalMarineArea", "type", "groups", - "members" + "members", + "fishing_protection_level_stats", + "mpaa_protection_level_stats", + "protection_coverage_stats", + "bounds" ] }, "conditions": [] @@ -587,7 +727,11 @@ "totalMarineArea", "type", "groups", - "members" + "members", + "fishing_protection_level_stats", + "mpaa_protection_level_stats", + "protection_coverage_stats", + "bounds" ] }, "conditions": [] @@ -603,7 +747,11 @@ "totalMarineArea", "type", "groups", - "members" + "members", + "fishing_protection_level_stats", + "mpaa_protection_level_stats", + "protection_coverage_stats", + "bounds" ] }, "conditions": [] @@ -618,7 +766,8 @@ "fishing_protection_level", "mpaa_protection_level", "location", - "area" + "area", + "mpaa_establishment_stage" ] }, "conditions": [] @@ -640,7 +789,8 @@ "fishing_protection_level", "mpaa_protection_level", "location", - "area" + "area", + "mpaa_establishment_stage" ] }, "conditions": [] @@ -655,7 +805,8 @@ "fishing_protection_level", "mpaa_protection_level", "location", - "area" + "area", + "mpaa_establishment_stage" ] }, "conditions": [] @@ -666,9 +817,12 @@ "subject": "api::mpa.mpa", "properties": { "fields": [ - "wdpaid", "name", - "area" + "area", + "year", + "protection_status", + "mpa_protection_coverage_stats", + "wdpaid" ] }, "conditions": [] @@ -686,9 +840,12 @@ "subject": "api::mpa.mpa", "properties": { "fields": [ - "wdpaid", "name", - "area" + "area", + "year", + "protection_status", + "mpa_protection_coverage_stats", + "wdpaid" ] }, "conditions": [] @@ -699,9 +856,12 @@ "subject": "api::mpa.mpa", "properties": { "fields": [ - "wdpaid", "name", - "area" + "area", + "year", + "protection_status", + "mpa_protection_coverage_stats", + "wdpaid" ] }, "conditions": [] @@ -766,7 +926,8 @@ "fields": [ "slug", "name", - "info" + "info", + "mpa_protection_coverage_stats" ] }, "conditions": [] @@ -786,7 +947,8 @@ "fields": [ "slug", "name", - "info" + "info", + "mpa_protection_coverage_stats" ] }, "conditions": [] @@ -799,7 +961,8 @@ "fields": [ "slug", "name", - "info" + "info", + "mpa_protection_coverage_stats" ] }, "conditions": [] diff --git a/cms/config/sync/core-store.plugin_content_manager_configuration_content_types##api##data-info.data-info.json b/cms/config/sync/core-store.plugin_content_manager_configuration_content_types##api##data-info.data-info.json index 6f8569ab..f660ff84 100644 --- a/cms/config/sync/core-store.plugin_content_manager_configuration_content_types##api##data-info.data-info.json +++ b/cms/config/sync/core-store.plugin_content_manager_configuration_content_types##api##data-info.data-info.json @@ -127,7 +127,7 @@ "id", "slug", "content", - "createdAt" + "data_sources" ], "edit": [ [ diff --git a/cms/config/sync/core-store.plugin_content_manager_configuration_content_types##api##data-tool.data-tool.json b/cms/config/sync/core-store.plugin_content_manager_configuration_content_types##api##data-tool.data-tool.json index 0cc4e812..561ef49f 100644 --- a/cms/config/sync/core-store.plugin_content_manager_configuration_content_types##api##data-tool.data-tool.json +++ b/cms/config/sync/core-store.plugin_content_manager_configuration_content_types##api##data-tool.data-tool.json @@ -209,6 +209,10 @@ } ], [ + { + "name": "data_tool_resource_types", + "size": 6 + }, { "name": "geography", "size": 6 @@ -218,10 +222,6 @@ { "name": "data_tool_ecosystems", "size": 6 - }, - { - "name": "data_tool_resource_types", - "size": 6 } ] ] diff --git a/cms/config/sync/core-store.plugin_content_manager_configuration_content_types##api##mpa.mpa.json b/cms/config/sync/core-store.plugin_content_manager_configuration_content_types##api##mpa.mpa.json index 04513a89..64f8697c 100644 --- a/cms/config/sync/core-store.plugin_content_manager_configuration_content_types##api##mpa.mpa.json +++ b/cms/config/sync/core-store.plugin_content_manager_configuration_content_types##api##mpa.mpa.json @@ -20,20 +20,6 @@ "sortable": true } }, - "wdpaid": { - "edit": { - "label": "wdpaid", - "description": "", - "placeholder": "", - "visible": true, - "editable": true - }, - "list": { - "label": "wdpaid", - "searchable": true, - "sortable": true - } - }, "name": { "edit": { "label": "name", @@ -106,6 +92,20 @@ "sortable": false } }, + "wdpaid": { + "edit": { + "label": "wdpaid", + "description": "", + "placeholder": "", + "visible": true, + "editable": true + }, + "list": { + "label": "wdpaid", + "searchable": true, + "sortable": true + } + }, "createdAt": { "edit": { "label": "createdAt", @@ -168,32 +168,26 @@ "layouts": { "list": [ "id", - "wdpaid", "name", - "area" + "area", + "year" ], "edit": [ [ - { - "name": "wdpaid", - "size": 4 - }, { "name": "name", "size": 6 - } - ], - [ - { - "name": "area", - "size": 4 }, { - "name": "year", + "name": "area", "size": 4 } ], [ + { + "name": "year", + "size": 4 + }, { "name": "protection_status", "size": 6 @@ -203,6 +197,10 @@ { "name": "mpa_protection_coverage_stats", "size": 6 + }, + { + "name": "wdpaid", + "size": 6 } ] ] diff --git a/cms/config/sync/core-store.plugin_content_manager_configuration_content_types##api##static-indicator.static-indicator.json b/cms/config/sync/core-store.plugin_content_manager_configuration_content_types##api##static-indicator.static-indicator.json index fc2eeb77..3eec1dd0 100644 --- a/cms/config/sync/core-store.plugin_content_manager_configuration_content_types##api##static-indicator.static-indicator.json +++ b/cms/config/sync/core-store.plugin_content_manager_configuration_content_types##api##static-indicator.static-indicator.json @@ -136,6 +136,12 @@ } }, "layouts": { + "list": [ + "id", + "slug", + "source", + "value" + ], "edit": [ [ { @@ -143,26 +149,20 @@ "size": 6 }, { - "name": "value", + "name": "source", "size": 6 } ], [ { - "name": "description", + "name": "value", "size": 6 }, { - "name": "source", + "name": "description", "size": 6 } ] - ], - "list": [ - "id", - "slug", - "source", - "value" ] } }, diff --git a/cms/config/sync/user-role.public.json b/cms/config/sync/user-role.public.json index 16f8a9fe..57b76cd7 100644 --- a/cms/config/sync/user-role.public.json +++ b/cms/config/sync/user-role.public.json @@ -3,141 +3,6 @@ "description": "Default role given to unauthenticated user.", "type": "public", "permissions": [ - { - "action": "api::contact-detail.contact-detail.find" - }, - { - "action": "api::data-info.data-info.find" - }, - { - "action": "api::data-info.data-info.findOne" - }, - { - "action": "api::data-source.data-source.find" - }, - { - "action": "api::data-source.data-source.findOne" - }, - { - "action": "api::data-tool-ecosystem.data-tool-ecosystem.find" - }, - { - "action": "api::data-tool-ecosystem.data-tool-ecosystem.findOne" - }, - { - "action": "api::data-tool-language.data-tool-language.find" - }, - { - "action": "api::data-tool-language.data-tool-language.findOne" - }, - { - "action": "api::data-tool-resource-type.data-tool-resource-type.find" - }, - { - "action": "api::data-tool-resource-type.data-tool-resource-type.findOne" - }, - { - "action": "api::data-tool.data-tool.find" - }, - { - "action": "api::data-tool.data-tool.findOne" - }, - { - "action": "api::dataset.dataset.find" - }, - { - "action": "api::dataset.dataset.findOne" - }, - { - "action": "api::fishing-protection-level-stat.fishing-protection-level-stat.find" - }, - { - "action": "api::fishing-protection-level-stat.fishing-protection-level-stat.findOne" - }, - { - "action": "api::fishing-protection-level.fishing-protection-level.find" - }, - { - "action": "api::fishing-protection-level.fishing-protection-level.findOne" - }, - { - "action": "api::habitat-stat.habitat-stat.find" - }, - { - "action": "api::habitat-stat.habitat-stat.findOne" - }, - { - "action": "api::habitat.habitat.find" - }, - { - "action": "api::habitat.habitat.findOne" - }, - { - "action": "api::layer.layer.find" - }, - { - "action": "api::layer.layer.findOne" - }, - { - "action": "api::location.location.find" - }, - { - "action": "api::location.location.findOne" - }, - { - "action": "api::mpa-protection-coverage-stat.mpa-protection-coverage-stat.find" - }, - { - "action": "api::mpa-protection-coverage-stat.mpa-protection-coverage-stat.findOne" - }, - { - "action": "api::mpa.mpa.find" - }, - { - "action": "api::mpa.mpa.findOne" - }, - { - "action": "api::mpaa-establishment-stage-stat.mpaa-establishment-stage-stat.find" - }, - { - "action": "api::mpaa-establishment-stage-stat.mpaa-establishment-stage-stat.findOne" - }, - { - "action": "api::mpaa-establishment-stage.mpaa-establishment-stage.find" - }, - { - "action": "api::mpaa-establishment-stage.mpaa-establishment-stage.findOne" - }, - { - "action": "api::mpaa-protection-level-stat.mpaa-protection-level-stat.find" - }, - { - "action": "api::mpaa-protection-level-stat.mpaa-protection-level-stat.findOne" - }, - { - "action": "api::mpaa-protection-level.mpaa-protection-level.find" - }, - { - "action": "api::mpaa-protection-level.mpaa-protection-level.findOne" - }, - { - "action": "api::protection-coverage-stat.protection-coverage-stat.find" - }, - { - "action": "api::protection-coverage-stat.protection-coverage-stat.findOne" - }, - { - "action": "api::protection-status.protection-status.find" - }, - { - "action": "api::protection-status.protection-status.findOne" - }, - { - "action": "api::static-indicator.static-indicator.find" - }, - { - "action": "api::static-indicator.static-indicator.findOne" - }, { "action": "plugin::users-permissions.auth.callback" }, diff --git a/frontend/.gitignore b/frontend/.gitignore index 356ba76f..63a6a82e 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -45,3 +45,7 @@ tsconfig.tsbuildinfo # storybook /storybook-static/ + +# translations +translations/* +!translations/en.json diff --git a/frontend/.vscode/settings.json b/frontend/.vscode/settings.json new file mode 100644 index 00000000..c164d719 --- /dev/null +++ b/frontend/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "i18n-ally.localesPaths": ["translations"] +} diff --git a/frontend/local.d.ts b/frontend/local.d.ts index 94805f21..d44e4adc 100644 --- a/frontend/local.d.ts +++ b/frontend/local.d.ts @@ -1,5 +1,5 @@ declare module '*.svg'; -declare module '*.svg?sprite' { +declare module '*.svg' { const content: { id: string; viewBox: string; diff --git a/frontend/next.config.js b/frontend/next.config.js index eea9bd9f..d239f25b 100644 --- a/frontend/next.config.js +++ b/frontend/next.config.js @@ -47,6 +47,10 @@ const nextConfig = { }, ]; }, + i18n: { + locales: ['en', 'es', 'fr'], + defaultLocale: 'en', + }, }; module.exports = nextConfig; diff --git a/frontend/package.json b/frontend/package.json index b7c56bf3..ce556529 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -60,6 +60,7 @@ "mapbox-gl": "3.1.2", "next": "13.5.6", "next-auth": "^4.24.7", + "next-intl": "^3.15.0", "next-usequerystate": "1.9.2", "orval": "6.18.1", "postcss": "8.4.21", diff --git a/frontend/src/components/header.tsx b/frontend/src/components/header.tsx index 3a9d8b71..3f921d1e 100644 --- a/frontend/src/components/header.tsx +++ b/frontend/src/components/header.tsx @@ -24,7 +24,7 @@ import { useSyncMapSettings, } from '@/containers/map/content/map/sync-settings'; import { cn } from '@/lib/classnames'; -import ArrowRight from '@/styles/icons/arrow-right.svg?sprite'; +import ArrowRight from '@/styles/icons/arrow-right.svg'; const NAVIGATION_ITEMS = [ { diff --git a/frontend/src/components/static-pages/intro/index.tsx b/frontend/src/components/static-pages/intro/index.tsx index 68796eca..6687905c 100644 --- a/frontend/src/components/static-pages/intro/index.tsx +++ b/frontend/src/components/static-pages/intro/index.tsx @@ -4,7 +4,7 @@ import { VariantProps, cva } from 'class-variance-authority'; import Icon from '@/components/ui/icon'; import { cn } from '@/lib/classnames'; -import ArrowRight from '@/styles/icons/arrow-right.svg?sprite'; +import ArrowRight from '@/styles/icons/arrow-right.svg'; const BACKGROUND_IMAGES = { computer: '/images/static-pages/bg-images/card-1.png', diff --git a/frontend/src/containers/about/questions-list/index.tsx b/frontend/src/containers/about/questions-list/index.tsx index 3e022d12..be804fb8 100644 --- a/frontend/src/containers/about/questions-list/index.tsx +++ b/frontend/src/containers/about/questions-list/index.tsx @@ -2,7 +2,7 @@ import { cva, VariantProps } from 'class-variance-authority'; import Icon from '@/components/ui/icon'; import { cn } from '@/lib/classnames'; -import ArrowRight from '@/styles/icons/arrow-right.svg?sprite'; +import ArrowRight from '@/styles/icons/arrow-right.svg'; const questionsListVariants = cva('', { variants: { diff --git a/frontend/src/containers/homepage/intro/index.tsx b/frontend/src/containers/homepage/intro/index.tsx index f9254cd3..1b03293c 100644 --- a/frontend/src/containers/homepage/intro/index.tsx +++ b/frontend/src/containers/homepage/intro/index.tsx @@ -5,7 +5,7 @@ import Image from 'next/image'; import Icon from '@/components/ui/icon'; import SidebarItem from '@/containers/homepage/intro/sidebar-item'; import { formatPercentage } from '@/lib/utils/formats'; -import ArrowRight from '@/styles/icons/arrow-right.svg?sprite'; +import ArrowRight from '@/styles/icons/arrow-right.svg'; import { useGetProtectionCoverageStats } from '@/types/generated/protection-coverage-stat'; import { useGetStaticIndicators } from '@/types/generated/static-indicator'; diff --git a/frontend/src/containers/homepage/link-cards/link-card/index.tsx b/frontend/src/containers/homepage/link-cards/link-card/index.tsx index 1c36ac23..94c77778 100644 --- a/frontend/src/containers/homepage/link-cards/link-card/index.tsx +++ b/frontend/src/containers/homepage/link-cards/link-card/index.tsx @@ -4,7 +4,7 @@ import { cva, type VariantProps } from 'class-variance-authority'; import Icon from '@/components/ui/icon'; import { cn } from '@/lib/classnames'; -import ArrowRight from '@/styles/icons/arrow-right.svg?sprite'; +import ArrowRight from '@/styles/icons/arrow-right.svg'; const BACKGROUND_IMAGES = { computer: '/images/static-pages/bg-images/card-1.png', diff --git a/frontend/src/containers/knowledge-hub/card-list/card-item/index.tsx b/frontend/src/containers/knowledge-hub/card-list/card-item/index.tsx index 11f62daf..24a33dd7 100644 --- a/frontend/src/containers/knowledge-hub/card-list/card-item/index.tsx +++ b/frontend/src/containers/knowledge-hub/card-list/card-item/index.tsx @@ -1,8 +1,8 @@ import Icon from '@/components/ui/icon'; import ExternalLinkIcon from '@/styles/icons/external-link-square.svg'; -import ListIcon from '@/styles/icons/list.svg?sprite'; -import StarIcon from '@/styles/icons/star.svg?sprite'; -import WorldIcon from '@/styles/icons/world.svg?sprite'; +import ListIcon from '@/styles/icons/list.svg'; +import StarIcon from '@/styles/icons/star.svg'; +import WorldIcon from '@/styles/icons/world.svg'; import { DataToolListResponseDataItem } from '@/types/generated/strapi.schemas'; const CIRCLE_ICON_CLASSES = diff --git a/frontend/src/containers/map/content/details/index.tsx b/frontend/src/containers/map/content/details/index.tsx index 3590b560..b72c1f9d 100644 --- a/frontend/src/containers/map/content/details/index.tsx +++ b/frontend/src/containers/map/content/details/index.tsx @@ -6,7 +6,7 @@ import { Button } from '@/components/ui/button'; import Icon from '@/components/ui/icon'; import tablesSettings from '@/containers/map/content/details/tables-settings'; import { useSyncMapContentSettings } from '@/containers/map/sync-settings'; -import CloseIcon from '@/styles/icons/close.svg?sprite'; +import CloseIcon from '@/styles/icons/close.svg'; import { getGetLocationsQueryOptions, useGetLocations } from '@/types/generated/location'; const MapDetails: React.FC = () => { diff --git a/frontend/src/containers/map/content/details/tables/national-highseas/useColumns.tsx b/frontend/src/containers/map/content/details/tables/national-highseas/useColumns.tsx index 470cdff1..20e0dd27 100644 --- a/frontend/src/containers/map/content/details/tables/national-highseas/useColumns.tsx +++ b/frontend/src/containers/map/content/details/tables/national-highseas/useColumns.tsx @@ -1,5 +1,7 @@ import { useMemo } from 'react'; +import { useRouter } from 'next/router'; + import { ColumnDef } from '@tanstack/react-table'; import FiltersButton from '@/components/filters-button'; @@ -26,6 +28,8 @@ type UseColumnsProps = { }; const useColumns = ({ filters, onFiltersChange }: UseColumnsProps) => { + const { locale } = useRouter(); + const { protectionStatus: protectionStatusOptions, establishmentStage: establishmentStageOptions, @@ -65,7 +69,7 @@ const useColumns = ({ filters, onFiltersChange }: UseColumnsProps) => { const { coverage: value } = row.original; if (!value) return <>—; - const formattedCoverage = cellFormatter.percentage(value); + const formattedCoverage = cellFormatter.percentage(locale, value); return ( @@ -86,7 +90,7 @@ const useColumns = ({ filters, onFiltersChange }: UseColumnsProps) => { ), cell: ({ row }) => { const { area: value } = row.original; - const formattedValue = cellFormatter.area(value); + const formattedValue = cellFormatter.area(locale, value); return ( {formattedValue} km2 diff --git a/frontend/src/containers/map/content/map/layers-toolbox/index.tsx b/frontend/src/containers/map/content/map/layers-toolbox/index.tsx index d9aad763..1bc882a2 100644 --- a/frontend/src/containers/map/content/map/layers-toolbox/index.tsx +++ b/frontend/src/containers/map/content/map/layers-toolbox/index.tsx @@ -4,7 +4,7 @@ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@radix-ui/r import { LuChevronDown } from 'react-icons/lu'; import Icon from '@/components/ui/icon'; -import LegendIcon from '@/styles/icons/legend.svg?sprite'; +import LegendIcon from '@/styles/icons/legend.svg'; import LayersLegend from './legend'; diff --git a/frontend/src/containers/map/content/map/layers-toolbox/legend/eez/index.tsx b/frontend/src/containers/map/content/map/layers-toolbox/legend/eez/index.tsx index 1630ed45..3e2525ee 100644 --- a/frontend/src/containers/map/content/map/layers-toolbox/legend/eez/index.tsx +++ b/frontend/src/containers/map/content/map/layers-toolbox/legend/eez/index.tsx @@ -1,9 +1,9 @@ import Icon from '@/components/ui/icon'; import { Tooltip, TooltipProvider, TooltipTrigger, TooltipContent } from '@/components/ui/tooltip'; -import EEZIcon from '@/styles/icons/eez.svg?sprite'; -import InfoIcon from '@/styles/icons/info.svg?sprite'; -import SelectedEEZIcon from '@/styles/icons/selected-eez.svg?sprite'; -import SeveralEEZIcon from '@/styles/icons/several-eez.svg?sprite'; +import EEZIcon from '@/styles/icons/eez.svg'; +import InfoIcon from '@/styles/icons/info.svg'; +import SelectedEEZIcon from '@/styles/icons/selected-eez.svg'; +import SeveralEEZIcon from '@/styles/icons/several-eez.svg'; import { useGetDataInfos } from '@/types/generated/data-info'; const ITEM_LIST_CLASSES = 'flex items-center space-x-2'; diff --git a/frontend/src/containers/map/content/map/layers-toolbox/legend/establishment/index.tsx b/frontend/src/containers/map/content/map/layers-toolbox/legend/establishment/index.tsx index dacaa69e..a8e9bf0f 100644 --- a/frontend/src/containers/map/content/map/layers-toolbox/legend/establishment/index.tsx +++ b/frontend/src/containers/map/content/map/layers-toolbox/legend/establishment/index.tsx @@ -1,9 +1,9 @@ import TooltipButton from '@/components/tooltip-button'; import Icon from '@/components/ui/icon'; -import DesignatedIcon from '@/styles/icons/designated.svg?sprite'; -import ImplementedIcon from '@/styles/icons/implemented.svg?sprite'; -import ManagedIcon from '@/styles/icons/managed.svg?sprite'; -import ProposedIcon from '@/styles/icons/proposed.svg?sprite'; +import DesignatedIcon from '@/styles/icons/designated.svg'; +import ImplementedIcon from '@/styles/icons/implemented.svg'; +import ManagedIcon from '@/styles/icons/managed.svg'; +import ProposedIcon from '@/styles/icons/proposed.svg'; const ITEM_LIST_CLASSES = 'flex items-center space-x-2'; const ICON_CLASSES = 'h-3.5 w-3.5 border border-black rounded-full'; diff --git a/frontend/src/containers/map/content/map/layers-toolbox/legend/index.tsx b/frontend/src/containers/map/content/map/layers-toolbox/legend/index.tsx index 5cc5ab2f..caabf0d3 100644 --- a/frontend/src/containers/map/content/map/layers-toolbox/legend/index.tsx +++ b/frontend/src/containers/map/content/map/layers-toolbox/legend/index.tsx @@ -13,10 +13,10 @@ import { useSyncMapLayers, } from '@/containers/map/content/map/sync-settings'; import { cn } from '@/lib/classnames'; -import ArrowDownIcon from '@/styles/icons/arrow-down.svg?sprite'; -import ArrowTopIcon from '@/styles/icons/arrow-top.svg?sprite'; -import CloseIcon from '@/styles/icons/close.svg?sprite'; -import OpacityIcon from '@/styles/icons/opacity.svg?sprite'; +import ArrowDownIcon from '@/styles/icons/arrow-down.svg'; +import ArrowTopIcon from '@/styles/icons/arrow-top.svg'; +import CloseIcon from '@/styles/icons/close.svg'; +import OpacityIcon from '@/styles/icons/opacity.svg'; import { useGetLayers } from '@/types/generated/layer'; import { LayerResponseDataObject } from '@/types/generated/strapi.schemas'; import { LayerTyped } from '@/types/layers'; diff --git a/frontend/src/containers/map/content/map/layers-toolbox/legend/item.tsx b/frontend/src/containers/map/content/map/layers-toolbox/legend/item.tsx index 525ee93f..b6b162ea 100644 --- a/frontend/src/containers/map/content/map/layers-toolbox/legend/item.tsx +++ b/frontend/src/containers/map/content/map/layers-toolbox/legend/item.tsx @@ -3,11 +3,11 @@ import { FC, ReactElement, isValidElement, useMemo } from 'react'; import TooltipButton from '@/components/tooltip-button'; import Icon from '@/components/ui/icon'; import { parseConfig } from '@/lib/json-converter'; -import EEZIcon from '@/styles/icons/eez.svg?sprite'; -import MPAIcon from '@/styles/icons/mpa.svg?sprite'; -import OECMIcon from '@/styles/icons/oecm.svg?sprite'; -import EEZSelectedIcon from '@/styles/icons/selected-eez.svg?sprite'; -import EEZMultipleIcon from '@/styles/icons/several-eez.svg?sprite'; +import EEZIcon from '@/styles/icons/eez.svg'; +import MPAIcon from '@/styles/icons/mpa.svg'; +import OECMIcon from '@/styles/icons/oecm.svg'; +import EEZSelectedIcon from '@/styles/icons/selected-eez.svg'; +import EEZMultipleIcon from '@/styles/icons/several-eez.svg'; import { LayerTyped, LegendConfig } from '@/types/layers'; export interface LegendItemsProps { config: LayerTyped['legend_config']; diff --git a/frontend/src/containers/map/content/map/popup/eez/index.tsx b/frontend/src/containers/map/content/map/popup/eez/index.tsx index ec36c42e..85ac10df 100644 --- a/frontend/src/containers/map/content/map/popup/eez/index.tsx +++ b/frontend/src/containers/map/content/map/popup/eez/index.tsx @@ -2,7 +2,8 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useMap } from 'react-map-gl'; -import { useParams, useRouter } from 'next/navigation'; +import { useParams } from 'next/navigation'; +import { useRouter } from 'next/router'; import { useQueries } from '@tanstack/react-query'; import type { Feature } from 'geojson'; diff --git a/frontend/src/containers/map/content/map/popup/index.tsx b/frontend/src/containers/map/content/map/popup/index.tsx index 2478eb66..b053e5a4 100644 --- a/frontend/src/containers/map/content/map/popup/index.tsx +++ b/frontend/src/containers/map/content/map/popup/index.tsx @@ -16,7 +16,7 @@ import { import PopupItem from '@/containers/map/content/map/popup/item'; import { layersInteractiveAtom, popupAtom } from '@/containers/map/store'; import { cn } from '@/lib/classnames'; -import CloseIcon from '@/styles/icons/close.svg?sprite'; +import CloseIcon from '@/styles/icons/close.svg'; import { useGetLayers } from '@/types/generated/layer'; import { useSyncMapLayers } from '../sync-settings'; diff --git a/frontend/src/containers/map/content/map/popup/protected-area/index.tsx b/frontend/src/containers/map/content/map/popup/protected-area/index.tsx index 79878576..6dc695ed 100644 --- a/frontend/src/containers/map/content/map/popup/protected-area/index.tsx +++ b/frontend/src/containers/map/content/map/popup/protected-area/index.tsx @@ -2,6 +2,8 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useMap } from 'react-map-gl'; +import { useRouter } from 'next/router'; + import type { Feature } from 'geojson'; import { useAtomValue } from 'jotai'; diff --git a/frontend/src/containers/map/sidebar/index.tsx b/frontend/src/containers/map/sidebar/index.tsx index c8569d7d..915580d2 100644 --- a/frontend/src/containers/map/sidebar/index.tsx +++ b/frontend/src/containers/map/sidebar/index.tsx @@ -6,7 +6,7 @@ import { Collapsible, CollapsibleContent } from '@/components/ui/collapsible'; import Icon from '@/components/ui/icon'; import { sidebarAtom, layersAtom } from '@/containers/map/store'; import { cn } from '@/lib/classnames'; -import LayersIcon from '@/styles/icons/layers.svg?sprite'; +import LayersIcon from '@/styles/icons/layers.svg'; import { useSyncMapContentSettings } from '../sync-settings'; diff --git a/frontend/src/layouts/static-page.tsx b/frontend/src/layouts/static-page.tsx index 86302afe..1c7313fa 100644 --- a/frontend/src/layouts/static-page.tsx +++ b/frontend/src/layouts/static-page.tsx @@ -5,7 +5,7 @@ import Head from '@/components/head'; import Header, { HeaderProps } from '@/components/header'; import Icon from '@/components/ui/icon'; import { cn } from '@/lib/classnames'; -import ArrowRight from '@/styles/icons/arrow-right.svg?sprite'; +import ArrowRight from '@/styles/icons/arrow-right.svg'; type SidebarProps = { sections: { diff --git a/frontend/src/pages/_app.tsx b/frontend/src/pages/_app.tsx index 5239a909..b586293d 100644 --- a/frontend/src/pages/_app.tsx +++ b/frontend/src/pages/_app.tsx @@ -3,8 +3,10 @@ import { useState } from 'react'; import { MapProvider } from 'react-map-gl'; import type { AppProps } from 'next/app'; +import { useRouter } from 'next/router'; import { QueryClient, QueryClientProvider, Hydrate } from '@tanstack/react-query'; +import { NextIntlClientProvider } from 'next-intl'; import 'styles/globals.css'; import 'mapbox-gl/dist/mapbox-gl.css'; @@ -29,6 +31,8 @@ const App: React.FC = ({ Component, pageProps }: Props) => { // between users const [queryClient] = useState(() => new QueryClient()); + const router = useRouter(); + const Layout = Component?.layout?.Component ?? ((page) => page?.children); let layoutProps = {}; @@ -48,16 +52,18 @@ const App: React.FC = ({ Component, pageProps }: Props) => { --font-figtree: ${figtree.style.fontFamily}; } `} - - - - - - - - - - + + + + + + + + + + + + ); }; diff --git a/frontend/src/types/index.d.ts b/frontend/src/types/index.d.ts index e95ef2b1..b107e2ca 100644 --- a/frontend/src/types/index.d.ts +++ b/frontend/src/types/index.d.ts @@ -6,7 +6,7 @@ declare global { } declare module '*.svg'; -declare module '*.svg?sprite' { +declare module '*.svg' { const content: { id: string; viewBox: string; diff --git a/frontend/translations/en.json b/frontend/translations/en.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/frontend/translations/en.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/frontend/yarn.lock b/frontend/yarn.lock index bc038a29..1e6e0275 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -385,6 +385,74 @@ __metadata: languageName: node linkType: hard +"@formatjs/ecma402-abstract@npm:2.0.0": + version: 2.0.0 + resolution: "@formatjs/ecma402-abstract@npm:2.0.0" + dependencies: + "@formatjs/intl-localematcher": 0.5.4 + tslib: ^2.4.0 + checksum: 0bba3b4f1a966c72d3f53173d650294fe313825b6451396c1040fb92bb86b2f771729888a1dadbc0a0074ef809229033fe8ff17c86dcb07a8ad42253b0c3a269 + languageName: node + linkType: hard + +"@formatjs/ecma402-abstract@npm:^1.11.4": + version: 1.18.3 + resolution: "@formatjs/ecma402-abstract@npm:1.18.3" + dependencies: + "@formatjs/intl-localematcher": 0.5.4 + tslib: ^2.4.0 + checksum: f41b42c93f80b1150171405e1a73be2f56efe108f4307da294024713521acd76a802b5d21d9846800bf41089d08676c4349fd8eecad59866a2f9a4815fcb250f + languageName: node + linkType: hard + +"@formatjs/fast-memoize@npm:2.2.0": + version: 2.2.0 + resolution: "@formatjs/fast-memoize@npm:2.2.0" + dependencies: + tslib: ^2.4.0 + checksum: 8697fe72a7ece252d600a7d08105f2a2f758e2dd96f54ac0a4c508b1205a559fc08835635e1f8e5ca9dcc3ee61ce1fca4a0e7047b402f29fc96051e293a280ff + languageName: node + linkType: hard + +"@formatjs/icu-messageformat-parser@npm:2.7.8": + version: 2.7.8 + resolution: "@formatjs/icu-messageformat-parser@npm:2.7.8" + dependencies: + "@formatjs/ecma402-abstract": 2.0.0 + "@formatjs/icu-skeleton-parser": 1.8.2 + tslib: ^2.4.0 + checksum: 404d6732653632eae3b10cfa70dc57c4fb0fe500c6ef9e687e938e4cb29e18b4e5d46633c88a2c06864328eb2f4713fbb6be404c6033682370d568971e2dda0d + languageName: node + linkType: hard + +"@formatjs/icu-skeleton-parser@npm:1.8.2": + version: 1.8.2 + resolution: "@formatjs/icu-skeleton-parser@npm:1.8.2" + dependencies: + "@formatjs/ecma402-abstract": 2.0.0 + tslib: ^2.4.0 + checksum: 8735322fa93ddd471822ba77400411660cb6221c87955cdcea159e8f9b72188106b4d4bf57d737d248810ae1974e1df4974914a6fb6045e91bf5ea22cc7fd30f + languageName: node + linkType: hard + +"@formatjs/intl-localematcher@npm:0.5.4": + version: 0.5.4 + resolution: "@formatjs/intl-localematcher@npm:0.5.4" + dependencies: + tslib: ^2.4.0 + checksum: a0af57874fcd163add5f7a0cb1c008e9b09feb1d24cbce1263379ae0393cddd6681197a7f2f512f351a97666fc8675ed52cc17d1834266ee8fc65e9edf3435f6 + languageName: node + linkType: hard + +"@formatjs/intl-localematcher@npm:^0.2.32": + version: 0.2.32 + resolution: "@formatjs/intl-localematcher@npm:0.2.32" + dependencies: + tslib: ^2.4.0 + checksum: 477e18aabaf2e6e90fc12952a3cb6c0ebb40ad99414d6b9d2501c6348fbad58cacb433ec6630955cfd1491ea7630f32a9dc280bb27d0fb8a784251404a54140a + languageName: node + linkType: hard + "@hapi/hoek@npm:^9.0.0": version: 9.3.0 resolution: "@hapi/hoek@npm:9.3.0" @@ -8482,6 +8550,18 @@ __metadata: languageName: node linkType: hard +"intl-messageformat@npm:^10.5.11": + version: 10.5.14 + resolution: "intl-messageformat@npm:10.5.14" + dependencies: + "@formatjs/ecma402-abstract": 2.0.0 + "@formatjs/fast-memoize": 2.2.0 + "@formatjs/icu-messageformat-parser": 2.7.8 + tslib: ^2.4.0 + checksum: 7aaed153283eb83720d72df7757390515a79a1823ea9f4191c69859f1e5dd0d9a7463e5f9186fe77a31414ed98fc81619fb4c838ffdf6d481b1b370403337ca3 + languageName: node + linkType: hard + "invariant@npm:^2.2.4": version: 2.2.4 resolution: "invariant@npm:2.2.4" @@ -9996,6 +10076,20 @@ __metadata: languageName: node linkType: hard +"next-intl@npm:^3.15.0": + version: 3.15.0 + resolution: "next-intl@npm:3.15.0" + dependencies: + "@formatjs/intl-localematcher": ^0.2.32 + negotiator: ^0.6.3 + use-intl: ^3.15.0 + peerDependencies: + next: ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: e7ceb12ef6305c5334cddd39dc7fb60cf32629d0e50543e810b235a9fe8019d1a95e4b361331a3e61b59c6543f944ba44643f0e98399c305f8a7dcf0ed567524 + languageName: node + linkType: hard + "next-usequerystate@npm:1.9.2": version: 1.9.2 resolution: "next-usequerystate@npm:1.9.2" @@ -12001,6 +12095,7 @@ __metadata: mapbox-gl: 3.1.2 next: 13.5.6 next-auth: ^4.24.7 + next-intl: ^3.15.0 next-usequerystate: 1.9.2 orval: 6.18.1 postcss: 8.4.21 @@ -13120,6 +13215,18 @@ __metadata: languageName: node linkType: hard +"use-intl@npm:^3.15.0": + version: 3.15.0 + resolution: "use-intl@npm:3.15.0" + dependencies: + "@formatjs/ecma402-abstract": ^1.11.4 + intl-messageformat: ^10.5.11 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 1234d7ce1d43692ef972f7aaffec3a6bababb5f31e25dca76e09535f9491699bb7f7ca4e97dece169071c4fea5bdaa9356eb065669295d37c3111d4b8deab178 + languageName: node + linkType: hard + "use-sidecar@npm:^1.1.2": version: 1.1.2 resolution: "use-sidecar@npm:1.1.2" From 4ae7e8f3224cdcba7343c4085200c68b80870a71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Prod=27homme?= Date: Thu, 13 Jun 2024 14:35:44 +0200 Subject: [PATCH 02/14] Required upgrade for i18n Reason: https://github.com/vercel/next.js/issues/55648 --- frontend/.nvmrc | 2 +- frontend/package.json | 2 +- frontend/yarn.lock | 145 +++++++++++++++++++++--------------------- 3 files changed, 75 insertions(+), 74 deletions(-) diff --git a/frontend/.nvmrc b/frontend/.nvmrc index 932b2b01..aacb5181 100644 --- a/frontend/.nvmrc +++ b/frontend/.nvmrc @@ -1 +1 @@ -18.15 +18.17 diff --git a/frontend/package.json b/frontend/package.json index ce556529..752a76b9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -58,7 +58,7 @@ "lodash-es": "^4.17.21", "lucide-react": "^0.274.0", "mapbox-gl": "3.1.2", - "next": "13.5.6", + "next": "14.2.4", "next-auth": "^4.24.7", "next-intl": "^3.15.0", "next-usequerystate": "1.9.2", diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 1e6e0275..b931ae09 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1132,10 +1132,10 @@ __metadata: languageName: node linkType: hard -"@next/env@npm:13.5.6": - version: 13.5.6 - resolution: "@next/env@npm:13.5.6" - checksum: 5e8f3f6f987a15dad3cd7b2bcac64a6382c2ec372d95d0ce6ab295eb59c9731222017eebf71ff3005932de2571f7543bce7e5c6a8c90030207fb819404138dc2 +"@next/env@npm:14.2.4": + version: 14.2.4 + resolution: "@next/env@npm:14.2.4" + checksum: ff47297f959c4f4a45393fc84eb2cdef0e92fb07903e1240e061ff71c2319d90d3faf23aa6f8e5747451a26527ab20b483a200845ac9c72629647d67407b15c2 languageName: node linkType: hard @@ -1148,65 +1148,65 @@ __metadata: languageName: node linkType: hard -"@next/swc-darwin-arm64@npm:13.5.6": - version: 13.5.6 - resolution: "@next/swc-darwin-arm64@npm:13.5.6" +"@next/swc-darwin-arm64@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-darwin-arm64@npm:14.2.4" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@next/swc-darwin-x64@npm:13.5.6": - version: 13.5.6 - resolution: "@next/swc-darwin-x64@npm:13.5.6" +"@next/swc-darwin-x64@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-darwin-x64@npm:14.2.4" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@next/swc-linux-arm64-gnu@npm:13.5.6": - version: 13.5.6 - resolution: "@next/swc-linux-arm64-gnu@npm:13.5.6" +"@next/swc-linux-arm64-gnu@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-linux-arm64-gnu@npm:14.2.4" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@next/swc-linux-arm64-musl@npm:13.5.6": - version: 13.5.6 - resolution: "@next/swc-linux-arm64-musl@npm:13.5.6" +"@next/swc-linux-arm64-musl@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-linux-arm64-musl@npm:14.2.4" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@next/swc-linux-x64-gnu@npm:13.5.6": - version: 13.5.6 - resolution: "@next/swc-linux-x64-gnu@npm:13.5.6" +"@next/swc-linux-x64-gnu@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-linux-x64-gnu@npm:14.2.4" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@next/swc-linux-x64-musl@npm:13.5.6": - version: 13.5.6 - resolution: "@next/swc-linux-x64-musl@npm:13.5.6" +"@next/swc-linux-x64-musl@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-linux-x64-musl@npm:14.2.4" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@next/swc-win32-arm64-msvc@npm:13.5.6": - version: 13.5.6 - resolution: "@next/swc-win32-arm64-msvc@npm:13.5.6" +"@next/swc-win32-arm64-msvc@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-win32-arm64-msvc@npm:14.2.4" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@next/swc-win32-ia32-msvc@npm:13.5.6": - version: 13.5.6 - resolution: "@next/swc-win32-ia32-msvc@npm:13.5.6" +"@next/swc-win32-ia32-msvc@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-win32-ia32-msvc@npm:14.2.4" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@next/swc-win32-x64-msvc@npm:13.5.6": - version: 13.5.6 - resolution: "@next/swc-win32-x64-msvc@npm:13.5.6" +"@next/swc-win32-x64-msvc@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-win32-x64-msvc@npm:14.2.4" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -2835,12 +2835,20 @@ __metadata: languageName: node linkType: hard -"@swc/helpers@npm:0.5.2": - version: 0.5.2 - resolution: "@swc/helpers@npm:0.5.2" +"@swc/counter@npm:^0.1.3": + version: 0.1.3 + resolution: "@swc/counter@npm:0.1.3" + checksum: df8f9cfba9904d3d60f511664c70d23bb323b3a0803ec9890f60133954173047ba9bdeabce28cd70ba89ccd3fd6c71c7b0bd58be85f611e1ffbe5d5c18616598 + languageName: node + linkType: hard + +"@swc/helpers@npm:0.5.5": + version: 0.5.5 + resolution: "@swc/helpers@npm:0.5.5" dependencies: + "@swc/counter": ^0.1.3 tslib: ^2.4.0 - checksum: 51d7e3d8bd56818c49d6bfbd715f0dbeedc13cf723af41166e45c03e37f109336bbcb57a1f2020f4015957721aeb21e1a7fff281233d797ff7d3dd1f447fa258 + checksum: d4f207b191e54b29460804ddf2984ba6ece1d679a0b2f6a9c765dcf27bba92c5769e7965668a4546fb9f1021eaf0ff9be4bf5c235ce12adcd65acdfe77187d11 languageName: node linkType: hard @@ -5566,13 +5574,20 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001406, caniuse-lite@npm:^1.0.30001464, caniuse-lite@npm:^1.0.30001541": +"caniuse-lite@npm:^1.0.30001464, caniuse-lite@npm:^1.0.30001541": version: 1.0.30001553 resolution: "caniuse-lite@npm:1.0.30001553" checksum: 45d6a2a3c3a098c8093a4c8883fceafb4bbf59d96f6fd5bb381ba4581d07eecbe0ede4f55383f0d49374154ff6a808bd90fbe32b17ccd1738034d2579787b33c languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001579": + version: 1.0.30001633 + resolution: "caniuse-lite@npm:1.0.30001633" + checksum: 718607f5d335ed26a469b03aaf059aec3352d81d6a974888122310d76c29ff0820e9bf57f16a1eb65693f8cef405e3a18a6257591ee1e5642865a4cb1a27cd4c + languageName: node + linkType: hard + "cartocolor@npm:^4.0.2": version: 4.0.2 resolution: "cartocolor@npm:4.0.2" @@ -8037,13 +8052,6 @@ __metadata: languageName: node linkType: hard -"glob-to-regexp@npm:^0.4.1": - version: 0.4.1 - resolution: "glob-to-regexp@npm:0.4.1" - checksum: e795f4e8f06d2a15e86f76e4d92751cf8bbfcf0157cea5c2f0f35678a8195a750b34096b1256e436f0cebc1883b5ff0888c47348443e69546a5a87f9e1eb1167 - languageName: node - linkType: hard - "glob@npm:7.1.7": version: 7.1.7 resolution: "glob@npm:7.1.7" @@ -8128,7 +8136,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": +"graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 @@ -10101,28 +10109,29 @@ __metadata: languageName: node linkType: hard -"next@npm:13.5.6": - version: 13.5.6 - resolution: "next@npm:13.5.6" +"next@npm:14.2.4": + version: 14.2.4 + resolution: "next@npm:14.2.4" dependencies: - "@next/env": 13.5.6 - "@next/swc-darwin-arm64": 13.5.6 - "@next/swc-darwin-x64": 13.5.6 - "@next/swc-linux-arm64-gnu": 13.5.6 - "@next/swc-linux-arm64-musl": 13.5.6 - "@next/swc-linux-x64-gnu": 13.5.6 - "@next/swc-linux-x64-musl": 13.5.6 - "@next/swc-win32-arm64-msvc": 13.5.6 - "@next/swc-win32-ia32-msvc": 13.5.6 - "@next/swc-win32-x64-msvc": 13.5.6 - "@swc/helpers": 0.5.2 + "@next/env": 14.2.4 + "@next/swc-darwin-arm64": 14.2.4 + "@next/swc-darwin-x64": 14.2.4 + "@next/swc-linux-arm64-gnu": 14.2.4 + "@next/swc-linux-arm64-musl": 14.2.4 + "@next/swc-linux-x64-gnu": 14.2.4 + "@next/swc-linux-x64-musl": 14.2.4 + "@next/swc-win32-arm64-msvc": 14.2.4 + "@next/swc-win32-ia32-msvc": 14.2.4 + "@next/swc-win32-x64-msvc": 14.2.4 + "@swc/helpers": 0.5.5 busboy: 1.6.0 - caniuse-lite: ^1.0.30001406 + caniuse-lite: ^1.0.30001579 + graceful-fs: ^4.2.11 postcss: 8.4.31 styled-jsx: 5.1.1 - watchpack: 2.4.0 peerDependencies: "@opentelemetry/api": ^1.1.0 + "@playwright/test": ^1.41.2 react: ^18.2.0 react-dom: ^18.2.0 sass: ^1.3.0 @@ -10148,11 +10157,13 @@ __metadata: peerDependenciesMeta: "@opentelemetry/api": optional: true + "@playwright/test": + optional: true sass: optional: true bin: next: dist/bin/next - checksum: c869b0014ae921ada3bf22301985027ec320aebcd6aa9c16e8afbded68bb8def5874cca034c680e8c351a79578f1e514971d02777f6f0a5a1d7290f25970ac0d + checksum: 3b858cfec2e061d811811921361855659b09424ea4178cf0f4a0bbe5d3978b45da6f04575fe213d76e47f626439db61591b79932f37ff984b7b7de87dd1ccce0 languageName: node linkType: hard @@ -12093,7 +12104,7 @@ __metadata: lodash-es: ^4.17.21 lucide-react: ^0.274.0 mapbox-gl: 3.1.2 - next: 13.5.6 + next: 14.2.4 next-auth: ^4.24.7 next-intl: ^3.15.0 next-usequerystate: 1.9.2 @@ -13346,16 +13357,6 @@ __metadata: languageName: node linkType: hard -"watchpack@npm:2.4.0": - version: 2.4.0 - resolution: "watchpack@npm:2.4.0" - dependencies: - glob-to-regexp: ^0.4.1 - graceful-fs: ^4.1.2 - checksum: 23d4bc58634dbe13b86093e01c6a68d8096028b664ab7139d58f0c37d962d549a940e98f2f201cecdabd6f9c340338dc73ef8bf094a2249ef582f35183d1a131 - languageName: node - linkType: hard - "wcwidth@npm:^1.0.1": version: 1.0.1 resolution: "wcwidth@npm:1.0.1" From a76484ab18286871d26a9e7bc197f7fe0d192d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Prod=27homme?= Date: Thu, 13 Jun 2024 14:49:25 +0200 Subject: [PATCH 03/14] Add hreflang meta tags --- frontend/src/components/head/index.tsx | 30 ++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/head/index.tsx b/frontend/src/components/head/index.tsx index 85b9267b..58b54021 100644 --- a/frontend/src/components/head/index.tsx +++ b/frontend/src/components/head/index.tsx @@ -1,15 +1,33 @@ import NextHead from 'next/head'; +import { useRouter } from 'next/router'; export type HeadProps = { title?: string; description?: string; }; -const Head: React.FC = ({ title, description }) => ( - - {`${title ? `${title} | ` : ''}SkyTruth 30x30`} - {description && } - -); +const Head: React.FC = ({ title, description }) => { + const { locales, asPath } = useRouter(); + + return ( + + {`${title ? `${title} | ` : ''}SkyTruth 30x30`} + {description && } + {locales.map((locale) => ( + + ))} + + + ); +}; export default Head; From a491e767fdfce29aa30d81f535c714aed9e9cda5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Prod=27homme?= Date: Thu, 13 Jun 2024 14:52:22 +0200 Subject: [PATCH 04/14] Improve typing of messages --- frontend/local.d.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frontend/local.d.ts b/frontend/local.d.ts index d44e4adc..75ecda98 100644 --- a/frontend/local.d.ts +++ b/frontend/local.d.ts @@ -10,3 +10,11 @@ declare module '*.svg' { } declare module '*.png'; declare module '*.jpg'; + +import en from './translations/en.json'; +type Messages = typeof en; + +declare global { + // Use type safe message keys with `next-intl` + interface IntlMessages extends Messages {} +} From 036ab9a656a03f1c8dbf526faeb5c2d6aa5cf520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Prod=27homme?= Date: Thu, 13 Jun 2024 16:17:38 +0200 Subject: [PATCH 05/14] Translate error pages and utils --- frontend/package.json | 1 + .../conservation-chart/tooltip/index.tsx | 6 +- .../charts/horizontal-bar-chart/index.tsx | 14 +++-- .../stacked-horizontal-bar-chart/index.tsx | 9 ++- .../src/containers/homepage/intro/index.tsx | 7 ++- .../map/content/details/table/helpers.ts | 8 +-- .../tables/global-regional/useColumns.tsx | 17 +++--- .../map/content/map/popup/eez/index.tsx | 10 ++-- .../map/content/map/popup/generic/index.tsx | 6 +- .../map/popup/protected-area/index.tsx | 3 + .../map/content/map/popup/regions/index.tsx | 9 +-- .../widgets/marine-conservation/index.tsx | 12 ++-- frontend/src/layouts/error-page.tsx | 57 +++++++++++-------- frontend/src/lib/i18n/index.ts | 10 ++++ frontend/src/lib/utils/file-upload.ts | 32 ++++++----- frontend/src/lib/utils/formats.ts | 12 ++-- frontend/src/pages/404.tsx | 35 +++++++++--- frontend/src/pages/500.tsx | 35 +++++++++--- frontend/src/pages/index.tsx | 8 ++- frontend/src/types/index.d.ts | 7 ++- frontend/translations/en.json | 24 +++++++- frontend/yarn.lock | 8 +++ 22 files changed, 231 insertions(+), 99 deletions(-) create mode 100644 frontend/src/lib/i18n/index.ts diff --git a/frontend/package.json b/frontend/package.json index 752a76b9..3f4c0750 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -53,6 +53,7 @@ "d3-time-format": "^4.1.0", "date-fns": "^2.30.0", "deck.gl": "8.9.31", + "deepmerge": "^4.3.1", "embla-carousel-react": "8.0.0", "jotai": "2.4.3", "lodash-es": "^4.17.21", diff --git a/frontend/src/components/charts/conservation-chart/tooltip/index.tsx b/frontend/src/components/charts/conservation-chart/tooltip/index.tsx index 027ff4e4..74b0f998 100644 --- a/frontend/src/components/charts/conservation-chart/tooltip/index.tsx +++ b/frontend/src/components/charts/conservation-chart/tooltip/index.tsx @@ -1,8 +1,12 @@ import React from 'react'; +import { useRouter } from 'next/router'; + import { formatPercentage } from '@/lib/utils/formats'; const ChartTooltip = ({ active, payload }) => { + const { locale } = useRouter(); + if (!active || !payload) return null; const percentageData = payload?.find(({ dataKey }) => dataKey === 'percentage'); @@ -13,7 +17,7 @@ const ChartTooltip = ({ active, payload }) => { return (
Year: {year} - Coverage: {formatPercentage(percentage)} + Coverage: {formatPercentage(locale, percentage)}
); }; diff --git a/frontend/src/components/charts/horizontal-bar-chart/index.tsx b/frontend/src/components/charts/horizontal-bar-chart/index.tsx index 1c452368..b48e0953 100644 --- a/frontend/src/components/charts/horizontal-bar-chart/index.tsx +++ b/frontend/src/components/charts/horizontal-bar-chart/index.tsx @@ -1,5 +1,7 @@ import { useMemo } from 'react'; +import { useRouter } from 'next/router'; + import TooltipButton from '@/components/tooltip-button'; import { cn } from '@/lib/classnames'; import { formatPercentage, formatKM } from '@/lib/utils/formats'; @@ -37,13 +39,17 @@ const HorizontalBarChart: React.FC = ({ }) => { const { title, background, totalArea, protectedArea, info, sources } = data; + const { locale } = useRouter(); + const targetPositionPercentage = useMemo(() => { return (PROTECTION_TARGET * 100) / DEFAULT_MAX_PERCENTAGE; }, []); const protectedAreaPercentage = useMemo(() => { - return formatPercentage((protectedArea / totalArea) * 100, { displayPercentageSign: false }); - }, [totalArea, protectedArea]); + return formatPercentage(locale, (protectedArea / totalArea) * 100, { + displayPercentageSign: false, + }); + }, [locale, totalArea, protectedArea]); const barFillPercentage = useMemo(() => { const totalPercentage = (protectedArea * 100) / totalArea; @@ -66,10 +72,10 @@ const HorizontalBarChart: React.FC = ({ - {formatKM(protectedArea)} km2 + {formatKM(locale, protectedArea)} km2 {' '} - out of {formatKM(totalArea)} km2 + out of {formatKM(locale, totalArea)} km2
diff --git a/frontend/src/components/charts/stacked-horizontal-bar-chart/index.tsx b/frontend/src/components/charts/stacked-horizontal-bar-chart/index.tsx index 12ab9659..ff7bba8e 100644 --- a/frontend/src/components/charts/stacked-horizontal-bar-chart/index.tsx +++ b/frontend/src/components/charts/stacked-horizontal-bar-chart/index.tsx @@ -1,3 +1,5 @@ +import { useRouter } from 'next/router'; + import TooltipButton from '@/components/tooltip-button'; import { cn } from '@/lib/classnames'; import { formatPercentage, formatKM } from '@/lib/utils/formats'; @@ -31,10 +33,12 @@ const StackedHorizontalBarChart: React.FC = ({ showLegend = true, showTarget = true, }) => { + const { locale } = useRouter(); + return (
- {formatPercentage(highlightedPercentage, { displayPercentageSign: false })} + {formatPercentage(locale, highlightedPercentage, { displayPercentageSign: false })} %
@@ -43,7 +47,8 @@ const StackedHorizontalBarChart: React.FC = ({ {info && } - {formatKM(totalProtectedArea)} km2 out of {formatKM(totalArea)} km2 + {formatKM(locale, totalProtectedArea)} km2 out of {formatKM(locale, totalArea)}{' '} + km2
diff --git a/frontend/src/containers/homepage/intro/index.tsx b/frontend/src/containers/homepage/intro/index.tsx index 1b03293c..247f3c6f 100644 --- a/frontend/src/containers/homepage/intro/index.tsx +++ b/frontend/src/containers/homepage/intro/index.tsx @@ -1,6 +1,7 @@ import { useMemo } from 'react'; import Image from 'next/image'; +import { useRouter } from 'next/router'; import Icon from '@/components/ui/icon'; import SidebarItem from '@/containers/homepage/intro/sidebar-item'; @@ -14,6 +15,8 @@ type IntroProps = { }; const Intro: React.FC = ({ onScrollClick }) => { + const { locale } = useRouter(); + const { data: { data: protectionStatsData }, } = useGetProtectionCoverageStats( @@ -73,8 +76,8 @@ const Intro: React.FC = ({ onScrollClick }) => { if (Number.isNaN(coveragePercentage)) return null; - return formatPercentage(coveragePercentage, { displayPercentageSign: false }); - }, [protectionStatsData]); + return formatPercentage(locale, coveragePercentage, { displayPercentageSign: false }); + }, [locale, protectionStatsData]); return (
diff --git a/frontend/src/containers/map/content/details/table/helpers.ts b/frontend/src/containers/map/content/details/table/helpers.ts index 17639d69..96c9b0b8 100644 --- a/frontend/src/containers/map/content/details/table/helpers.ts +++ b/frontend/src/containers/map/content/details/table/helpers.ts @@ -1,11 +1,11 @@ import { formatPercentage, formatKM } from '@/lib/utils/formats'; -const percentage = (value: number) => { - return formatPercentage(value, { displayPercentageSign: false }); +const percentage = (locale: string, value: number) => { + return formatPercentage(locale, value, { displayPercentageSign: false }); }; -const area = (value: number) => { - return formatKM(value); +const area = (locale: string, value: number) => { + return formatKM(locale, value); }; const capitalize = (value: string) => { diff --git a/frontend/src/containers/map/content/details/tables/global-regional/useColumns.tsx b/frontend/src/containers/map/content/details/tables/global-regional/useColumns.tsx index 08e09ad2..1dcdaa88 100644 --- a/frontend/src/containers/map/content/details/tables/global-regional/useColumns.tsx +++ b/frontend/src/containers/map/content/details/tables/global-regional/useColumns.tsx @@ -1,6 +1,7 @@ import { useMemo } from 'react'; import Link from 'next/link'; +import { useRouter } from 'next/router'; import { ColumnDef } from '@tanstack/react-table'; @@ -29,6 +30,8 @@ const useColumns = () => { const searchParams = useMapSearchParams(); const tooltips = useTooltips(); + const { locale } = useRouter(); + const columns: ColumnDef[] = useMemo(() => { return [ { @@ -65,7 +68,7 @@ const useColumns = () => { ), cell: ({ row }) => { const { coverage: value } = row.original; - const formattedCoverage = cellFormatter.percentage(value); + const formattedCoverage = cellFormatter.percentage(locale, value); return ( @@ -86,7 +89,7 @@ const useColumns = () => { ), cell: ({ row }) => { const { area: value } = row.original; - const formattedValue = cellFormatter.area(value); + const formattedValue = cellFormatter.area(locale, value); return ( {formattedValue} km2 @@ -107,7 +110,7 @@ const useColumns = () => { const { mpas: value } = row.original; if (Number.isNaN(value)) return 'N/A'; - const formattedValue = cellFormatter.percentage(value); + const formattedValue = cellFormatter.percentage(locale, value); return {formattedValue}%; }, }, @@ -124,7 +127,7 @@ const useColumns = () => { const { oecms: value } = row.original; if (Number.isNaN(value)) return 'N/A'; - const formattedValue = cellFormatter.percentage(value); + const formattedValue = cellFormatter.percentage(locale, value); return {formattedValue}%; }, }, @@ -139,7 +142,7 @@ const useColumns = () => { ), cell: ({ row }) => { const { fullyHighlyProtected: value } = row.original; - const formattedValue = cellFormatter.percentage(value); + const formattedValue = cellFormatter.percentage(locale, value); return {formattedValue}%; }, }, @@ -155,7 +158,7 @@ const useColumns = () => { // cell: ({ row }) => { // const { highlyProtectedLfp: value } = row.original; // if (!value) return <>No data; - // const formattedValue = cellFormatter.percentage(value); + // const formattedValue = cellFormatter.percentage(locale, value); // return {formattedValue}%; // }, // }, @@ -171,7 +174,7 @@ const useColumns = () => { cell: ({ row }) => { const { globalContribution: value } = row.original; if (!value) return <>No data; - const formattedValue = cellFormatter.percentage(value); + const formattedValue = cellFormatter.percentage(locale, value); return {formattedValue}%; }, }, diff --git a/frontend/src/containers/map/content/map/popup/eez/index.tsx b/frontend/src/containers/map/content/map/popup/eez/index.tsx index 85ac10df..df9c3058 100644 --- a/frontend/src/containers/map/content/map/popup/eez/index.tsx +++ b/frontend/src/containers/map/content/map/popup/eez/index.tsx @@ -25,7 +25,7 @@ const EEZLayerPopup = ({ layerId }) => { const DATA_REF = useRef(); const { default: map } = useMap(); const searchParams = useMapSearchParams(); - const { push } = useRouter(); + const { locale, push } = useRouter(); const [, setLocationBBox] = useAtom(bboxLocation); const [popup, setPopup] = useAtom(popupAtom); const { locationCode } = useParams(); @@ -189,13 +189,13 @@ const EEZLayerPopup = ({ layerId }) => { const coveragePercentage = useMemo(() => { if (locationsData.length) { - return formatPercentage((totalCumSumProtectedArea / totalMarineArea) * 100, { + return formatPercentage(locale, (totalCumSumProtectedArea / totalMarineArea) * 100, { displayPercentageSign: false, }); } return '-'; - }, [totalCumSumProtectedArea, totalMarineArea, locationsData]); + }, [locale, totalCumSumProtectedArea, totalMarineArea, locationsData]); // handle renderer const handleMapRender = useCallback(() => { @@ -243,11 +243,11 @@ const EEZLayerPopup = ({ layerId }) => { {coveragePercentage !== '-' && %}
- {formatKM(totalCumSumProtectedArea)} + {formatKM(locale, totalCumSumProtectedArea)} km2 {' '} - out of {formatKM(totalMarineArea)} km2 + out of {formatKM(locale, totalMarineArea)} km2
{locationCodes?.length === 1 && ( diff --git a/frontend/src/containers/map/content/map/popup/generic/index.tsx b/frontend/src/containers/map/content/map/popup/generic/index.tsx index a3ddca1d..40129140 100644 --- a/frontend/src/containers/map/content/map/popup/generic/index.tsx +++ b/frontend/src/containers/map/content/map/popup/generic/index.tsx @@ -2,6 +2,8 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useMap } from 'react-map-gl'; +import { useRouter } from 'next/router'; + import type { Feature } from 'geojson'; import { useAtomValue } from 'jotai'; @@ -16,6 +18,8 @@ const GenericPopup = ({ layerId, ...restConfig }: InteractionConfig & { layerId: const { default: map } = useMap(); const { events } = restConfig; + const { locale } = useRouter(); + const popup = useAtomValue(popupAtom); const layersInteractiveIds = useAtomValue(layersInteractiveIdsAtom); @@ -112,7 +116,7 @@ const GenericPopup = ({ layerId, ...restConfig }: InteractionConfig & { layerId:
{label}
- {customFormat && format({ value: DATA[key], ...customFormat })} + {customFormat && format({ locale, value: DATA[key], ...customFormat })} {!customFormat && DATA[key]}
diff --git a/frontend/src/containers/map/content/map/popup/protected-area/index.tsx b/frontend/src/containers/map/content/map/popup/protected-area/index.tsx index 6dc695ed..6ba047a0 100644 --- a/frontend/src/containers/map/content/map/popup/protected-area/index.tsx +++ b/frontend/src/containers/map/content/map/popup/protected-area/index.tsx @@ -17,6 +17,7 @@ import { LayerTyped } from '@/types/layers'; const TERMS_CLASSES = 'font-mono uppercase'; const ProtectedAreaPopup = ({ layerId }: { layerId: number }) => { + const { locale } = useRouter(); const [rendered, setRendered] = useState(false); const DATA_REF = useRef(); const { default: map } = useMap(); @@ -128,12 +129,14 @@ const ProtectedAreaPopup = ({ layerId }: { layerId: number }) => {
Global coverage
{format({ + locale, value: globalCoveragePercentage, id: 'formatPercentage', })}
{format({ + locale, value: DATA?.REP_M_AREA, id: 'formatKM', options: { diff --git a/frontend/src/containers/map/content/map/popup/regions/index.tsx b/frontend/src/containers/map/content/map/popup/regions/index.tsx index fd31c2c1..803a8651 100644 --- a/frontend/src/containers/map/content/map/popup/regions/index.tsx +++ b/frontend/src/containers/map/content/map/popup/regions/index.tsx @@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useMap } from 'react-map-gl'; -import { useRouter } from 'next/navigation'; +import { useRouter } from 'next/router'; import type { Feature } from 'geojson'; import { useAtom, useAtomValue, useSetAtom } from 'jotai'; @@ -23,7 +23,7 @@ const RegionsPopup = ({ layerId }) => { const DATA_REF = useRef(); const { default: map } = useMap(); const searchParams = useMapSearchParams(); - const { push } = useRouter(); + const { locale, push } = useRouter(); const setLocationBBox = useSetAtom(bboxLocation); const [popup, setPopup] = useAtom(popupAtom); @@ -137,13 +137,14 @@ const RegionsPopup = ({ layerId }) => { ); const percentage = formatPercentage( + locale, (totalCumSumProtectedArea / locationsQuery.data.totalMarineArea) * 100, { displayPercentageSign: false, } ); - const protectedArea = formatKM(totalCumSumProtectedArea); + const protectedArea = formatKM(locale, totalCumSumProtectedArea); return { percentage, @@ -208,7 +209,7 @@ const RegionsPopup = ({ layerId }) => { km2 {' '} - out of {formatKM(locationsQuery.data.totalMarineArea)} km2 + out of {formatKM(locale, locationsQuery.data.totalMarineArea)} km2