Skip to content

Commit

Permalink
Revert "Remove node's url from lib/i18n-utils. (#38560)"
Browse files Browse the repository at this point in the history
This reverts commit 6d0dacc.
  • Loading branch information
griffbrad authored Jan 6, 2020
1 parent 528768b commit fcdbb8d
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 99 deletions.
41 changes: 17 additions & 24 deletions client/lib/i18n-utils/switch-locale.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import i18n from 'i18n-calypso';
import debugFactory from 'debug';
import { map, includes } from 'lodash';
import { parse as parseUrl, format as formatUrl } from 'url';

/**
* Internal dependencies
*/
import { isDefaultLocale, getLanguage } from './utils';
import { getUrlFromParts } from 'lib/url/url-parts';

const debug = debugFactory( 'calypso:i18n' );

Expand All @@ -18,14 +18,13 @@ const getPromises = {};
/**
* De-duplicates repeated GET fetches of the same URL while one is taking place.
* Once it's finished, it'll allow for the same request to be done again.
*
* @param {string} url The URL to fetch
*
* @returns {Promise} The fetch promise.
*/
function dedupedGet( url ) {
if ( ! ( url in getPromises ) ) {
getPromises[ url ] = globalThis.fetch( url ).finally( () => delete getPromises[ url ] );
getPromises[ url ] = fetch( url ).finally( () => delete getPromises[ url ] );
}

return getPromises[ url ];
Expand All @@ -36,7 +35,7 @@ function dedupedGet( url ) {
* Normally it should only serve as a helper function for `getLanguageFileUrl`,
* but we export it here still in help with the test suite.
*
* @returns {string} The path URL to the language files.
* @return {String} The path URL to the language files.
*/
export function getLanguageFilePathUrl() {
const protocol = typeof window === 'undefined' ? 'https://' : '//'; // use a protocol-relative path in the browser
Expand All @@ -48,11 +47,11 @@ export function getLanguageFilePathUrl() {
* Get the language file URL for the given locale and file type, js or json.
* A revision cache buster will be appended automatically if `setLangRevisions` has been called beforehand.
*
* @param {string} localeSlug A locale slug. e.g. fr, jp, zh-tw
* @param {string} fileType The desired file type, js or json. Default to json.
* @param {object} languageRevisions An optional language revisions map. If it exists, the function will append the revision within as cache buster.
* @param {String} localeSlug A locale slug. e.g. fr, jp, zh-tw
* @param {String} fileType The desired file type, js or json. Default to json.
* @param {Object} languageRevisions An optional language revisions map. If it exists, the function will append the revision within as cache buster.
*
* @returns {string} A language file URL.
* @return {String} A language file URL.
*/
export function getLanguageFileUrl( localeSlug, fileType = 'json', languageRevisions = {} ) {
if ( ! includes( [ 'js', 'json' ], fileType ) ) {
Expand Down Expand Up @@ -145,24 +144,19 @@ export default function switchLocale( localeSlug ) {
}

export function loadUserUndeployedTranslations( currentLocaleSlug ) {
if ( typeof window === 'undefined' || ! window.location || ! window.location.search ) {
if ( ! location || ! location.search ) {
return;
}

const search = new URLSearchParams( window.location.search );
// TODO: replace with Object.fromEntries when available (core-js@3).
const params = {};
for ( const [ key, value ] of search.entries() ) {
params[ key ] = value;
}
const parsedURL = parseUrl( location.search, true );

const {
'load-user-translations': username,
project = 'wpcom',
translationSet = 'default',
translationStatus = 'current',
locale = currentLocaleSlug,
} = params;
} = parsedURL.query;

if ( ! username ) {
return;
Expand Down Expand Up @@ -192,18 +186,17 @@ export function loadUserUndeployedTranslations( currentLocaleSlug ) {
format: 'json',
};

const requestUrl = getUrlFromParts( {
const requestUrl = formatUrl( {
protocol: 'https:',
host: 'translate.wordpress.com',
pathname,
query,
} );

return window
.fetch( requestUrl.href, {
headers: { Accept: 'application/json' },
credentials: 'include',
} )
return fetch( requestUrl, {
headers: { Accept: 'application/json' },
credentials: 'include',
} )
.then( res => res.json() )
.then( translations => i18n.addTranslations( translations ) );
}
Expand Down Expand Up @@ -244,8 +237,8 @@ function switchWebpackCSS( isRTL ) {
* Loads a CSS stylesheet into the page.
*
* @param {string} cssUrl URL of a CSS stylesheet to be loaded into the page
* @param {window.Element} currentLink an existing <link> DOM element before which we want to insert the new one
* @returns {Promise<string>} the new <link> DOM element after the CSS has been loaded
* @param {Element} currentLink an existing <link> DOM element before which we want to insert the new one
* @returns {Promise<String>} the new <link> DOM element after the CSS has been loaded
*/
function loadCSS( cssUrl, currentLink ) {
return new Promise( resolve => {
Expand Down
54 changes: 23 additions & 31 deletions client/lib/i18n-utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
* External dependencies
*/
import { find, isString, map, pickBy, includes, endsWith } from 'lodash';
import url from 'url';
import { getLocaleSlug } from 'i18n-calypso';

/**
* Internal dependencies
*/
import config from 'config';
import { languages } from 'languages';
import { getUrlParts, getUrlFromParts } from 'lib/url/url-parts';

/**
* a locale can consist of three component
Expand All @@ -30,7 +30,7 @@ export function getPathParts( path ) {
* Checks if provided locale is a default one.
*
* @param {string} locale - locale slug (eg: 'fr')
* @returns {boolean} true when the default locale is provided
* @return {boolean} true when the default locale is provided
*/
export function isDefaultLocale( locale ) {
return locale === config( 'i18n_default_locale_slug' );
Expand All @@ -40,7 +40,7 @@ export function isDefaultLocale( locale ) {
* Checks if provided locale has a parentLangSlug and is therefore a locale variant
*
* @param {string} locale - locale slug (eg: 'fr')
* @returns {boolean} true when the locale has a parentLangSlug
* @return {boolean} true when the locale has a parentLangSlug
*/
export function isLocaleVariant( locale ) {
if ( ! isString( locale ) ) {
Expand All @@ -66,9 +66,8 @@ export function isLocaleRtl( locale ) {
* Checks against a list of locales that don't have any GP translation sets
* A 'translation set' refers to a collection of strings to be translated see:
* https://glotpress.blog/the-manual/translation-sets/
*
* @param {string} locale - locale slug (eg: 'fr')
* @returns {boolean} true when the locale is NOT a member of the exception list
* @return {boolean} true when the locale is NOT a member of the exception list
*/
export function canBeTranslated( locale ) {
return [ 'en', 'sr_latin' ].indexOf( locale ) === -1;
Expand All @@ -77,17 +76,16 @@ export function canBeTranslated( locale ) {
/**
* Return a list of all supported language slugs
*
* @returns {Array} A list of all supported language slugs
* @return {Array} A list of all supported language slugs
*/
export function getLanguageSlugs() {
return map( languages, 'langSlug' );
}

/**
* Matches and returns language from config.languages based on the given localeSlug
*
* @param {string} langSlug locale slug of the language to match
* @returns {object|undefined} An object containing the locale data or undefined.
* @param {String} langSlug locale slug of the language to match
* @return {Object|undefined} An object containing the locale data or undefined.
*/
export function getLanguage( langSlug ) {
if ( localeRegex.test( langSlug ) ) {
Expand All @@ -104,12 +102,11 @@ export function getLanguage( langSlug ) {

/**
* Assuming that locale is adding at the end of path, retrieves the locale if present.
*
* @param {string} path - original path
* @returns {string|undefined} The locale slug if present or undefined
* @return {string|undefined} The locale slug if present or undefined
*/
export function getLocaleFromPath( path ) {
const urlParts = getUrlParts( path );
const urlParts = url.parse( path );
const locale = getPathParts( urlParts.pathname ).pop();

return 'undefined' === typeof getLanguage( locale ) ? undefined : locale;
Expand All @@ -125,7 +122,7 @@ export function getLocaleFromPath( path ) {
* @returns {string} original path with new locale slug
*/
export function addLocaleToPath( path, locale ) {
const urlParts = getUrlParts( path );
const urlParts = url.parse( path );
const queryString = urlParts.search || '';

return removeLocaleFromPath( urlParts.pathname ) + `/${ locale }` + queryString;
Expand Down Expand Up @@ -181,38 +178,34 @@ const urlLocalizationMapping = {

export function localizeUrl( fullUrl, locale ) {
const localeSlug = locale || ( typeof getLocaleSlug === 'function' ? getLocaleSlug() : 'en' );
const urlParts = getUrlParts( String( fullUrl ) );
const urlParts = url.parse( String( fullUrl ) );

if ( ! urlParts.host ) {
if ( ! urlParts ) {
return fullUrl;
}

// Let's unify the URL.
urlParts.protocol = 'https:';
// Let's use `host` for everything.
delete urlParts.hostname;

urlParts.protocol = 'https';
if ( 'en.wordpress.com' === urlParts.hostname ) {
urlParts.host = 'wordpress.com';
}
if ( ! endsWith( urlParts.pathname, '.php' ) ) {
urlParts.pathname = ( urlParts.pathname + '/' ).replace( /\/+$/, '/' );
}

if ( ! localeSlug || 'en' === localeSlug ) {
if ( 'en.wordpress.com' === urlParts.host ) {
if ( 'en.wordpress.com' === urlParts.hostname ) {
urlParts.host = 'wordpress.com';
return getUrlFromParts( urlParts ).href;
return url.format( urlParts );
}
return fullUrl;
}

if ( 'en.wordpress.com' === urlParts.host ) {
urlParts.host = 'wordpress.com';
}

const lookup = [ urlParts.host, urlParts.host + urlParts.pathname ];
const lookup = [ urlParts.hostname, urlParts.hostname + urlParts.pathname ];

for ( let i = lookup.length - 1; i >= 0; i-- ) {
if ( lookup[ i ] in urlLocalizationMapping ) {
return getUrlFromParts( urlLocalizationMapping[ lookup[ i ] ]( urlParts, localeSlug ) ).href;
return url.format( urlLocalizationMapping[ lookup[ i ] ]( urlParts, localeSlug ) );
}
}

Expand All @@ -223,12 +216,11 @@ export function localizeUrl( fullUrl, locale ) {
/**
* Removes the trailing locale slug from the path, if it is present.
* '/start/en' => '/start', '/start' => '/start', '/start/flow/fr' => '/start/flow', '/start/flow' => '/start/flow'
*
* @param {string} path - original path
* @returns {string} original path minus locale slug
*/
export function removeLocaleFromPath( path ) {
const urlParts = getUrlParts( path );
const urlParts = url.parse( path );
const queryString = urlParts.search || '';
const parts = getPathParts( urlParts.pathname );
const locale = parts.pop();
Expand All @@ -243,9 +235,9 @@ export function removeLocaleFromPath( path ) {
/**
* Filter out unexpected values from the given language revisions object.
*
* @param {object} languageRevisions A candidate language revisions object for filtering.
* @param {Object} languageRevisions A candidate language revisions object for filtering.
*
* @returns {object} A valid language revisions object derived from the given one.
* @return {Object} A valid language revisions object derived from the given one.
*/
export function filterLanguageRevisions( languageRevisions ) {
const langSlugs = getLanguageSlugs();
Expand Down
2 changes: 1 addition & 1 deletion client/lib/url/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ export { default as isHttps } from './is-https';
export { addSchemeIfMissing, setUrlScheme } from './scheme-utils';
export { decodeURIIfValid, decodeURIComponentIfValid } from './decode-utils';
export { default as format } from './format';
export { getUrlParts, getUrlFromParts } from './url-parts';
export { getUrlParts } from './url-parts';
43 changes: 0 additions & 43 deletions client/lib/url/url-parts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,6 @@ interface UrlParts {
password: string;
}

interface OptionalUrlParts {
protocol?: string;
host?: string;
hostname?: string;
port?: string;
origin?: string;
pathname?: string;
hash?: string;
search?: string;
searchParams?: URLSearchParams;
username?: string;
password?: string;
}

type UrlPartKey = keyof UrlParts;

const EMPTY_URL: Readonly< UrlParts > = Object.freeze( {
Expand Down Expand Up @@ -114,32 +100,3 @@ export function getUrlParts( url: URLString | URL ): UrlParts {

return pathParts;
}

/**
* Returns a URL object built from the provided URL parts.
*
* @param parts the provided URL parts.
*
* @returns the generated URL object.
*/
export function getUrlFromParts( parts: OptionalUrlParts ): URL {
if ( ! parts?.protocol ) {
throw new Error( 'getUrlFromParts: protocol missing.' );
}

if ( ! parts.host && ! parts.hostname ) {
throw new Error( 'getUrlFromParts: host missing.' );
}

const result = new URL( BASE_URL );

// Apply 'host' first, since it includes both hostname and port.
result.host = parts.host ?? result.host;

for ( const part of URL_PART_KEYS ) {
if ( part !== 'host' && part !== 'origin' && part !== 'searchParams' ) {
result[ part ] = parts[ part ] ?? result[ part ];
}
}
return result;
}

0 comments on commit fcdbb8d

Please sign in to comment.