As per wikipedia
Internationalisation
andLocalisation
, often abbreviatedi18n
andL10n
, is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes.
Let's take an example use-case; so that we both are on the same page.
- We have one collection named
home-page
having the following fields. ( My use-case was to provide support for 4-5 languages, may require more in future).
where banner(single component) and brand(repeatable component) are components.
Fields description:
-
title
-
home-page
having three fieldstitle
,title_ar
,title_ru
, values of titleEnglish(en)
,Arabic(ar)
andRussian(ru)
language repectively. -
Banner and Brand
-
title
in banner andname
in the brand are language-dependent and the rest of the fields are the same for all languages. - And, when selected languageCode isar
, my frontend will needtitle
=titile_ar
in response for banner andname
=name_ar
in response for brand.
My Approach ( didn't use any plugin ):
-
Made a file specifying the language dependent fields.
This is generated automatically (based on the
collection
) when server starts.
projec_dir/constants/i18n.config.json
{ "home-page": [ "title" ], "component.banner-component": [ "title" ], "component.brand-component": [ "name" ] }
get data from the model using find, findOne or any other customised service.
fetch schema of the model (required for the name of the attribute to get language dependent fields from the JSON imported from project-dir/constants/i18n.config.json)
replace
${field}
with${field}${languageCode}
.delete
${field}${languageCode}
.
Code:
-
project_dir/constants/i18n.constants.js
const i18nFields = require('./i18n.config.json'); const DEFAULT_LANGUAGE = 'en'; const LANGUAGE_LIST = ['en', 'ar', 'ka', 'ru', 'uzb']; const I_18_FIELDS = i18nFields; const I18N_LIST = ['home-page']; module.exports = { DEFAULT_LANGUAGE, LANGUAGE_LIST, I_18_FIELDS, I18N_LIST, };
-
project_dir/utils/i18n.utils.js
const _ = require('lodash'); const { LANGUAGE_LIST, DEFAULT_LANGUAGE, } = require('../constants/i18n.constants'); function internationalizeFields(components, langCode, fields) { if (!components) { return undefined; } const i18Component = { ...components }; if (fields) { fields.forEach((field) => { const currentLanguageFieldValue = _.get( i18Component, `${field}_${langCode}` ); if (langCode !== DEFAULT_LANGUAGE) { _.set(i18Component, field, currentLanguageFieldValue); } LANGUAGE_LIST.forEach((lang) => _.unset(i18Component, `${field}_${lang}`) ); }); } return i18Component; } module.exports = { internationalizeFields, };
- project_dir/utils/strapi.util.js
/* global strapi */ function getAttributes({ modelName }) { try { return strapi.api[modelName].models[modelName].__schema__.attributes; } catch (err) { //throw error } } function addComponentSchema({ parentSchema }) { const result = Object.keys(parentSchema).reduce((acc, curr) => { acc[curr] = parentSchema[curr]; if (parentSchema[curr].type !== 'component') { return acc; } const component = strapi.components[acc[curr].component]; if (!component) { throw error } acc[curr].schema = component.attributes; acc[curr].schema = addComponentSchema({ parentSchema: acc[curr].schema }); return acc; }, {}); if (!result || Object.keys(result).length === 0) { //through error } return result; } module.exports = { getAttributes, addComponentSchema, };
- project_dir/utils/controller.util.js
const { DEFAULT_LANGUAGE } = require('../common/constants/i18n.constants'); const { I_18_FIELDS } = require('../common/constants/i18n.constants'); const { internationalizeFields } = require('../common/utils/i18n.utils'); const { getAttributes, addComponentSchema } = require('./strapi.utils'); /** * @param {*} modelName modelName for keys in I_18_FIELDS * @param {*} data data to be internationlised * @param {*} schema schema corresponding to modelName * @param {*} lang * @returns internationalised data */ async function internationalizeData({ modelName, data, schema, lang = DEFAULT_LANGUAGE, }) { if (!data) { return data; } if (!schema) { const modelSchema = getAttributes({ modelName }); schema = addComponentSchema({ parentSchema: modelSchema }); } const schemaKeys = Object.keys(schema); if (!schemaKeys.length) { return data; } if (Array.isArray(data)) { data.forEach(async (entry, index) => { data[index] = await internationalizeData({ modelName, data: entry, schema, lang, }); }); return data; } else { data = internationalizeFields(data, lang, I_18_FIELDS[modelName], null); } schemaKeys.forEach(async (curr) => { if ( schema[curr] && (schema[curr].type === 'component' || schema[curr].collection) ) { if ((schema[curr].repeatable || schema[curr].collection) && data[curr]) { data[curr].forEach(async (entry, index) => { data[curr][index] = await internationalizeData({ modelName: schema[curr].component || schema[curr].collection, data: entry, schema: schema[curr].schema, lang, }); }); } else if (modelName.indexOf('.') === -1) { data[curr] = await internationalizeData({ modelName: schema[curr].component, data: data[curr], schema: schema[curr].schema, lang, }); } } }); return data; } module.exports = { internationalizeData, };
- project_dir/api/homepage/controller.js
/* global strapi */ const { sanitizeEntity } = require('strapi-utils'); const { internationalizeData } = require('../../../utils/controller.util'); async function findOne(ctx) { const { id } = ctx.params; const { lang } = ctx.request.header; const entity = await strapi.services['home-page'].find({ id }); const sanitizedEntity = sanitizeEntity(entity, { model: strapi.models['home-page'], }); const data = internationalizeData({ modelName: 'home-page', data: sanitizedEntity, schema: null, lang, }); return data; } module.exports = { findOne, };
Similarly, you can do for other apis.
Let's discuss your approach in the discussion box or you can hit me up at aastha.talwaria29@gmail.com.
Thanks for reading.
Top comments (0)