Skip to content

Commit

Permalink
ref: tr: better tsdoc example & docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Sv443 committed Feb 10, 2025
1 parent 5456e7b commit 5d198df
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 31 deletions.
25 changes: 16 additions & 9 deletions docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -2526,16 +2526,23 @@ You can pass the result of the generic type [`TrKeys`](#trkeys) to easily genera
<details><summary><b>Example - click to view</b></summary>

```ts
import { tr } from "@sv443-network/userutils";
import { tr, type TrKeys } from "@sv443-network/userutils";

tr.addTranslations("en", {
const transEn = {
hello: "Hello, World!",
});
} as const;

const t = tr.use("en");
tr.addTranslations("en", transEn);

// to be loaded in from a DataStore or `navigator.language` or similar:
let currentLanguage = "en";

// very concise and easy to use:
t("hello"); // "Hello, World!"
function greet() {
const t = tr.use<TrKeys<typeof transEn>>(currentLanguage);

// very concise and easy to use:
t("hello"); // "Hello, World!"
}
```
</details>

Expand Down Expand Up @@ -2593,7 +2600,7 @@ const trEn = {
apples_n: "There are %1 apples",
},
"foo.bar": "This key isn't nested, it just has a dot",
};
} as const;

tr.addTransform(tr.transforms.percent);

Expand Down Expand Up @@ -2691,11 +2698,11 @@ import { tr, type TrKeys, type LooseUnion } from "@sv443-network/userutils";
const trEn = {
hello: "Hello, World!",
goodbye: "Goodbye, World!",
};
} as const;

const trDe = {
hello: "Hallo, Welt!",
};
} as const;

tr.addTranslations("en", trEn);
tr.addTranslations("de", trDe);
Expand Down
51 changes: 29 additions & 22 deletions lib/translation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import type { Stringifiable } from "./types.js";
* };
*/
export interface TrObject {
[key: string]: string | TrObject;
[key: string]: string | TrObject;
}

/** Properties for the transform function that transforms a matched translation string into something else */
Expand Down Expand Up @@ -71,13 +71,13 @@ export type TrKeys<TTrObj, P extends string = ""> = {

/** All translations loaded into memory */
const trans: {
[language: string]: TrObject;
[language: string]: TrObject;
} = {};

/** All registered value transformers */
const valTransforms: Array<{
regex: RegExp;
fn: TransformFn;
regex: RegExp;
fn: TransformFn;
}> = [];

/** Fallback language - if undefined, the trKey itself will be returned if the translation is not found */
Expand All @@ -97,10 +97,10 @@ function translate<TTrKey extends string = string>(language: string, key: TTrKey

/** Apply all transforms that match the translation string */
const transformTrVal = (trKey: TTrKey, trValue: string): string => {
const tfs = valTransforms.filter(({ regex }) => new RegExp(regex).test(trValue));
const tfs = valTransforms.filter(({ regex }) => new RegExp(regex).test(String(trValue)));

if(tfs.length === 0)
return trValue;
return String(trValue);

let retStr = String(trValue);

Expand Down Expand Up @@ -267,35 +267,42 @@ function getFallbackLanguage(): string | undefined {
* After all %n-formatted values have been injected, the transform functions will be called sequentially in the order they were added.
* @example
* ```ts
* tr.addTranslations("en", {
* "greeting": {
* "with_username": "Hello, ${USERNAME}",
* "headline_html": "Hello, ${USERNAME}<br><c=red>You have ${UNREAD_NOTIFS} unread notifications.</c>"
* import { tr, type TrKeys } from "@sv443-network/userutils";
*
* const transEn = {
* "headline": {
* "basic": "Hello, ${USERNAME}",
* "html": "Hello, ${USERNAME}<br><c=red>You have ${UNREAD_NOTIFS} unread notifications.</c>"
* }
* });
* } as const;
*
* tr.addTranslations("en", transEn);
*
* // replace ${PATTERN}
* tr.addTransform(/<\$([A-Z_]+)>/g, ({ matches }) => {
* // replace ${PATTERN} with predefined values
* tr.addTransform(/\$\{([A-Z_]+)\}/g, ({ matches }) => {
* switch(matches?.[1]) {
* default: return "<UNKNOWN_PATTERN>";
* // these would be grabbed from elsewhere in the application:
* case "USERNAME": return "JohnDoe45";
* case "UNREAD_NOTIFS": return 5;
* default:
* return `[UNKNOWN: ${matches?.[1]}]`;
* // these would be grabbed from elsewhere in the application, like a DataStore, global state or variable:
* case "USERNAME":
* return "JohnDoe45";
* case "UNREAD_NOTIFS":
* return 5;
* }
* });
*
* // replace <c=red>...</c> with <span class="color red">...</span>
* // replace <c=red>...</c> with <span style="color: red;">...</span>
* tr.addTransform(/<c=([a-z]+)>(.*?)<\/c>/g, ({ matches }) => {
* const color = matches?.[1];
* const content = matches?.[2];
*
* return "<span class=\"color " + color + "\">" + content + "</span>";
* return `<span style="color: ${color};">${content}</span>`;
* });
*
* tr.setLanguage("en");
* const t = tr.use<TrKeys<typeof transEn>>("en");
*
* tr("greeting.with_username"); // "Hello, JohnDoe45"
* tr("greeting.headline"); // "<b>Hello, JohnDoe45</b>\nYou have 5 unread notifications."
* t("headline.basic"); // "Hello, JohnDoe45"
* t("headline.html"); // "Hello, JohnDoe45<br><span style="color: red;">You have 5 unread notifications.</span>"
* ```
* @param args A tuple containing the regular expression to match and the transform function to call if the pattern is found in a translation string
*/
Expand Down

0 comments on commit 5d198df

Please sign in to comment.