feat(i18n, client): migrate meta translations (#40885)
This commit is contained in:
committed by
GitHub
parent
f5f2df187b
commit
1a642ba542
@@ -14,10 +14,11 @@ i18n.use(initReactI18next).init({
|
|||||||
[i18nextCode]: {
|
[i18nextCode]: {
|
||||||
translations: require(`./locales/${clientLocale}/translations.json`),
|
translations: require(`./locales/${clientLocale}/translations.json`),
|
||||||
trending: require(`./locales/${clientLocale}/trending.json`),
|
trending: require(`./locales/${clientLocale}/trending.json`),
|
||||||
intro: require(`./locales/${clientLocale}/intro.json`)
|
intro: require(`./locales/${clientLocale}/intro.json`),
|
||||||
|
metaTags: require(`./locales/${clientLocale}/meta-tags.json`)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ns: ['translations', 'trending', 'intro'],
|
ns: ['translations', 'trending', 'intro', 'metaTags'],
|
||||||
defaultNS: 'translations',
|
defaultNS: 'translations',
|
||||||
returnObjects: true,
|
returnObjects: true,
|
||||||
// Uncomment the next line for debug logging
|
// Uncomment the next line for debug logging
|
||||||
|
@@ -23,6 +23,9 @@ const filesThatShouldExist = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'intro.json'
|
name: 'intro.json'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'meta-tags.json'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
27
client/i18n/locales/chinese/meta-tags.json
Normal file
27
client/i18n/locales/chinese/meta-tags.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"title": "免费学习编程 – 适合忙碌人士的编程课程",
|
||||||
|
"description": "在家学习编程,构建项目,获得认证。自 2014 年以来,已有超过 40,000 名 freeCodeCamp 学员入职谷歌、苹果、亚马逊、微软等科技公司。",
|
||||||
|
"social-description": "Learn to Code — For Free",
|
||||||
|
"keywords": [
|
||||||
|
"javascript",
|
||||||
|
"js",
|
||||||
|
"网站",
|
||||||
|
"web",
|
||||||
|
"开发",
|
||||||
|
"free",
|
||||||
|
"code",
|
||||||
|
"camp",
|
||||||
|
"课程",
|
||||||
|
"html",
|
||||||
|
"css",
|
||||||
|
"react",
|
||||||
|
"redux",
|
||||||
|
"api",
|
||||||
|
"前端",
|
||||||
|
"后端",
|
||||||
|
"学习",
|
||||||
|
"教程",
|
||||||
|
"编程"
|
||||||
|
],
|
||||||
|
"youre-unsubscribed": "你已取消订阅"
|
||||||
|
}
|
@@ -1,31 +1,4 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
|
||||||
"title": "免费学习编程 – 适合忙碌人士的编程课程",
|
|
||||||
"description": "在家学习编程,构建项目,获得认证。自 2014 年以来,已有超过 40,000 名 freeCodeCamp 学员入职谷歌、苹果、亚马逊、微软等科技公司。",
|
|
||||||
"social-description": "Learn to Code — For Free",
|
|
||||||
"keywords": [
|
|
||||||
"javascript",
|
|
||||||
"js",
|
|
||||||
"网站",
|
|
||||||
"web",
|
|
||||||
"开发",
|
|
||||||
"free",
|
|
||||||
"code",
|
|
||||||
"camp",
|
|
||||||
"课程",
|
|
||||||
"html",
|
|
||||||
"css",
|
|
||||||
"react",
|
|
||||||
"redux",
|
|
||||||
"api",
|
|
||||||
"前端",
|
|
||||||
"后端",
|
|
||||||
"学习",
|
|
||||||
"教程",
|
|
||||||
"编程"
|
|
||||||
],
|
|
||||||
"youre-unsubscribed": "你已取消订阅"
|
|
||||||
},
|
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"logged-in-cta-btn": "开始学习(免费)",
|
"logged-in-cta-btn": "开始学习(免费)",
|
||||||
"logged-out-cta-btn": "登录以保存你的学习进度(免费)",
|
"logged-out-cta-btn": "登录以保存你的学习进度(免费)",
|
||||||
|
29
client/i18n/locales/english/meta-tags.json
Normal file
29
client/i18n/locales/english/meta-tags.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"title": "Learn to Code — For Free — Coding Courses for Busy People",
|
||||||
|
"description": "Learn to Code — For Free",
|
||||||
|
"social-description": "Learn to Code — For Free",
|
||||||
|
"keywords": [
|
||||||
|
"javascript",
|
||||||
|
"js",
|
||||||
|
"website",
|
||||||
|
"web",
|
||||||
|
"development",
|
||||||
|
"free",
|
||||||
|
"code",
|
||||||
|
"camp",
|
||||||
|
"course",
|
||||||
|
"courses",
|
||||||
|
"html",
|
||||||
|
"css",
|
||||||
|
"react",
|
||||||
|
"redux",
|
||||||
|
"api",
|
||||||
|
"front",
|
||||||
|
"back",
|
||||||
|
"end",
|
||||||
|
"learn",
|
||||||
|
"tutorial",
|
||||||
|
"programming"
|
||||||
|
],
|
||||||
|
"youre-unsubscribed": "You have been unsubscribed"
|
||||||
|
}
|
@@ -1,33 +1,4 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
|
||||||
"title": "Learn to Code — For Free — Coding Courses for Busy People",
|
|
||||||
"description": "Learn to Code — For Free",
|
|
||||||
"social-description": "Learn to Code — For Free",
|
|
||||||
"keywords": [
|
|
||||||
"javascript",
|
|
||||||
"js",
|
|
||||||
"website",
|
|
||||||
"web",
|
|
||||||
"development",
|
|
||||||
"free",
|
|
||||||
"code",
|
|
||||||
"camp",
|
|
||||||
"course",
|
|
||||||
"courses",
|
|
||||||
"html",
|
|
||||||
"css",
|
|
||||||
"react",
|
|
||||||
"redux",
|
|
||||||
"api",
|
|
||||||
"front",
|
|
||||||
"back",
|
|
||||||
"end",
|
|
||||||
"learn",
|
|
||||||
"tutorial",
|
|
||||||
"programming"
|
|
||||||
],
|
|
||||||
"youre-unsubscribed": "You have been unsubscribed"
|
|
||||||
},
|
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"logged-in-cta-btn": "Get started (it's free)",
|
"logged-in-cta-btn": "Get started (it's free)",
|
||||||
"logged-out-cta-btn": "Sign in to save your progress (it's free)",
|
"logged-out-cta-btn": "Sign in to save your progress (it's free)",
|
||||||
|
29
client/i18n/locales/espanol/meta-tags.json
Normal file
29
client/i18n/locales/espanol/meta-tags.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"title": "Aprende a codificar gratis: cursos de programación para personas ocupadas",
|
||||||
|
"description": "Aprende a codificar en casa. Construye proyectos. Obtén certificaciones. Desde el 2014, más de 40,000 graduados de freeCodeCamp.org han conseguido trabajos en empresas de tecnología como Google, Apple, Amazon y Microsoft.",
|
||||||
|
"social-description": "Learn to Code — For Free",
|
||||||
|
"keywords": [
|
||||||
|
"javascript",
|
||||||
|
"js",
|
||||||
|
"sitio web",
|
||||||
|
"web",
|
||||||
|
"desarrollo",
|
||||||
|
"gratis",
|
||||||
|
"código",
|
||||||
|
"camp",
|
||||||
|
"curso",
|
||||||
|
"cursos",
|
||||||
|
"html",
|
||||||
|
"css",
|
||||||
|
"react",
|
||||||
|
"redux",
|
||||||
|
"api",
|
||||||
|
"front",
|
||||||
|
"back",
|
||||||
|
"end",
|
||||||
|
"aprende",
|
||||||
|
"tutorial",
|
||||||
|
"programación"
|
||||||
|
],
|
||||||
|
"youre-unsubscribed": "Tu suscripción ha sido cancelada"
|
||||||
|
}
|
@@ -1,33 +1,4 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
|
||||||
"title": "Aprende a codificar gratis: cursos de programación para personas ocupadas",
|
|
||||||
"description": "Aprende a codificar en casa. Construye proyectos. Obtén certificaciones. Desde el 2014, más de 40,000 graduados de freeCodeCamp.org han conseguido trabajos en empresas de tecnología como Google, Apple, Amazon y Microsoft.",
|
|
||||||
"social-description": "Learn to Code — For Free",
|
|
||||||
"keywords": [
|
|
||||||
"javascript",
|
|
||||||
"js",
|
|
||||||
"sitio web",
|
|
||||||
"web",
|
|
||||||
"desarrollo",
|
|
||||||
"gratis",
|
|
||||||
"código",
|
|
||||||
"camp",
|
|
||||||
"curso",
|
|
||||||
"cursos",
|
|
||||||
"html",
|
|
||||||
"css",
|
|
||||||
"react",
|
|
||||||
"redux",
|
|
||||||
"api",
|
|
||||||
"front",
|
|
||||||
"back",
|
|
||||||
"end",
|
|
||||||
"aprende",
|
|
||||||
"tutorial",
|
|
||||||
"programación"
|
|
||||||
],
|
|
||||||
"youre-unsubscribed": "Tu suscripción ha sido cancelada"
|
|
||||||
},
|
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"logged-in-cta-btn": "Empieza es gratis",
|
"logged-in-cta-btn": "Empieza es gratis",
|
||||||
"logged-out-cta-btn": "Inicia sesión para guardar tu progreso (es gratis)",
|
"logged-out-cta-btn": "Inicia sesión para guardar tu progreso (es gratis)",
|
||||||
|
31
client/i18n/meta-tags-schema.js
Normal file
31
client/i18n/meta-tags-schema.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
const metaTagsSchema = {
|
||||||
|
title: 'Learn to Code — For Free — Coding Courses for Busy People',
|
||||||
|
description: 'Learn to Code — For Free',
|
||||||
|
'social-description': 'Learn to Code — For Free',
|
||||||
|
keywords: [
|
||||||
|
'javascript',
|
||||||
|
'js',
|
||||||
|
'website',
|
||||||
|
'web',
|
||||||
|
'development',
|
||||||
|
'free',
|
||||||
|
'code',
|
||||||
|
'camp',
|
||||||
|
'course',
|
||||||
|
'courses',
|
||||||
|
'html',
|
||||||
|
'css',
|
||||||
|
'react',
|
||||||
|
'redux',
|
||||||
|
'api',
|
||||||
|
'front',
|
||||||
|
'back',
|
||||||
|
'end',
|
||||||
|
'learn',
|
||||||
|
'tutorial',
|
||||||
|
'programming'
|
||||||
|
],
|
||||||
|
'youre-unsubscribed': 'You have been unsubscribed'
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.metaTagsSchema = metaTagsSchema;
|
@@ -5,6 +5,7 @@ const { availableLangs } = require('./allLangs');
|
|||||||
const { trendingSchema } = require('./trending-schema');
|
const { trendingSchema } = require('./trending-schema');
|
||||||
const { motivationSchema } = require('./motivation-schema');
|
const { motivationSchema } = require('./motivation-schema');
|
||||||
const { introSchema } = require('./intro-schema');
|
const { introSchema } = require('./intro-schema');
|
||||||
|
const { metaTagsSchema } = require('./meta-tags-schema');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flattens a nested object structure into a single
|
* Flattens a nested object structure into a single
|
||||||
@@ -105,6 +106,7 @@ const translationSchemaKeys = Object.keys(flattenAnObject(translationsSchema));
|
|||||||
const trendingSchemaKeys = Object.keys(flattenAnObject(trendingSchema));
|
const trendingSchemaKeys = Object.keys(flattenAnObject(trendingSchema));
|
||||||
const motivationSchemaKeys = Object.keys(flattenAnObject(motivationSchema));
|
const motivationSchemaKeys = Object.keys(flattenAnObject(motivationSchema));
|
||||||
const introSchemaKeys = Object.keys(flattenAnObject(introSchema));
|
const introSchemaKeys = Object.keys(flattenAnObject(introSchema));
|
||||||
|
const metaTagsSchemaKeys = Object.keys(flattenAnObject(metaTagsSchema));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function that checks the translations.json file
|
* Function that checks the translations.json file
|
||||||
@@ -236,7 +238,35 @@ const introSchemaValidation = languages => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const metaTagsSchemaValidation = languages => {
|
||||||
|
languages.forEach(language => {
|
||||||
|
const filePath = path.join(
|
||||||
|
__dirname,
|
||||||
|
`/locales/${language}/meta-tags.json`
|
||||||
|
);
|
||||||
|
const fileData = fs.readFileSync(filePath);
|
||||||
|
const fileJson = JSON.parse(fileData);
|
||||||
|
const fileKeys = Object.keys(flattenAnObject(fileJson));
|
||||||
|
findMissingKeys(fileKeys, metaTagsSchemaKeys, `${language}/meta-tags.json`);
|
||||||
|
findExtraneousKeys(
|
||||||
|
fileKeys,
|
||||||
|
metaTagsSchemaKeys,
|
||||||
|
`${language}/metaTags.json`
|
||||||
|
);
|
||||||
|
const emptyKeys = noEmptyObjectValues(fileJson);
|
||||||
|
if (emptyKeys.length) {
|
||||||
|
throw new Error(
|
||||||
|
`${language}/metaTags.json has these empty keys: ${emptyKeys.join(
|
||||||
|
', '
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
console.info(`${language} metaTags.json is correct!`);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
translationSchemaValidation(availableLangs.client);
|
translationSchemaValidation(availableLangs.client);
|
||||||
trendingSchemaValidation(availableLangs.client);
|
trendingSchemaValidation(availableLangs.client);
|
||||||
motivationSchemaValidation(availableLangs.client);
|
motivationSchemaValidation(availableLangs.client);
|
||||||
introSchemaValidation(availableLangs.client);
|
introSchemaValidation(availableLangs.client);
|
||||||
|
metaTagsSchemaValidation(availableLangs.client);
|
||||||
|
@@ -3,35 +3,6 @@
|
|||||||
* structure here exactly, the tests will fail.
|
* structure here exactly, the tests will fail.
|
||||||
*/
|
*/
|
||||||
const translationsSchema = {
|
const translationsSchema = {
|
||||||
meta: {
|
|
||||||
title: 'Learn to Code — For Free — Coding Courses for Busy People',
|
|
||||||
description: 'Learn to Code — For Free',
|
|
||||||
'social-description': 'Learn to Code — For Free',
|
|
||||||
keywords: [
|
|
||||||
'javascript',
|
|
||||||
'js',
|
|
||||||
'website',
|
|
||||||
'web',
|
|
||||||
'development',
|
|
||||||
'free',
|
|
||||||
'code',
|
|
||||||
'camp',
|
|
||||||
'course',
|
|
||||||
'courses',
|
|
||||||
'html',
|
|
||||||
'css',
|
|
||||||
'react',
|
|
||||||
'redux',
|
|
||||||
'api',
|
|
||||||
'front',
|
|
||||||
'back',
|
|
||||||
'end',
|
|
||||||
'learn',
|
|
||||||
'tutorial',
|
|
||||||
'programming'
|
|
||||||
],
|
|
||||||
'youre-unsubscribed': 'You have been unsubscribed'
|
|
||||||
},
|
|
||||||
buttons: {
|
buttons: {
|
||||||
'logged-in-cta-btn': "Get started (it's free)",
|
'logged-in-cta-btn': "Get started (it's free)",
|
||||||
'logged-out-cta-btn': "Sign in to save your progress (it's free)",
|
'logged-out-cta-btn': "Sign in to save your progress (it's free)",
|
||||||
|
@@ -15,7 +15,7 @@ function ShowUnsubscribed({ unsubscribeId }) {
|
|||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>{t('meta.youre-unsubscribed')} | freeCodeCamp.org</title>
|
<title>{t('metaTags:youre-unsubscribed')} | freeCodeCamp.org</title>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
<Grid>
|
<Grid>
|
||||||
<main>
|
<main>
|
||||||
|
@@ -21,7 +21,7 @@ export const Landing = ({ page = 'landing' }) => {
|
|||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>{t('meta.title')}</title>
|
<title>{t('metaTags:title')}</title>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
<main className='landing-page'>
|
<main className='landing-page'>
|
||||||
<Grid>
|
<Grid>
|
||||||
|
@@ -152,9 +152,9 @@ class DefaultLayout extends Component {
|
|||||||
meta={[
|
meta={[
|
||||||
{
|
{
|
||||||
name: 'description',
|
name: 'description',
|
||||||
content: t('meta.description')
|
content: t('metaTags:description')
|
||||||
},
|
},
|
||||||
{ name: 'keywords', content: t('meta.keywords') }
|
{ name: 'keywords', content: t('metaTags:keywords') }
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<link
|
<link
|
||||||
|
@@ -61,7 +61,7 @@ export const LearnPage = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<LearnLayout>
|
<LearnLayout>
|
||||||
<Helmet title={t('meta.title')} />
|
<Helmet title={t('metaTags:title')} />
|
||||||
<Grid>
|
<Grid>
|
||||||
<Row>
|
<Row>
|
||||||
<Col md={8} mdOffset={2} sm={10} smOffset={1} xs={12}>
|
<Col md={8} mdOffset={2} sm={10} smOffset={1} xs={12}>
|
||||||
|
@@ -16,7 +16,7 @@ export const getheadTagComponents = () => {
|
|||||||
<link href={pathToBootstrap} key='bootstrap-min' rel='stylesheet' />,
|
<link href={pathToBootstrap} key='bootstrap-min' rel='stylesheet' />,
|
||||||
<meta content='freeCodeCamp.org' key='og:title' name='og:title' />,
|
<meta content='freeCodeCamp.org' key='og:title' name='og:title' />,
|
||||||
<meta
|
<meta
|
||||||
content={i18next.t('meta.social-description')}
|
content={i18next.t('metaTags:social-description')}
|
||||||
key='og:description'
|
key='og:description'
|
||||||
name='og:description'
|
name='og:description'
|
||||||
/>,
|
/>,
|
||||||
@@ -37,7 +37,7 @@ export const getheadTagComponents = () => {
|
|||||||
name='twitter:title'
|
name='twitter:title'
|
||||||
/>,
|
/>,
|
||||||
<meta
|
<meta
|
||||||
content={i18next.t('meta.social-description')}
|
content={i18next.t('metaTags:social-description')}
|
||||||
key='twitter:description'
|
key='twitter:description'
|
||||||
name='twitter:description'
|
name='twitter:description'
|
||||||
/>,
|
/>,
|
||||||
|
Reference in New Issue
Block a user