i18n: Use internal formatting
This commit is contained in:
parent
eb59c0a0fb
commit
77b78071d7
7 changed files with 64 additions and 35 deletions
|
|
@ -34,6 +34,7 @@
|
|||
"dependencies": {
|
||||
"@swc/helpers": "0.5.0",
|
||||
"fuzzysort": "^2.0.4",
|
||||
"intl-messageformat": "^10.5.11",
|
||||
"spitroast": "^1.4.3"
|
||||
},
|
||||
"pnpm": {
|
||||
|
|
|
|||
46
pnpm-lock.yaml
generated
46
pnpm-lock.yaml
generated
|
|
@ -11,6 +11,9 @@ dependencies:
|
|||
fuzzysort:
|
||||
specifier: ^2.0.4
|
||||
version: 2.0.4
|
||||
intl-messageformat:
|
||||
specifier: ^10.5.11
|
||||
version: 10.5.11
|
||||
spitroast:
|
||||
specifier: ^1.4.3
|
||||
version: 1.4.3
|
||||
|
|
@ -250,6 +253,40 @@ packages:
|
|||
dev: true
|
||||
optional: true
|
||||
|
||||
/@formatjs/ecma402-abstract@1.18.2:
|
||||
resolution: {integrity: sha512-+QoPW4csYALsQIl8GbN14igZzDbuwzcpWrku9nyMXlaqAlwRBgl5V+p0vWMGFqHOw37czNXaP/lEk4wbLgcmtA==}
|
||||
dependencies:
|
||||
'@formatjs/intl-localematcher': 0.5.4
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/@formatjs/fast-memoize@2.2.0:
|
||||
resolution: {integrity: sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==}
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/@formatjs/icu-messageformat-parser@2.7.6:
|
||||
resolution: {integrity: sha512-etVau26po9+eewJKYoiBKP6743I1br0/Ie00Pb/S/PtmYfmjTcOn2YCh2yNkSZI12h6Rg+BOgQYborXk46BvkA==}
|
||||
dependencies:
|
||||
'@formatjs/ecma402-abstract': 1.18.2
|
||||
'@formatjs/icu-skeleton-parser': 1.8.0
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/@formatjs/icu-skeleton-parser@1.8.0:
|
||||
resolution: {integrity: sha512-QWLAYvM0n8hv7Nq5BEs4LKIjevpVpbGLAJgOaYzg9wABEoX1j0JO1q2/jVkO6CVlq0dbsxZCngS5aXbysYueqA==}
|
||||
dependencies:
|
||||
'@formatjs/ecma402-abstract': 1.18.2
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/@formatjs/intl-localematcher@0.5.4:
|
||||
resolution: {integrity: sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==}
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/@react-native-clipboard/clipboard@1.10.0:
|
||||
resolution: {integrity: sha512-1L+I0vmeUJgMi8MnNsqI00391/RFLkmmxj9qAuOS2madpvce/oNqJb8Pwk2Fc/uxIJSxOckTpq+dQwyPU6s+7w==}
|
||||
peerDependencies:
|
||||
|
|
@ -495,6 +532,15 @@ packages:
|
|||
resolution: {integrity: sha512-Api1mJL+Ad7W7vnDZnWq5pGaXJjyencT+iKGia2PlHUcSsSzWwIQ3S1isiMpwpavjYtGd2FzhUIhnnhOULZgDw==}
|
||||
dev: false
|
||||
|
||||
/intl-messageformat@10.5.11:
|
||||
resolution: {integrity: sha512-eYq5fkFBVxc7GIFDzpFQkDOZgNayNTQn4Oufe8jw6YY6OHVw70/4pA3FyCsQ0Gb2DnvEJEMmN2tOaXUGByM+kg==}
|
||||
dependencies:
|
||||
'@formatjs/ecma402-abstract': 1.18.2
|
||||
'@formatjs/fast-memoize': 2.2.0
|
||||
'@formatjs/icu-messageformat-parser': 2.7.6
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/invariant@2.2.4:
|
||||
resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
|
||||
dependencies:
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { ApplicationCommand, ApplicationCommandOptionType } from "@/lib/api/comm
|
|||
|
||||
export default () => <ApplicationCommand>{
|
||||
name: "plugins",
|
||||
description: Strings.COMMAND_DEBUG_DESC,
|
||||
description: Strings.COMMAND_PLUGINS_DESC,
|
||||
options: [
|
||||
{
|
||||
name: "ephemeral",
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
"COMMAND_EVAL_OPT_CODE": "The code to evaluate.",
|
||||
"COMMAND_PLUGINS_DESC": "Send list of installed plugins.",
|
||||
"COMMAND_PLUGINS_OPT_EPHEMERALLY": "Send plugins list ephemerally.",
|
||||
"CONFIRMATION_LINK_IS_A_TYPE": "This link is a {urlType}, would you like to install it?",
|
||||
"CONFIRMATION_LINK_IS_A_TYPE": "This link is a **{urlType, select, plugin {Plugin} theme {Theme} other {Add-on}}**, would you like to install it?",
|
||||
"CONNECT_TO_DEBUG_WEBSOCKET": "Connect to debug websocket",
|
||||
"CONNECT_TO_REACT_DEVTOOLS": "Connect to React DevTools",
|
||||
"COPY_URL": "Copy URL",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
import { findByName } from "@/lib/metro/filters";
|
||||
import langDefault from "./default.json";
|
||||
|
||||
const IntlMessageFormat = findByName("MessageFormat") as typeof import("intl-messageformat").default;
|
||||
|
||||
type I18nKey = keyof typeof langDefault;
|
||||
|
||||
export const Strings = new Proxy({}, {
|
||||
|
|
@ -8,26 +11,7 @@ export const Strings = new Proxy({}, {
|
|||
}
|
||||
}) as Record<I18nKey, string>;
|
||||
|
||||
export function formatString(key: I18nKey, val: Record<string, any>) {
|
||||
export function formatString<T = void>(key: I18nKey, val: Record<string, T>) {
|
||||
const str = Strings[key];
|
||||
|
||||
return str.replaceAll(/{(.*)}/g, (_, cap) => {
|
||||
return val[cap] ?? cap;
|
||||
});
|
||||
}
|
||||
|
||||
export function formatStringSplit(key: I18nKey, val: Record<string, any>) {
|
||||
const str = Strings[key];
|
||||
|
||||
const splitted = str.split(/({[^}]+})/);
|
||||
|
||||
for (const inp in val) {
|
||||
for (let i = 0; i < splitted.length; i++) {
|
||||
if (splitted[i] === `{${inp}}`) {
|
||||
splitted[i] = val[inp];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return splitted;
|
||||
return new IntlMessageFormat(str).format(val);
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ import { getAssetIDByName } from "@/lib/api/assets";
|
|||
import { showToast } from "@ui/toasts";
|
||||
import { useProxy } from "@/lib/api/storage";
|
||||
import { isThemeSupported } from "@/lib/api/native/loader";
|
||||
import { Strings, formatStringSplit } from "@/core/i18n";
|
||||
import { Strings, formatString } from "@/core/i18n";
|
||||
|
||||
type PostType = "Plugin" | "Theme";
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ const actionSheetPatch = () => after("default", ForumPostLongPressActionSheet, (
|
|||
actions.unshift(<ActionsSection key="install">
|
||||
<ActionSheetRow
|
||||
icon={<ActionSheetRow.Icon source={getAssetIDByName(installed ? "ic_message_delete" : "DownloadIcon")} />}
|
||||
label={formatStringSplit(installed ? "UNINSTALL_TITLE" : "INSTALL_TITLE", { title: postType })}
|
||||
label={formatString(installed ? "UNINSTALL_TITLE" : "INSTALL_TITLE", { title: postType })}
|
||||
disabled={loading}
|
||||
onPress={installOrRemove}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { showConfirmationAlert } from "@ui/alerts";
|
|||
import { getAssetIDByName } from "@/lib/api/assets";
|
||||
import { showToast } from "@ui/toasts";
|
||||
import { isThemeSupported } from "@/lib/api/native/loader";
|
||||
import { Strings, formatString, formatStringSplit } from "@/core/i18n";
|
||||
import { Strings, formatString } from "@/core/i18n";
|
||||
|
||||
const showSimpleActionSheet = find((m) => m?.showSimpleActionSheet && !Object.getOwnPropertyDescriptor(m, "showSimpleActionSheet")?.get);
|
||||
const handleClick = findByProps("handleClick");
|
||||
|
|
@ -16,18 +16,16 @@ const { openURL } = url;
|
|||
const { getChannelId } = channels;
|
||||
const { getChannel } = findByProps("getChannel");
|
||||
|
||||
const { TextStyleSheet } = findByProps("TextStyleSheet");
|
||||
|
||||
function typeFromUrl(url: string) {
|
||||
if (url.startsWith(PROXY_PREFIX)) {
|
||||
return "Plugin";
|
||||
return "plugin";
|
||||
} else if (url.endsWith(".json") && isThemeSupported()) {
|
||||
return "Theme";
|
||||
} else return;
|
||||
return "theme";
|
||||
}
|
||||
}
|
||||
|
||||
function installWithToast(type: "Plugin" | "Theme", url: string) {
|
||||
(type === "Plugin" ? installPlugin : installTheme)(url)
|
||||
function installWithToast(type: "plugin" | "theme", url: string) {
|
||||
(type === "plugin" ? installPlugin : installTheme)(url)
|
||||
.then(() => {
|
||||
showToast(Strings.TOASTS_SUCCESSFULLY_INSTALLED, getAssetIDByName("Check"));
|
||||
})
|
||||
|
|
@ -65,11 +63,11 @@ export default () => {
|
|||
if (!urlType) return orig.apply(this, args);
|
||||
|
||||
// Make clicking on theme links only work in #themes, should there be a theme proxy in the future, this can be removed.
|
||||
if (urlType === "Theme" && getChannel(getChannelId())?.parent_id !== THEMES_CHANNEL_ID) return orig.apply(this, args);
|
||||
if (urlType === "theme" && getChannel(getChannelId())?.parent_id !== THEMES_CHANNEL_ID) return orig.apply(this, args);
|
||||
|
||||
showConfirmationAlert({
|
||||
title: Strings.HOLD_UP,
|
||||
content: formatStringSplit("CONFIRMATION_LINK_IS_A_TYPE", { urlType: <RN.Text style={TextStyleSheet["text-md/semibold"]}>{urlType}</RN.Text> }),
|
||||
content: formatString("CONFIRMATION_LINK_IS_A_TYPE", { urlType }),
|
||||
onConfirm: () => installWithToast(urlType, url),
|
||||
confirmText: Strings.INSTALL,
|
||||
cancelText: Strings.CANCEL,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue