mirror of
https://github.com/owncast/owncast.git
synced 2025-11-02 20:23:29 +08:00
Update localization files + references (#4556)
* Initial plan * Add localization support to NameChangeModal component Co-authored-by: gabek <414923+gabek@users.noreply.github.com> * Add NameChangeModal translations to English language file Co-authored-by: gabek <414923+gabek@users.noreply.github.com> * fix(i18n): fix localization keys * chore(test): add i18n test * chore(i18n): update translation script * chore(i18n): reorgnize translation keys and update components * chore: fix linting warnings * chore(i18n): update all the language files * feat(i18n): add last live ago i18n key --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: gabek <414923+gabek@users.noreply.github.com> Co-authored-by: Gabe Kangas <gabek@real-ity.com>
This commit is contained in:
@ -38,7 +38,14 @@ function sortObjectKeys(obj) {
|
||||
|
||||
function scanTranslationKeys() {
|
||||
const files = glob.sync('**/*.{ts,tsx,js,jsx}', {
|
||||
ignore: ['node_modules/**', '.next/**', 'out/**'],
|
||||
ignore: [
|
||||
'node_modules/**',
|
||||
'.next/**',
|
||||
'out/**',
|
||||
'storybook-static/**',
|
||||
'coverage/**',
|
||||
'.storybook/**',
|
||||
],
|
||||
});
|
||||
|
||||
const results = {};
|
||||
@ -101,6 +108,57 @@ function scanTranslationKeys() {
|
||||
defaultText || `<strong><em>Missing translation ${key}: Please report</em></strong>`;
|
||||
}
|
||||
},
|
||||
|
||||
CallExpression(p) {
|
||||
const { node } = p;
|
||||
|
||||
// Check if this is a call to t() function
|
||||
if (node.callee.type !== 'Identifier' || node.callee.name !== 't') return;
|
||||
|
||||
// Check if the first argument is a Localization key
|
||||
if (node.arguments.length === 0) return;
|
||||
|
||||
const firstArg = node.arguments[0];
|
||||
let key = null;
|
||||
|
||||
// Handle t(Localization.Frontend.NameChangeModal.placeholder)
|
||||
if (firstArg.type === 'MemberExpression') {
|
||||
const dotPath = getDotPath(firstArg);
|
||||
if (dotPath) {
|
||||
key = dotPath;
|
||||
}
|
||||
}
|
||||
// Handle t("some.string.key") - but only if it looks like a translation key
|
||||
else if (firstArg.type === 'StringLiteral') {
|
||||
const { value } = firstArg;
|
||||
// Only include string literals that follow our translation key pattern:
|
||||
// - Must have dots for hierarchy (e.g., Frontend.Component.key)
|
||||
// - Must start with a capital letter (namespace convention)
|
||||
// - Must not contain spaces (translation keys shouldn't have spaces)
|
||||
// - Must not be common JS patterns like prototype methods
|
||||
if (
|
||||
value.includes('.') &&
|
||||
/^[A-Z][a-zA-Z0-9]*\./.test(value) &&
|
||||
!value.includes(' ') &&
|
||||
!value.includes('prototype') &&
|
||||
!value.includes('()') &&
|
||||
value.split('.').length >= 2 &&
|
||||
value.split('.').length <= 5
|
||||
) {
|
||||
// Reasonable depth for translation keys
|
||||
key = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (key) {
|
||||
// For t() calls, we don't have defaultText, so use the fallback
|
||||
if (!results[key]) {
|
||||
console.log(`[i18n] Found t() call with key: ${key} in ${file}`);
|
||||
}
|
||||
results[key] =
|
||||
results[key] || `<strong><em>Missing translation ${key}: Please report</em></strong>`;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -164,7 +222,7 @@ function updateTranslationFile(flatTranslations) {
|
||||
|
||||
if (changed) {
|
||||
const merged = sortObjectKeys(mergeDeep(existing, newNestedTranslations));
|
||||
fs.writeFileSync(TRANSLATIONS_PATH, JSON.stringify(merged, null, 2));
|
||||
fs.writeFileSync(TRANSLATIONS_PATH, JSON.stringify(merged, null, '\t'));
|
||||
console.log(`[i18n] Updated ${TRANSLATIONS_PATH}`);
|
||||
} else {
|
||||
console.log('[i18n] No new keys to add.');
|
||||
|
||||
Reference in New Issue
Block a user