mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-03 19:29:32 -05:00 
			
		
		
		
	
							parent
							
								
									13cc1f0aa6
								
							
						
					
					
						commit
						fc6c9a19d9
					
				@ -248,6 +248,7 @@ export const defaultLang = { name: 'English', code: 'en', loader: () => import('
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export const langs = [
 | 
					export const langs = [
 | 
				
			||||||
  { name: 'Arabic', code: 'ar', loader: () => import('$lib/i18n/ar.json') },
 | 
					  { name: 'Arabic', code: 'ar', loader: () => import('$lib/i18n/ar.json') },
 | 
				
			||||||
 | 
					  { name: 'Bulgarian', code: 'bg', loader: () => import('$lib/i18n/bg.json') },
 | 
				
			||||||
  { name: 'Bislama', code: 'bi', loader: () => import('$lib/i18n/bi.json') },
 | 
					  { name: 'Bislama', code: 'bi', loader: () => import('$lib/i18n/bi.json') },
 | 
				
			||||||
  { name: 'Catalan', code: 'ca', loader: () => import('$lib/i18n/ca.json') },
 | 
					  { name: 'Catalan', code: 'ca', loader: () => import('$lib/i18n/ca.json') },
 | 
				
			||||||
  { name: 'Czech', code: 'cs', loader: () => import('$lib/i18n/cs.json') },
 | 
					  { name: 'Czech', code: 'cs', loader: () => import('$lib/i18n/cs.json') },
 | 
				
			||||||
@ -255,32 +256,49 @@ export const langs = [
 | 
				
			|||||||
  { name: 'German', code: 'de', loader: () => import('$lib/i18n/de.json') },
 | 
					  { name: 'German', code: 'de', loader: () => import('$lib/i18n/de.json') },
 | 
				
			||||||
  defaultLang,
 | 
					  defaultLang,
 | 
				
			||||||
  { name: 'Spanish', code: 'es', loader: () => import('$lib/i18n/es.json') },
 | 
					  { name: 'Spanish', code: 'es', loader: () => import('$lib/i18n/es.json') },
 | 
				
			||||||
 | 
					  { name: 'Persian', code: 'fa', loader: () => import('$lib/i18n/fa.json') },
 | 
				
			||||||
  { name: 'Finnish', code: 'fi', loader: () => import('$lib/i18n/fi.json') },
 | 
					  { name: 'Finnish', code: 'fi', loader: () => import('$lib/i18n/fi.json') },
 | 
				
			||||||
  { name: 'French', code: 'fr', loader: () => import('$lib/i18n/fr.json') },
 | 
					  { name: 'French', code: 'fr', loader: () => import('$lib/i18n/fr.json') },
 | 
				
			||||||
  { name: 'Hebrew', code: 'he', loader: () => import('$lib/i18n/he.json') },
 | 
					  { name: 'Hebrew', code: 'he', loader: () => import('$lib/i18n/he.json') },
 | 
				
			||||||
  { name: 'Hindi', code: 'hi', loader: () => import('$lib/i18n/hi.json') },
 | 
					  { name: 'Hindi', code: 'hi', loader: () => import('$lib/i18n/hi.json') },
 | 
				
			||||||
  { name: 'Croatian', code: 'hr', loader: () => import('$lib/i18n/hr.json') },
 | 
					  { name: 'Croatian', code: 'hr', loader: () => import('$lib/i18n/hr.json') },
 | 
				
			||||||
  { name: 'Hungarian', code: 'hu', loader: () => import('$lib/i18n/hu.json') },
 | 
					  { name: 'Hungarian', code: 'hu', loader: () => import('$lib/i18n/hu.json') },
 | 
				
			||||||
 | 
					  { name: 'Armenian', code: 'hy', loader: () => import('$lib/i18n/hy.json') },
 | 
				
			||||||
 | 
					  { name: 'Indonesian', code: 'id', loader: () => import('$lib/i18n/id.json') },
 | 
				
			||||||
  { name: 'Italian', code: 'it', loader: () => import('$lib/i18n/it.json') },
 | 
					  { name: 'Italian', code: 'it', loader: () => import('$lib/i18n/it.json') },
 | 
				
			||||||
  { name: 'Japanese', code: 'ja', loader: () => import('$lib/i18n/ja.json') },
 | 
					  { name: 'Japanese', code: 'ja', loader: () => import('$lib/i18n/ja.json') },
 | 
				
			||||||
 | 
					  { name: 'Kurdish (Northern)', code: 'kmr', loader: () => import('$lib/i18n/kmr.json') },
 | 
				
			||||||
  { name: 'Korean', code: 'ko', loader: () => import('$lib/i18n/ko.json') },
 | 
					  { name: 'Korean', code: 'ko', loader: () => import('$lib/i18n/ko.json') },
 | 
				
			||||||
  { name: 'Lithuanian', code: 'lt', loader: () => import('$lib/i18n/lt.json') },
 | 
					  { name: 'Lithuanian', code: 'lt', loader: () => import('$lib/i18n/lt.json') },
 | 
				
			||||||
  { name: 'Latvian', code: 'lv', loader: () => import('$lib/i18n/lv.json') },
 | 
					  { name: 'Latvian', code: 'lv', loader: () => import('$lib/i18n/lv.json') },
 | 
				
			||||||
  { name: 'Mongolian', code: 'mn', loader: () => import('$lib/i18n/mn.json') },
 | 
					  { name: 'Mongolian', code: 'mn', loader: () => import('$lib/i18n/mn.json') },
 | 
				
			||||||
  { name: 'Norwegian Bokmål', code: 'nb-NO', loader: () => import('$lib/i18n/nb_NO.json') },
 | 
					  { name: 'Norwegian Bokmål', code: 'nb-NO', weblateCode: 'nb_NO', loader: () => import('$lib/i18n/nb_NO.json') },
 | 
				
			||||||
  { name: 'Dutch', code: 'nl', loader: () => import('$lib/i18n/nl.json') },
 | 
					  { name: 'Dutch', code: 'nl', loader: () => import('$lib/i18n/nl.json') },
 | 
				
			||||||
  { name: 'Polish', code: 'pl', loader: () => import('$lib/i18n/pl.json') },
 | 
					  { name: 'Polish', code: 'pl', loader: () => import('$lib/i18n/pl.json') },
 | 
				
			||||||
  { name: 'Portuguese', code: 'pt', loader: () => import('$lib/i18n/pt.json') },
 | 
					  { name: 'Portuguese', code: 'pt', loader: () => import('$lib/i18n/pt.json') },
 | 
				
			||||||
 | 
					  { name: 'Portuguese (Brazil) ', code: 'pt-BR', weblateCode: 'pt_BR', loader: () => import('$lib/i18n/pt_BR.json') },
 | 
				
			||||||
  { name: 'Romanian', code: 'ro', loader: () => import('$lib/i18n/ro.json') },
 | 
					  { name: 'Romanian', code: 'ro', loader: () => import('$lib/i18n/ro.json') },
 | 
				
			||||||
  { name: 'Russian', code: 'ru', loader: () => import('$lib/i18n/ru.json') },
 | 
					  { name: 'Russian', code: 'ru', loader: () => import('$lib/i18n/ru.json') },
 | 
				
			||||||
  { name: 'Slovak', code: 'sk', loader: () => import('$lib/i18n/sk.json') },
 | 
					  { name: 'Slovak', code: 'sk', loader: () => import('$lib/i18n/sk.json') },
 | 
				
			||||||
  { name: 'Slovenian', code: 'sl', loader: () => import('$lib/i18n/sl.json') },
 | 
					  { name: 'Slovenian', code: 'sl', loader: () => import('$lib/i18n/sl.json') },
 | 
				
			||||||
  { name: 'Serbian', code: 'sr', loader: () => import('$lib/i18n/sr.json') },
 | 
					  { name: 'Serbian', code: 'sr', loader: () => import('$lib/i18n/sr.json') },
 | 
				
			||||||
  { name: 'Swedish', code: 'sv', loader: () => import('$lib/i18n/sv.json') },
 | 
					  { name: 'Swedish', code: 'sv', loader: () => import('$lib/i18n/sv.json') },
 | 
				
			||||||
 | 
					  { name: 'Tamil', code: 'ta', loader: () => import('$lib/i18n/ta.json') },
 | 
				
			||||||
  { name: 'Thai', code: 'th', loader: () => import('$lib/i18n/th.json') },
 | 
					  { name: 'Thai', code: 'th', loader: () => import('$lib/i18n/th.json') },
 | 
				
			||||||
 | 
					  { name: 'Turkish', code: 'tr', loader: () => import('$lib/i18n/tr.json') },
 | 
				
			||||||
  { name: 'Ukrainian', code: 'uk', loader: () => import('$lib/i18n/uk.json') },
 | 
					  { name: 'Ukrainian', code: 'uk', loader: () => import('$lib/i18n/uk.json') },
 | 
				
			||||||
  { name: 'Vietnamese', code: 'vi', loader: () => import('$lib/i18n/vi.json') },
 | 
					  { name: 'Vietnamese', code: 'vi', loader: () => import('$lib/i18n/vi.json') },
 | 
				
			||||||
  { name: 'Chinese (Traditional)', code: 'zh-Hant', loader: () => import('$lib/i18n/zh_Hant.json') },
 | 
					  {
 | 
				
			||||||
  { name: 'Chinese (Simplified)', code: 'zh-Hans', loader: () => import('$lib/i18n/zh_SIMPLIFIED.json') },
 | 
					    name: 'Chinese (Traditional)',
 | 
				
			||||||
 | 
					    code: 'zh-Hant',
 | 
				
			||||||
 | 
					    weblateCode: 'zh_Hant',
 | 
				
			||||||
 | 
					    loader: () => import('$lib/i18n/zh_Hant.json'),
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    name: 'Chinese (Simplified)',
 | 
				
			||||||
 | 
					    code: 'zh-Hans',
 | 
				
			||||||
 | 
					    weblateCode: 'zh_SIMPLIFIED',
 | 
				
			||||||
 | 
					    loader: () => import('$lib/i18n/zh_SIMPLIFIED.json'),
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  { name: 'Development (keys only)', code: 'dev', loader: () => Promise.resolve({}) },
 | 
					  { name: 'Development (keys only)', code: 'dev', loader: () => Promise.resolve({}) },
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,7 @@
 | 
				
			|||||||
 | 
					import { langs } from '$lib/constants';
 | 
				
			||||||
import messages from '$lib/i18n/en.json';
 | 
					import messages from '$lib/i18n/en.json';
 | 
				
			||||||
import { exec as execCallback } from 'node:child_process';
 | 
					import { exec as execCallback } from 'node:child_process';
 | 
				
			||||||
 | 
					import { readFileSync, readdirSync } from 'node:fs';
 | 
				
			||||||
import { promisify } from 'node:util';
 | 
					import { promisify } from 'node:util';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Messages = { [key: string]: string | Messages };
 | 
					type Messages = { [key: string]: string | Messages };
 | 
				
			||||||
@ -30,4 +32,24 @@ describe('i18n', () => {
 | 
				
			|||||||
    // Only translations directly using the store seem to get extracted
 | 
					    // Only translations directly using the store seem to get extracted
 | 
				
			||||||
    expect({ ...extractedMessages, ...existingMessages }).toEqual(existingMessages);
 | 
					    expect({ ...extractedMessages, ...existingMessages }).toEqual(existingMessages);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('loaders', () => {
 | 
				
			||||||
 | 
					    const languageFiles = readdirSync('src/lib/i18n').sort();
 | 
				
			||||||
 | 
					    for (const filename of languageFiles) {
 | 
				
			||||||
 | 
					      test(`${filename} should have a loader`, async () => {
 | 
				
			||||||
 | 
					        const code = filename.replaceAll('.json', '');
 | 
				
			||||||
 | 
					        const item = langs.find((lang) => lang.weblateCode === code || lang.code === code);
 | 
				
			||||||
 | 
					        expect(item, `${filename} has no loader`).toBeDefined();
 | 
				
			||||||
 | 
					        if (!item) {
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // verify it loads the right file
 | 
				
			||||||
 | 
					        const module: { default?: unknown } = await item.loader();
 | 
				
			||||||
 | 
					        const translations = JSON.stringify(module.default, null, 2).trim();
 | 
				
			||||||
 | 
					        const content = readFileSync(`src/lib/i18n/${filename}`).toString().trim();
 | 
				
			||||||
 | 
					        expect(translations === content, `${item.name} did not load ${filename}`).toEqual(true);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user