fix: some i18n bugs (#5400)

* fix: i18n plugin not work in IE11

* feat: add setting for block cookie setting i18n locale (#5437)

* feat: add setting for block cookie setting i18n locale

* add I18nAppConfig to IAppConfig & change appConfig key to i18n

Co-authored-by: liyidong <liyidong@baidu.com>
Co-authored-by: leo.lyd <leo.lyd@alibaba-inc.com>

* fix locale will always in default when execute history.push in cookie blocked mode (#5441)

* feat: add setting for block cookie setting i18n locale

* add I18nAppConfig to IAppConfig & change appConfig key to i18n

* fix: fix locale will always in default when execute history.push in cookie blocked mode

Co-authored-by: liyidong <liyidong@baidu.com>
Co-authored-by: leo.lyd <leo.lyd@alibaba-inc.com>

* fix: modifyHistory params delivery error (#5442)

* feat: add setting for block cookie setting i18n locale

* add I18nAppConfig to IAppConfig & change appConfig key to i18n

* fix: fix locale will always in default when execute history.push in cookie blocked mode

* fix: fix modifyHistory params delivery error

Co-authored-by: liyidong <liyidong@baidu.com>
Co-authored-by: leo.lyd <leo.lyd@alibaba-inc.com>

* feat: no defaultLocale return from getDetectedLocaleFromPathname & adjust detect locale sequence in getDetectedLocale function (#5458)

* feat: add setting for block cookie setting i18n locale

* add I18nAppConfig to IAppConfig & change appConfig key to i18n

* fix: fix locale will always in default when execute history.push in cookie blocked mode

* fix: fix modifyHistory params delivery error

* feat: no defaultLocale return from getDetectedLocaleFromPathname & adjust detect locale sequence in getDetectedLocale function

Co-authored-by: liyidong <liyidong@baidu.com>
Co-authored-by: leo.lyd <leo.lyd@alibaba-inc.com>

* fix: redirect incorrect i18n page (#5461)

* fix: redirect incorrect i18n page

* fix: eslint warning

* fix: cookie path

Co-authored-by: srhb18 <srhb18@163.com>
Co-authored-by: liyidong <liyidong@baidu.com>
Co-authored-by: leo.lyd <leo.lyd@alibaba-inc.com>
This commit is contained in:
luhc228 2022-08-25 15:37:17 +08:00 committed by GitHub
parent 201393172e
commit 1ee7db0419
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 108 additions and 72 deletions

View File

@ -5,7 +5,8 @@
{
"locales": [
"zh-CN",
"en-US"
"en-US",
"zh-HK"
],
"defaultLocale": "zh-CN",
"autoRedirect": true

View File

@ -1,4 +1,5 @@
export const LOCALES = {
ENGLISH: 'en-US',
ZH_CN: 'zh-CN'
ZH_CN: 'zh-CN',
zh_HK: 'zh-HK',
};

View File

@ -23,6 +23,18 @@ export const messages = {
basicLayout: '主布局',
userLayout: '用户布局',
notFound: '未找到页面',
userLogin: '用户登录页'
userLogin: '用户登录页',
},
[LOCALES.zh_HK]: {
homeTitle: '首頁',
aboutTitle: '關於',
currentLocale: '當前語言',
defaultLocale: '默認語言',
configuredLocales: '配置的語言',
localeSwitcher: '語言切換',
basicLayout: '主佈局',
userLayout: '用戶佈局',
notFound: '未找到頁面',
userLogin: '用戶登錄頁',
},
};

View File

@ -1,6 +1,6 @@
{
"name": "build-plugin-ice-i18n",
"version": "0.2.1",
"version": "0.2.2",
"description": "ICE i18n build-scripts plugin",
"author": "ice-admin@alibaba-inc.com",
"homepage": "https://github.com/alibaba/ice#readme",

View File

@ -4,7 +4,7 @@ import { I18nConfig } from './types';
import { LOCALE_COOKIE_KEY } from './constants';
export default async function (
{ onGetWebpackConfig, getValue, applyMethod }: IPluginAPI,
{ onGetWebpackConfig, getValue, applyMethod }: IPluginAPI,
i18nConfig: I18nConfig,
) {
checkI18nConfig(i18nConfig);
@ -20,8 +20,8 @@ export default async function (
// copy templates to .ice/i18n dir
applyMethod(
'addPluginTemplate',
path.join(__dirname, 'templates'),
'addPluginTemplate',
path.join(__dirname, 'templates'),
{ LOCALE_COOKIE_KEY, i18nConfig, i18nRouting }
);
applyMethod(
@ -39,12 +39,23 @@ export default async function (
// export API
// import { useLocale, getAllLocales, getDefaultLocale, getLocale } from 'ice';
applyMethod(
'addExport',
{
source: './plugins/i18n',
'addExport',
{
source: './plugins/i18n',
importSource: '$$ice/plugins/i18n',
exportMembers: ['useLocale', 'getAllLocales', 'getDefaultLocale', 'getLocale', 'setLocale']
});
}
);
// set I18nAppConfig to IAppConfig
applyMethod(
'addAppConfigTypes',
{
source: '../plugins/i18n/pluginRuntime/types',
specifier: '{ I18nAppConfig }',
exportName: 'i18n?: I18nAppConfig'
}
);
}
function checkI18nConfig(i18nConfig: I18nConfig) {

View File

@ -1,10 +1,10 @@
import * as React from 'react';
import { History } from 'history';
import Cookies from 'universal-cookie';
import { I18nProvider, getLocaleFromCookies } from '$ice/i18n';
import { I18nProvider, getLocaleFromCookies, getLocale } from '$ice/i18n';
import { LOCALE_COOKIE_KEY } from './constants';
import getLocaleData from './utils/getLocaleData';
import { I18nConfig } from './types';
import { I18nConfig, I18nAppConfig } from './types';
import normalizeLocalePath from './utils/normalizeLocalePath';
import addRoutesByLocales from './utils/addRoutesByLocales';
import getRedirectIndexRoute from './utils/getRedirectIndexRoute';
@ -12,12 +12,13 @@ import getRedirectIndexRoute from './utils/getRedirectIndexRoute';
export default ({ modifyRoutes, buildConfig, addProvider, appConfig }) => {
const { i18n: i18nConfig } = buildConfig;
const { i18nRouting, autoRedirect } = i18nConfig;
const { router: appConfigRouter = {} } = appConfig;
const { router: appConfigRouter = {}, i18n: i18nAppConfig = {} } = appConfig;
const { blockCookie = false } = i18nAppConfig;
const { history = {}, basename } = appConfigRouter;
if (i18nRouting !== false) {
modifyRoutes((routes) => {
// routes 值是被 formatRoutes 方法处理后返回的结果
// routes 值是被 formatRoutes 方法处理后返回的结果
const modifiedRoutes = addRoutesByLocales(routes, i18nConfig);
if (autoRedirect === true) {
@ -38,11 +39,12 @@ export default ({ modifyRoutes, buildConfig, addProvider, appConfig }) => {
if (!process.env.__IS_SERVER__) {
const { detectedLocale } = getLocaleData({ url: window.location, i18nConfig, basename });
setInitICELocaleToCookie(detectedLocale);
const cookieBlocked = typeof blockCookie === 'function' ? blockCookie() : blockCookie;
setInitICELocaleToCookie(detectedLocale, cookieBlocked);
}
if (i18nRouting !== false) {
modifyHistory(history, i18nConfig, basename);
modifyHistory(history, i18nConfig, i18nAppConfig, basename);
}
};
@ -56,20 +58,21 @@ function Provider() {
};
}
function setInitICELocaleToCookie(locale: string) {
function setInitICELocaleToCookie(locale: string, cookieBlocked: boolean) {
const cookies = new Cookies();
const iceLocale = cookies.get(LOCALE_COOKIE_KEY);
if (!iceLocale) {
cookies.set(LOCALE_COOKIE_KEY, locale);
if (!cookieBlocked) {
cookies.set(LOCALE_COOKIE_KEY, locale, { path: '/' });
}
}
function modifyHistory(history: History, i18nConfig: I18nConfig, basename?: string) {
function modifyHistory(history: History, i18nConfig: I18nConfig, i18nAppConfig: I18nAppConfig, basename?: string) {
const originHistory = { ...history };
const { defaultLocale } = i18nConfig;
const { blockCookie = false } = i18nAppConfig;
const cookieBlocked = typeof blockCookie === 'function' ? blockCookie() : blockCookie;
function getLocalePath(
originPathname: string,
originPathname: string,
locale: string,
) {
const localePathResult = normalizeLocalePath(originPathname, i18nConfig, basename);
@ -87,15 +90,15 @@ function modifyHistory(history: History, i18nConfig: I18nConfig, basename?: stri
return path;
}
history.push = function(path: string | Location, state?: unknown) {
const locale = getLocaleFromCookies() || defaultLocale;
history.push = function(path: string | Location, state?: unknown, localeParam?: string) {
const locale = localeParam || (cookieBlocked ? getLocale() : getLocaleFromCookies()) || defaultLocale;
const pathname = getPathname(path);
const localePath = getLocalePath(pathname, locale);
originHistory.push(localePath, state);
};
history.replace = function(path: string | Location, state?: unknown) {
const locale = getLocaleFromCookies() || defaultLocale;
history.replace = function(path: string | Location, state?: unknown, localeParam?: string) {
const locale = localeParam || (cookieBlocked ? getLocale() : getLocaleFromCookies()) || defaultLocale;
const pathname = getPathname(path);
const localePath = getLocalePath(pathname, locale);
originHistory.replace(localePath, state);

View File

@ -55,7 +55,7 @@ export function getAllLocales(): string[] {
}
<% if (i18nRouting !== false) {%>
function getDetectedLocaleFromPath(locales: string[], defaultLocale: string) {
function getDetectedLocaleFromPath(locales: string[]) {
const appConfig = getAppConfig();
if (history === null) {
if (process.env.NODE_ENV !== 'production') {
@ -65,7 +65,7 @@ function getDetectedLocaleFromPath(locales: string[], defaultLocale: string) {
}
const { location: { pathname } } = history;
return getDetectedLocaleFromPathname({ pathname, locales, defaultLocale, basename: appConfig?.router?.basename });
return getDetectedLocaleFromPathname({ pathname, locales, basename: appConfig?.router?.basename });
}
<% } %>
@ -75,7 +75,7 @@ function getDetectedLocaleFromPath(locales: string[], defaultLocale: string) {
export function getLocale(): string {
return (
<% if (i18nRouting !== false) {%>
getDetectedLocaleFromPath(locales, defaultLocale) ||
getDetectedLocaleFromPath(locales) ||
<% } %>
cookies.get(LOCALE_COOKIE_KEY) ||
defaultLocale
@ -90,7 +90,16 @@ export function setLocale(locale: string) {
}
function setLocaleToCookies(locale: string) {
cookies.set(LOCALE_COOKIE_KEY, locale, { path: '/' });
<% if (i18nRouting !== false) {%>
const { i18n: i18nConfig = {} } = getAppConfig();
const { blockCookie = false } = i18nConfig;
const cookieBlocked = typeof blockCookie === 'function' ? blockCookie() : blockCookie;
if (!cookieBlocked) {
<% } %>
cookies.set(LOCALE_COOKIE_KEY, locale, { path: '/' });
<% if (i18nRouting !== false) {%>
}
<% } %>
}
export function getLocaleFromCookies() {

View File

@ -7,4 +7,8 @@ export interface I18nConfig {
autoRedirect?: true;
// 国际化路由
i18nRouting?: false;
}
}
export interface I18nAppConfig {
blockCookie?: boolean | Function;
}

View File

@ -1,27 +1,21 @@
import replaceBasename from './replaceBasename';
interface GetDetectedLocalFromPathnameParams {
pathname: string;
locales: string[];
basename?: string;
}
/**
* pathname
*/
function getDetectedLocaleFromPathname(
{
pathname,
locales,
defaultLocale,
basename,
}: {
pathname: string;
locales: string[];
defaultLocale: string;
basename?: string;
}) {
function getDetectedLocaleFromPathname({ pathname, locales, basename }: GetDetectedLocalFromPathnameParams) {
const normalizedPathname = replaceBasename(pathname, basename);
const pathnameParts = normalizedPathname.split('/').filter(pathnamePart => pathnamePart);
let detectedLocale = defaultLocale;
// eslint-disable-next-line no-restricted-syntax
for (const locale of locales) {
// 从路径获取locale时默认路径不再命中默认语言返回空字符串调用业务需执行兜底默认语言
let detectedLocale = '';
for (let index = 0; index < locales.length; index++) {
const locale = locales[index];
if (pathnameParts[0] === locale) {
detectedLocale = locale;
break;

View File

@ -32,13 +32,13 @@ export default function getLocaleData({
}
function getDetectedLocale(
{
pathname,
{
pathname,
i18nConfig,
headers = {},
basename,
}: {
pathname: string,
}: {
pathname: string,
i18nConfig: I18nConfig,
headers?: Record<string, string>,
basename?: string,
@ -49,14 +49,15 @@ function getDetectedLocale(
} else {
cookies = (new Cookies()).getAll();
}
const { defaultLocale, locales, i18nRouting } = i18nConfig;
const detectedLocale =
getLocaleFromCookie(locales, cookies) ||
getPreferredLocale(locales, headers) ||
(i18nRouting === false ? undefined : getDetectedLocaleFromPathname({ pathname, locales, basename, defaultLocale })) ||
defaultLocale;
// 检测获取Locale的优先级为path前缀 > cookie > 浏览器语言设置 > 默认语言
const detectedLocale =
(i18nRouting === false ? undefined : getDetectedLocaleFromPathname({ pathname, locales, basename })) ||
getLocaleFromCookie(locales, cookies) ||
getPreferredLocale(locales, headers) ||
defaultLocale;
return detectedLocale;
}
@ -66,7 +67,7 @@ function getDetectedLocale(
* pathname `/` `/${basename}`
*/
function getRedirectUrl(
pathname: string,
pathname: string,
i18nConfig: I18nConfig & { detectedLocale: string },
basename?: string,
) {
@ -74,9 +75,9 @@ function getRedirectUrl(
const normalizedPathname = replaceBasename(pathname, basename);
const isRootPath = normalizedPathname === '/';
if (
autoRedirect === true &&
i18nRouting !== false &&
isRootPath &&
autoRedirect === true &&
i18nRouting !== false &&
isRootPath &&
defaultLocale !== detectedLocale
) {
return `/${detectedLocale}`;
@ -94,7 +95,7 @@ function getPreferredLocale(locales: string[], headers?: { [key: string]: string
const acceptLanguageValue = headers?.['accept-language'];
return acceptLanguagePick(locales, acceptLanguageValue);
} else {
const acceptLanguages = window.navigator.languages;
const acceptLanguages = window.navigator.languages || [];
return acceptLanguages.find(acceptLanguage => locales.includes(acceptLanguage));
}
}

View File

@ -8,8 +8,8 @@ import getLocaleData from './getLocaleData';
*/
export default function getRedirectIndexRoute(originRoutes: any[], i18nConfig: I18nConfig, basename?: string) {
function walkRoute(routes: any[]) {
// eslint-disable-next-line no-restricted-syntax
for (const route of routes) {
for (let index = 0; index < routes.length; index++) {
const route = routes[index];
const { path, children, ...rest } = route;
if (path === '/') {
if (children) {
@ -27,10 +27,10 @@ export default function getRedirectIndexRoute(originRoutes: any[], i18nConfig: I
...route,
exact: true,
component: (props: any) => (
<IndexComponent
{...props}
i18nConfig={i18nConfig}
basename={basename}
<IndexComponent
{...props}
i18nConfig={i18nConfig}
basename={basename}
OriginIndexComponent={route.component}
/>
)

View File

@ -9,10 +9,10 @@ function normalizeLocalePath(
pathname = replaceBasename(pathname, basename);
const { defaultLocale, locales } = i18nConfig;
const subPaths = pathname.split('/');
let detectedLocale = defaultLocale;
// eslint-disable-next-line no-restricted-syntax
for (const locale of locales) {
let detectedLocale = defaultLocale;
for (let index = 0; index < locales.length; index++) {
const locale = locales[index];
if (subPaths[1] && subPaths[1] === locale) {
detectedLocale = locale;
subPaths.splice(1, 1);